diff --git a/src/libraries/Common/src/System/LocalAppContextSwitches.Common.cs b/src/libraries/Common/src/System/LocalAppContextSwitches.Common.cs
index 555751c6947a4..19806ceee1c79 100644
--- a/src/libraries/Common/src/System/LocalAppContextSwitches.Common.cs
+++ b/src/libraries/Common/src/System/LocalAppContextSwitches.Common.cs
@@ -55,6 +55,11 @@ private static bool GetSwitchDefaultValue(string switchName)
return true;
}
+ if (switchName == "System.Xml.XmlResolver.IsNetworkingEnabledByDefault")
+ {
+ return true;
+ }
+
return false;
}
}
diff --git a/src/libraries/System.Private.Xml/src/ILLink/ILLink.Substitutions.xml b/src/libraries/System.Private.Xml/src/ILLink/ILLink.Substitutions.xml
new file mode 100644
index 0000000000000..52cf62fc63618
--- /dev/null
+++ b/src/libraries/System.Private.Xml/src/ILLink/ILLink.Substitutions.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
diff --git a/src/libraries/System.Private.Xml/src/System.Private.Xml.csproj b/src/libraries/System.Private.Xml/src/System.Private.Xml.csproj
index 2bbb69bb379cd..b05a319099867 100644
--- a/src/libraries/System.Private.Xml/src/System.Private.Xml.csproj
+++ b/src/libraries/System.Private.Xml/src/System.Private.Xml.csproj
@@ -6,6 +6,10 @@
false
+
+
+
+
@@ -119,7 +123,6 @@
-
@@ -130,10 +133,10 @@
+
-
@@ -759,10 +762,7 @@
-
+
diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Core/LocalAppContextSwitches.cs b/src/libraries/System.Private.Xml/src/System/Xml/Core/LocalAppContextSwitches.cs
index 8bc1f54dc8b50..a95f9105051da 100644
--- a/src/libraries/System.Private.Xml/src/System/Xml/Core/LocalAppContextSwitches.cs
+++ b/src/libraries/System.Private.Xml/src/System/Xml/Core/LocalAppContextSwitches.cs
@@ -2,10 +2,11 @@
// The .NET Foundation licenses this file to you under the MIT license.
using System.Runtime.CompilerServices;
+using SwitchesHelpers = System.LocalAppContextSwitches;
-namespace System
+namespace System.Xml
{
- internal static partial class LocalAppContextSwitches
+ internal static class LocalAppContextSwitches
{
private static int s_dontThrowOnInvalidSurrogatePairs;
public static bool DontThrowOnInvalidSurrogatePairs
@@ -13,7 +14,7 @@ public static bool DontThrowOnInvalidSurrogatePairs
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
- return GetCachedSwitchValue("Switch.System.Xml.DontThrowOnInvalidSurrogatePairs", ref s_dontThrowOnInvalidSurrogatePairs);
+ return SwitchesHelpers.GetCachedSwitchValue("Switch.System.Xml.DontThrowOnInvalidSurrogatePairs", ref s_dontThrowOnInvalidSurrogatePairs);
}
}
@@ -23,7 +24,7 @@ public static bool IgnoreEmptyKeySequences
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
- return GetCachedSwitchValue("Switch.System.Xml.IgnoreEmptyKeySequencess", ref s_ignoreEmptyKeySequences);
+ return SwitchesHelpers.GetCachedSwitchValue("Switch.System.Xml.IgnoreEmptyKeySequences", ref s_ignoreEmptyKeySequences);
}
}
@@ -33,7 +34,7 @@ public static bool IgnoreKindInUtcTimeSerialization
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
- return GetCachedSwitchValue("Switch.System.Xml.IgnoreKindInUtcTimeSerialization", ref s_ignoreKindInUtcTimeSerialization);
+ return SwitchesHelpers.GetCachedSwitchValue("Switch.System.Xml.IgnoreKindInUtcTimeSerialization", ref s_ignoreKindInUtcTimeSerialization);
}
}
@@ -43,7 +44,7 @@ public static bool LimitXPathComplexity
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
- return GetCachedSwitchValue("Switch.System.Xml.LimitXPathComplexity", ref s_limitXPathComplexity);
+ return SwitchesHelpers.GetCachedSwitchValue("Switch.System.Xml.LimitXPathComplexity", ref s_limitXPathComplexity);
}
}
@@ -53,7 +54,17 @@ public static bool AllowDefaultResolver
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
- return GetCachedSwitchValue("Switch.System.Xml.AllowDefaultResolver", ref s_allowDefaultResolver);
+ return SwitchesHelpers.GetCachedSwitchValue("Switch.System.Xml.AllowDefaultResolver", ref s_allowDefaultResolver);
+ }
+ }
+
+ private static int s_isNetworkingEnabledByDefault;
+ public static bool IsNetworkingEnabledByDefault
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ get
+ {
+ return SwitchesHelpers.GetCachedSwitchValue("System.Xml.XmlResolver.IsNetworkingEnabledByDefault", ref s_isNetworkingEnabledByDefault);
}
}
}
diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlReader.cs b/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlReader.cs
index e0f76fe5fad1c..80a1c18372ab7 100644
--- a/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlReader.cs
+++ b/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlReader.cs
@@ -1612,7 +1612,7 @@ public static XmlReader Create(string inputUri)
// Avoid using XmlReader.Create(string, XmlReaderSettings), as it references a lot of types
// that then can't be trimmed away.
- return new XmlTextReaderImpl(inputUri, XmlReaderSettings.s_defaultReaderSettings, null, new XmlUrlResolver());
+ return new XmlTextReaderImpl(inputUri, XmlReaderSettings.s_defaultReaderSettings, null, XmlReaderSettings.GetDefaultPermissiveResolver());
}
// Creates an XmlReader according to the settings for parsing XML from the given Uri.
diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlReaderSettings.cs b/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlReaderSettings.cs
index 68adf4d128807..f4d873161c1f2 100644
--- a/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlReaderSettings.cs
+++ b/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlReaderSettings.cs
@@ -321,7 +321,7 @@ internal XmlReader CreateReader(string inputUri, XmlParserContext? inputContext)
ArgumentException.ThrowIfNullOrEmpty(inputUri);
// resolve and open the url
- XmlResolver tmpResolver = GetXmlResolver() ?? new XmlUrlResolver();
+ XmlResolver tmpResolver = GetXmlResolver() ?? GetDefaultPermissiveResolver();
// create text XML reader
XmlReader reader = new XmlTextReaderImpl(inputUri, this, inputContext, tmpResolver);
@@ -436,7 +436,7 @@ internal XmlReader AddValidation(XmlReader reader)
if (resolver == null && !IsXmlResolverSet)
{
- resolver = new XmlUrlResolver();
+ resolver = GetDefaultPermissiveResolver();
}
}
@@ -623,6 +623,11 @@ private XmlReader AddConformanceWrapper(XmlReader baseReader)
return baseReader;
}
+ internal static XmlResolver GetDefaultPermissiveResolver()
+ {
+ return LocalAppContextSwitches.IsNetworkingEnabledByDefault ? new XmlUrlResolver() : XmlResolver.FileSystemResolver;
+ }
+
[DoesNotReturn]
[StackTraceHidden]
private static void ThrowArgumentOutOfRangeException(string paramName)
diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlTextReaderImpl.cs b/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlTextReaderImpl.cs
index 4de62beab8966..1c118faafb865 100644
--- a/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlTextReaderImpl.cs
+++ b/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlTextReaderImpl.cs
@@ -2532,7 +2532,7 @@ private bool IsResolverNull
private XmlResolver GetTempResolver()
{
- return _xmlResolver ?? new XmlUrlResolver();
+ return _xmlResolver ?? XmlReaderSettings.GetDefaultPermissiveResolver();
}
internal bool DtdParserProxy_PushEntity(IDtdEntityInfo entity, out int entityId)
diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlValidatingReaderImpl.cs b/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlValidatingReaderImpl.cs
index bb6d8f8337c9f..f2c8caf707a1c 100644
--- a/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlValidatingReaderImpl.cs
+++ b/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlValidatingReaderImpl.cs
@@ -1082,7 +1082,7 @@ private void SetupValidation(ValidationType valType)
if (tempResolver == null && !_coreReaderImpl.IsResolverSet)
{
// it is safe to return valid resolver as it'll be used in the schema validation
- return s_tempResolver ??= new XmlUrlResolver();
+ return s_tempResolver ??= XmlReaderSettings.GetDefaultPermissiveResolver();
}
return tempResolver;
diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Schema/XmlSchemaSet.cs b/src/libraries/System.Private.Xml/src/System/Xml/Schema/XmlSchemaSet.cs
index 0012e4a3c0312..f8292c5e70a12 100644
--- a/src/libraries/System.Private.Xml/src/System/Xml/Schema/XmlSchemaSet.cs
+++ b/src/libraries/System.Private.Xml/src/System/Xml/Schema/XmlSchemaSet.cs
@@ -106,7 +106,7 @@ public XmlSchemaSet(XmlNameTable nameTable)
if (_readerSettings.GetXmlResolver() == null)
{
// The created resolver will be used in the schema validation only
- _readerSettings.XmlResolver = new XmlUrlResolver();
+ _readerSettings.XmlResolver = XmlReaderSettings.GetDefaultPermissiveResolver();
_readerSettings.IsXmlResolverSet = false;
}
@@ -232,7 +232,7 @@ internal Hashtable SchemaLocations
lock (InternalSyncObject)
{
//Check if schema from url has already been added
- XmlResolver tempResolver = _readerSettings.GetXmlResolver() ?? new XmlUrlResolver();
+ XmlResolver tempResolver = _readerSettings.GetXmlResolver() ?? XmlReaderSettings.GetDefaultPermissiveResolver();
Uri tempSchemaUri = tempResolver.ResolveUri(null, schemaUri);
if (IsSchemaLoaded(tempSchemaUri, targetNamespace, out schema))
{
diff --git a/src/libraries/System.Private.Xml/src/System/Xml/XmlDownloadManager.cs b/src/libraries/System.Private.Xml/src/System/Xml/XmlDownloadManager.cs
index 83ebba25199ec..304a346bdaf6f 100644
--- a/src/libraries/System.Private.Xml/src/System/Xml/XmlDownloadManager.cs
+++ b/src/libraries/System.Private.Xml/src/System/Xml/XmlDownloadManager.cs
@@ -1,13 +1,14 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-using System;
using System.IO;
using System.Net;
+using System.Net.Http;
+using System.Threading.Tasks;
namespace System.Xml
{
- internal sealed partial class XmlDownloadManager
+ internal static class XmlDownloadManager
{
internal static Stream GetStream(Uri uri, ICredentials? credentials, IWebProxy? proxy)
{
@@ -22,5 +23,44 @@ internal static Stream GetStream(Uri uri, ICredentials? credentials, IWebProxy?
return GetNonFileStreamAsync(uri, credentials, proxy).GetAwaiter().GetResult();
}
}
+
+ internal static Task GetStreamAsync(Uri uri, ICredentials? credentials, IWebProxy? proxy)
+ {
+ if (uri.Scheme == "file")
+ {
+ Uri fileUri = uri;
+ return Task.FromResult(new FileStream(fileUri.LocalPath, FileMode.Open, FileAccess.Read, FileShare.Read, 1, useAsync: true));
+ }
+ else
+ {
+ return GetNonFileStreamAsync(uri, credentials, proxy);
+ }
+ }
+
+ private static async Task GetNonFileStreamAsync(Uri uri, ICredentials? credentials, IWebProxy? proxy)
+ {
+ var handler = new HttpClientHandler();
+ using (var client = new HttpClient(handler))
+ {
+#pragma warning disable CA1416 // Validate platform compatibility, 'credentials' and 'proxy' will not be set for browser, so safe to suppress
+ if (credentials != null)
+ {
+ handler.Credentials = credentials;
+ }
+ if (proxy != null)
+ {
+ handler.Proxy = proxy;
+ }
+#pragma warning restore CA1416
+
+ using (Stream respStream = await client.GetStreamAsync(uri).ConfigureAwait(false))
+ {
+ var result = new MemoryStream();
+ respStream.CopyTo(result);
+ result.Position = 0;
+ return result;
+ }
+ }
+ }
}
}
diff --git a/src/libraries/System.Private.Xml/src/System/Xml/XmlDownloadManagerAsync.cs b/src/libraries/System.Private.Xml/src/System/Xml/XmlDownloadManagerAsync.cs
deleted file mode 100644
index c2d774d0f4006..0000000000000
--- a/src/libraries/System.Private.Xml/src/System/Xml/XmlDownloadManagerAsync.cs
+++ /dev/null
@@ -1,53 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-using System;
-using System.IO;
-using System.Net;
-using System.Net.Http;
-using System.Threading.Tasks;
-
-namespace System.Xml
-{
- internal sealed partial class XmlDownloadManager
- {
- internal static Task GetStreamAsync(Uri uri, ICredentials? credentials, IWebProxy? proxy)
- {
- if (uri.Scheme == "file")
- {
- Uri fileUri = uri;
- return Task.Run(() => new FileStream(fileUri.LocalPath, FileMode.Open, FileAccess.Read, FileShare.Read, 1, useAsync: true));
- }
- else
- {
- return GetNonFileStreamAsync(uri, credentials, proxy);
- }
- }
-
- private static async Task GetNonFileStreamAsync(Uri uri, ICredentials? credentials, IWebProxy? proxy)
- {
- var handler = new HttpClientHandler();
- using (var client = new HttpClient(handler))
- {
-#pragma warning disable CA1416 // Validate platform compatibility, 'credentials' and 'proxy' will not be set for browser, so safe to suppress
- if (credentials != null)
- {
- handler.Credentials = credentials;
- }
- if (proxy != null)
- {
- handler.Proxy = proxy;
- }
-#pragma warning restore CA1416
-
- using (Stream respStream = await client.GetStreamAsync(uri).ConfigureAwait(false))
- {
- var result = new MemoryStream();
- respStream.CopyTo(result);
- result.Position = 0;
- return result;
- }
- }
- }
- }
-}
diff --git a/src/libraries/System.Private.Xml/src/System/Xml/XmlResolver.FileSystemResolver.cs b/src/libraries/System.Private.Xml/src/System/Xml/XmlResolver.FileSystemResolver.cs
new file mode 100644
index 0000000000000..8785d09e9c12c
--- /dev/null
+++ b/src/libraries/System.Private.Xml/src/System/Xml/XmlResolver.FileSystemResolver.cs
@@ -0,0 +1,54 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.IO;
+using System.Threading.Tasks;
+
+namespace System.Xml
+{
+ public abstract partial class XmlResolver
+ {
+ ///
+ /// Gets an XML resolver which resolves only file system URIs.
+ ///
+ /// An XML resolver which resolves only file system URIs.
+ ///
+ /// Calling or on the
+ /// instance returned by this property will resolve only URIs which scheme is file.
+ ///
+ public static XmlResolver FileSystemResolver => XmlFileSystemResolver.s_singleton;
+
+ // An XML resolver that resolves only file system URIs.
+ private sealed class XmlFileSystemResolver : XmlResolver
+ {
+ internal static readonly XmlFileSystemResolver s_singleton = new();
+
+ // Private constructor ensures existing only one instance of XmlFileSystemResolver
+ private XmlFileSystemResolver() { }
+
+ public override object? GetEntity(Uri absoluteUri, string? role, Type? ofObjectToReturn)
+ {
+ if ((ofObjectToReturn is null || ofObjectToReturn == typeof(Stream) || ofObjectToReturn == typeof(object))
+ && absoluteUri.Scheme == "file")
+ {
+ return new FileStream(absoluteUri.LocalPath, FileMode.Open, FileAccess.Read, FileShare.Read, 1);
+ }
+
+ throw new XmlException(SR.Xml_UnsupportedClass, string.Empty);
+ }
+
+ public override Task
diff --git a/src/libraries/System.Private.Xml/tests/TrimmingTests/XmlUrlResolverDefaults.Disabled.IsNetworkingEnabledByDefault.cs b/src/libraries/System.Private.Xml/tests/TrimmingTests/XmlUrlResolverDefaults.Disabled.IsNetworkingEnabledByDefault.cs
new file mode 100644
index 0000000000000..683b1d960be37
--- /dev/null
+++ b/src/libraries/System.Private.Xml/tests/TrimmingTests/XmlUrlResolverDefaults.Disabled.IsNetworkingEnabledByDefault.cs
@@ -0,0 +1,44 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+#nullable enable
+
+using System;
+using System.IO;
+using System.Linq;
+using System.Xml;
+using System.Xml.Linq;
+
+class XmlUrlResolverDefaults
+{
+ public static int Main()
+ {
+ File.WriteAllText("file.xml", """
+
+
+ test-value
+
+ """);
+
+ XDocument doc = XDocument.Load("file.xml");
+
+ string value = doc.Descendants("some-element").Single().Value;
+ if (value == "test-value")
+ {
+ Type? urlResolver = GetXmlType("System.Xml.XmlUrlResolver");
+ if (urlResolver == null)
+ {
+ // we should not preserve the type
+ return 100;
+ }
+
+ return -1;
+ }
+
+ return -2;
+ }
+
+ // The intention of this method is to ensure the trimmer doesn't preserve the Type.
+ private static Type? GetXmlType(string name) =>
+ typeof(XmlReader).Assembly.GetType(name, throwOnError: false);
+}
diff --git a/src/libraries/System.Private.Xml/tests/TrimmingTests/XmlUrlResolverDefaults.IsNetworkingEnabledByDefault.cs b/src/libraries/System.Private.Xml/tests/TrimmingTests/XmlUrlResolverDefaults.IsNetworkingEnabledByDefault.cs
new file mode 100644
index 0000000000000..6dafb02774e37
--- /dev/null
+++ b/src/libraries/System.Private.Xml/tests/TrimmingTests/XmlUrlResolverDefaults.IsNetworkingEnabledByDefault.cs
@@ -0,0 +1,44 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+#nullable enable
+
+using System;
+using System.IO;
+using System.Linq;
+using System.Xml;
+using System.Xml.Linq;
+
+class XmlUrlResolverDefaults
+{
+ public static int Main()
+ {
+ File.WriteAllText("file.xml", """
+
+
+ test-value
+
+ """);
+
+ XDocument doc = XDocument.Load("file.xml");
+
+ string value = doc.Descendants("some-element").Single().Value;
+ if (value == "test-value")
+ {
+ Type? urlResolver = GetXmlType("System.Xml.XmlUrlResolver");
+ if (urlResolver != null)
+ {
+ // we should preserve the type but we want to avoid doing web requests during the test
+ return 100;
+ }
+
+ return -1;
+ }
+
+ return -2;
+ }
+
+ // The intention of this method is to ensure the trimmer preserves the Type.
+ private static Type? GetXmlType(string name) =>
+ typeof(XmlReader).Assembly.GetType(name, throwOnError: false);
+}
diff --git a/src/libraries/System.Xml.ReaderWriter/ref/System.Xml.ReaderWriter.cs b/src/libraries/System.Xml.ReaderWriter/ref/System.Xml.ReaderWriter.cs
index 68368f91a265e..0c8cb022dc2ca 100644
--- a/src/libraries/System.Xml.ReaderWriter/ref/System.Xml.ReaderWriter.cs
+++ b/src/libraries/System.Xml.ReaderWriter/ref/System.Xml.ReaderWriter.cs
@@ -952,6 +952,7 @@ public abstract partial class XmlResolver
protected XmlResolver() { }
public virtual System.Net.ICredentials Credentials { set { } }
public static System.Xml.XmlResolver ThrowingResolver { get { throw null; } }
+ public static System.Xml.XmlResolver FileSystemResolver { get { throw null; } }
public abstract object? GetEntity(System.Uri absoluteUri, string? role, System.Type? ofObjectToReturn);
public virtual System.Threading.Tasks.Task GetEntityAsync(System.Uri absoluteUri, string? role, System.Type? ofObjectToReturn) { throw null; }
public virtual System.Uri ResolveUri(System.Uri? baseUri, string? relativeUri) { throw null; }