Skip to content

Commit 3d22564

Browse files
lilinusstephentoub
andauthored
Fix XDocument.LoadAsync to not use sync reads (#123800)
Co-authored-by: Stephen Toub <[email protected]>
1 parent d9a7a38 commit 3d22564

File tree

3 files changed

+56
-4
lines changed

3 files changed

+56
-4
lines changed

src/libraries/System.Private.Xml.Linq/src/System/Xml/Linq/XDeclaration.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
using System.IO;
55
using System.Text;
6+
using System.Threading.Tasks;
67
using StringBuilder = System.Text.StringBuilder;
78

89
namespace System.Xml.Linq
@@ -65,6 +66,15 @@ internal XDeclaration(XmlReader r)
6566
r.Read();
6667
}
6768

69+
internal static async Task<XDeclaration> CreateAsync(XmlReader r)
70+
{
71+
string? version = r.GetAttribute("version");
72+
string? encoding = r.GetAttribute("encoding");
73+
string? standalone = r.GetAttribute("standalone");
74+
await r.ReadAsync().ConfigureAwait(false);
75+
return new XDeclaration(version, encoding, standalone);
76+
}
77+
6878
/// <summary>
6979
/// Gets or sets the encoding for this document.
7080
/// </summary>

src/libraries/System.Private.Xml.Linq/src/System/Xml/Linq/XDocument.cs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,12 @@ public static XDocument Load(XmlReader reader, LoadOptions options)
425425
if (reader.ReadState == ReadState.Initial) reader.Read();
426426

427427
XDocument d = InitLoad(reader, options);
428+
429+
if (reader.NodeType == XmlNodeType.XmlDeclaration)
430+
{
431+
d.Declaration = new XDeclaration(reader);
432+
}
433+
428434
d.ReadContentFrom(reader, options);
429435

430436
if (!reader.EOF) throw new InvalidOperationException(SR.InvalidOperation_ExpectedEndOfFile);
@@ -467,6 +473,12 @@ private static async Task<XDocument> LoadAsyncInternal(XmlReader reader, LoadOpt
467473
}
468474

469475
XDocument d = InitLoad(reader, options);
476+
477+
if (reader.NodeType == XmlNodeType.XmlDeclaration)
478+
{
479+
d.Declaration = await XDeclaration.CreateAsync(reader).ConfigureAwait(false);
480+
}
481+
470482
await d.ReadContentFromAsync(reader, options, cancellationToken).ConfigureAwait(false);
471483

472484
if (!reader.EOF) throw new InvalidOperationException(SR.InvalidOperation_ExpectedEndOfFile);
@@ -496,10 +508,6 @@ private static XDocument InitLoad(XmlReader reader, LoadOptions options)
496508
d.SetLineInfo(li.LineNumber, li.LinePosition);
497509
}
498510
}
499-
if (reader.NodeType == XmlNodeType.XmlDeclaration)
500-
{
501-
d.Declaration = new XDeclaration(reader);
502-
}
503511
return d;
504512
}
505513

src/libraries/System.Private.Xml.Linq/tests/misc/LoadSaveAsyncTests.cs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System;
55
using System.Collections.Generic;
66
using System.IO;
7+
using System.Text;
78
using System.Threading;
89
using System.Threading.Tasks;
910
using System.Xml;
@@ -232,6 +233,39 @@ public async Task SaveAsync_CallsAsyncOnly_SaveSync_CallsSyncOnly(bool isAsync,
232233
}
233234
}
234235

236+
public static IEnumerable<object[]> IsAsync_LoadOptions_XmlString_Data
237+
{
238+
get
239+
{
240+
foreach (bool isAsync in new[] { true, false })
241+
{
242+
foreach (LoadOptions loadOptions in Enum.GetValues(typeof(LoadOptions)))
243+
{
244+
yield return new object[] { isAsync, loadOptions, "<root>Test</root>" };
245+
yield return new object[] { isAsync, loadOptions, "<?xml version=\"1.0\" encoding=\"utf-8\"?><root>Test</root>" };
246+
}
247+
}
248+
}
249+
}
250+
251+
[Theory]
252+
[MemberData(nameof(IsAsync_LoadOptions_XmlString_Data))]
253+
public async Task XDocument_LoadAsync_CallsAsyncOnly_LoadSync_CallsSyncOnly(bool isAsync, LoadOptions loadOptions, string xmlString)
254+
{
255+
using MemoryStream memoryStream = new MemoryStream(Encoding.UTF8.GetBytes(xmlString));
256+
using (CheckSyncAsyncStream stream = new CheckSyncAsyncStream(isAsync, memoryStream))
257+
{
258+
if (isAsync)
259+
{
260+
await XDocument.LoadAsync(stream, loadOptions, CancellationToken.None);
261+
}
262+
else
263+
{
264+
XDocument.Load(stream, loadOptions);
265+
}
266+
}
267+
}
268+
235269
[Theory]
236270
[MemberData(nameof(RoundtripOptions_MemberData))]
237271
public static async Task RoundtripSyncAsyncCheckAndMatches_XmlReader(bool document, LoadOptions loadOptions, SaveOptions saveOptions)

0 commit comments

Comments
 (0)