From 44655fd0dc7b08cd20eced97981bcad99e48ef67 Mon Sep 17 00:00:00 2001 From: Steve Pfister Date: Thu, 15 Jul 2021 00:36:02 -0400 Subject: [PATCH] Include native underlying handler support in HttpClientHandler for iOS/tvOS/MacCatalyst and Android (#55384) Completes the plan for net6 laid out in https://github.com/dotnet/designs/blob/main/accepted/2020/mono-convergence/platform-specific-httpclient.md#the-plan-for-net-5 This change supports using either the native HttpMessageHandler types that exist in the Xamarin repos (NSUrlSessionHandler for iOS/tvOS/Catalyst and AndroidMessageHandler for Android) or SocketsHttpHandler as the underlying handler in HttpClientHandler. The behavior for new HttpClient() was established earlier in net6, but did not go all the way. For example, if the System.Net.Http.UseNativeHttpHandler feature switch was set to true, using HttpClient in different ways would lead to different underlying handlers. Before this PR: // System.Net.Http.UseNativeHttpHandler == true new HttpClient(); // Chooses the native handler as the underlying handler var handler = new HttpClientHandler(); // SocketsHttpHandler is the only choice new HttpClient(handler); The change creates a handful of partial HttpClientHandler files in order to split out the platform specific parts. As you review the PR, you'll notice a bunch of if (IsSocketHandler) blocks. The intent of these are to make use of the linker and get linked out once the linker knows which handler is the active one. get { if (IsSocketHandler) { return _socketHandler!.UseCookies; } else { return GetUseCookies(); } } Get and Set methods like GetUseCookies make it easier to tell the linker via DynamicDependency to preserve the reflection calls being made to the native underlying handler. [DynamicDependency("get_UseCookies", "Xamarin.Android.Net.AndroidMessageHandler", "Mono.Android")] private bool GetUseCookies() => (bool)InvokeNativeHandlerMethod("get_UseCookies"); It is important to point out that the underlying handler has to be derived from HttpMessageHandler. It cannot be HttpClientHandler or you'll end up with a circular dependency. --- eng/testing/tests.mobile.targets | 1 + .../System.Net.Http/ref/System.Net.Http.cs | 63 +++ .../src/ILLink/ILLink.Substitutions.xml | 4 +- .../ILLink.Suppressions.LibraryBuild.xml | 135 +++++- .../src/System.Net.Http.csproj | 16 +- ...HttpClient.CreateDefaultHandler.Android.cs | 29 -- ...Client.CreateDefaultHandler.MacCatalyst.cs | 29 -- .../Http/HttpClient.CreateDefaultHandler.cs | 13 - .../HttpClient.CreateDefaultHandler.iOS.cs | 29 -- .../HttpClient.CreateDefaultHandler.tvOS.cs | 29 -- .../src/System/Net/Http/HttpClient.cs | 2 +- .../Net/Http/HttpClientHandler.Android.cs | 237 ++++++++++ .../Net/Http/HttpClientHandler.AnyMobile.cs | 434 ++++++++++++++++++ .../Net/Http/HttpClientHandler.Apple.cs | 65 +++ .../Net/Http/HttpClientHandler.MacCatalyst.cs | 52 +++ .../src/System/Net/Http/HttpClientHandler.cs | 63 +++ .../System/Net/Http/HttpClientHandler.iOS.cs | 52 +++ .../System/Net/Http/HttpClientHandler.tvOS.cs | 52 +++ .../RuntimeSettingParser.cs | 16 + .../System.Net.Http.Unit.Tests.csproj | 6 - .../FunctionalTests/Directory.Build.props | 6 +- 21 files changed, 1185 insertions(+), 148 deletions(-) delete mode 100644 src/libraries/System.Net.Http/src/System/Net/Http/HttpClient.CreateDefaultHandler.Android.cs delete mode 100644 src/libraries/System.Net.Http/src/System/Net/Http/HttpClient.CreateDefaultHandler.MacCatalyst.cs delete mode 100644 src/libraries/System.Net.Http/src/System/Net/Http/HttpClient.CreateDefaultHandler.cs delete mode 100644 src/libraries/System.Net.Http/src/System/Net/Http/HttpClient.CreateDefaultHandler.iOS.cs delete mode 100644 src/libraries/System.Net.Http/src/System/Net/Http/HttpClient.CreateDefaultHandler.tvOS.cs create mode 100644 src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.Android.cs create mode 100644 src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.AnyMobile.cs create mode 100644 src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.Apple.cs create mode 100644 src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.MacCatalyst.cs create mode 100644 src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.iOS.cs create mode 100644 src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.tvOS.cs diff --git a/eng/testing/tests.mobile.targets b/eng/testing/tests.mobile.targets index c3107ec4a060a..45184d7f7efbc 100644 --- a/eng/testing/tests.mobile.targets +++ b/eng/testing/tests.mobile.targets @@ -26,6 +26,7 @@ false false false + false diff --git a/src/libraries/System.Net.Http/ref/System.Net.Http.cs b/src/libraries/System.Net.Http/ref/System.Net.Http.cs index ef465d5a3d053..cf0b2d01f0522 100644 --- a/src/libraries/System.Net.Http/ref/System.Net.Http.cs +++ b/src/libraries/System.Net.Http/ref/System.Net.Http.cs @@ -114,35 +114,87 @@ public partial class HttpClientHandler : System.Net.Http.HttpMessageHandler public HttpClientHandler() { } public bool AllowAutoRedirect { get { throw null; } set { } } [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("ios")] + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("tvos")] + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("maccatalyst")] public System.Net.DecompressionMethods AutomaticDecompression { get { throw null; } set { } } + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("android")] [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("ios")] + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("tvos")] + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("maccatalyst")] public bool CheckCertificateRevocationList { get { throw null; } set { } } + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("android")] + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("ios")] + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("tvos")] + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("maccatalyst")] public System.Net.Http.ClientCertificateOption ClientCertificateOptions { get { throw null; } set { } } + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("android")] [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("ios")] + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("tvos")] + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("maccatalyst")] public System.Security.Cryptography.X509Certificates.X509CertificateCollection ClientCertificates { get { throw null; } } [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] public System.Net.CookieContainer CookieContainer { get { throw null; } set { } } [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] public System.Net.ICredentials? Credentials { get { throw null; } set { } } + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("android")] [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("ios")] + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("tvos")] + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("maccatalyst")] public static System.Func DangerousAcceptAnyServerCertificateValidator { get { throw null; } } + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("android")] [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("ios")] + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("tvos")] + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("maccatalyst")] public System.Net.ICredentials? DefaultProxyCredentials { get { throw null; } set { } } [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("ios")] + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("tvos")] + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("maccatalyst")] public int MaxAutomaticRedirections { get { throw null; } set { } } + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("android")] [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("ios")] + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("tvos")] + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("maccatalyst")] public int MaxConnectionsPerServer { get { throw null; } set { } } public long MaxRequestContentBufferSize { get { throw null; } set { } } + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("android")] [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("ios")] + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("tvos")] + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("maccatalyst")] public int MaxResponseHeadersLength { get { throw null; } set { } } [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("ios")] + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("tvos")] + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("maccatalyst")] public bool PreAuthenticate { get { throw null; } set { } } + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("android")] + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("ios")] + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("tvos")] + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("maccatalyst")] public System.Collections.Generic.IDictionary Properties { get { throw null; } } [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("ios")] + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("tvos")] + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("maccatalyst")] public System.Net.IWebProxy? Proxy { get { throw null; } set { } } + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("android")] [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("ios")] + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("tvos")] + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("maccatalyst")] public System.Func? ServerCertificateCustomValidationCallback { get { throw null; } set { } } + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("android")] [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("ios")] + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("tvos")] + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("maccatalyst")] public System.Security.Authentication.SslProtocols SslProtocols { get { throw null; } set { } } public virtual bool SupportsAutomaticDecompression { get { throw null; } } public virtual bool SupportsProxy { get { throw null; } } @@ -152,9 +204,20 @@ public HttpClientHandler() { } [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] public bool UseDefaultCredentials { get { throw null; } set { } } [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("ios")] + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("tvos")] + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("maccatalyst")] public bool UseProxy { get { throw null; } set { } } protected override void Dispose(bool disposing) { } + // + // Attributes are commented out due to https://github.com/dotnet/arcade/issues/7585 + // API compat will fail until this is fixed + // + //[System.Runtime.Versioning.UnsupportedOSPlatformAttribute("android")] [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] + //[System.Runtime.Versioning.UnsupportedOSPlatformAttributeUnsupportedOSPlatform("ios")] + //[System.Runtime.Versioning.UnsupportedOSPlatformAttributeUnsupportedOSPlatform("tvos")] + //[System.Runtime.Versioning.UnsupportedOSPlatformAttributeUnsupportedOSPlatform("maccatalyst")] protected internal override System.Net.Http.HttpResponseMessage Send(System.Net.Http.HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) { throw null; } protected internal override System.Threading.Tasks.Task SendAsync(System.Net.Http.HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) { throw null; } } diff --git a/src/libraries/System.Net.Http/src/ILLink/ILLink.Substitutions.xml b/src/libraries/System.Net.Http/src/ILLink/ILLink.Substitutions.xml index 314469c96d777..8af1dcbdfa8a6 100644 --- a/src/libraries/System.Net.Http/src/ILLink/ILLink.Substitutions.xml +++ b/src/libraries/System.Net.Http/src/ILLink/ILLink.Substitutions.xml @@ -3,8 +3,8 @@ - - + + diff --git a/src/libraries/System.Net.Http/src/ILLink/ILLink.Suppressions.LibraryBuild.xml b/src/libraries/System.Net.Http/src/ILLink/ILLink.Suppressions.LibraryBuild.xml index e11daf0bd241f..dbeca2aa0a94d 100644 --- a/src/libraries/System.Net.Http/src/ILLink/ILLink.Suppressions.LibraryBuild.xml +++ b/src/libraries/System.Net.Http/src/ILLink/ILLink.Suppressions.LibraryBuild.xml @@ -5,7 +5,140 @@ ILLink IL2075 member - M:System.Net.Http.HttpClient.CreateDefaultHandler() + M:System.Net.Http.HttpClientHandler.CreateNativeHandler() + The Xamarin.iOS and Mono.Android libraries are not present when running the trimmer analysis during our build. A consuming application will get a warning if these libraries aren't present when trimming the full app. + + + ILLink + IL2075 + member + M:System.Net.Http.HttpClientHandler.InvokeNativeHandlerMethod(System.String,System.Object[]) + The Xamarin.iOS and Mono.Android libraries are not present when running the trimmer analysis during our build. A consuming application will get a warning if these libraries aren't present when trimming the full app. + + + ILLink + IL2035 + member + M:System.Net.Http.HttpClientHandler.GetUseCookies() + The Xamarin.iOS and Mono.Android libraries are not present when running the trimmer analysis during our build. A consuming application will get a warning if these libraries aren't present when trimming the full app. + + + ILLink + IL2035 + member + M:System.Net.Http.HttpClientHandler.SetUseCookies(System.Boolean) + The Xamarin.iOS and Mono.Android libraries are not present when running the trimmer analysis during our build. A consuming application will get a warning if these libraries aren't present when trimming the full app. + + + ILLink + IL2035 + member + M:System.Net.Http.HttpClientHandler.GetCookieContainer() + The Xamarin.iOS and Mono.Android libraries are not present when running the trimmer analysis during our build. A consuming application will get a warning if these libraries aren't present when trimming the full app. + + + ILLink + IL2035 + member + M:System.Net.Http.HttpClientHandler.SetCookieContainer(System.Net.CookieContainer) + The Xamarin.iOS and Mono.Android libraries are not present when running the trimmer analysis during our build. A consuming application will get a warning if these libraries aren't present when trimming the full app. + + + ILLink + IL2035 + member + M:System.Net.Http.HttpClientHandler.GetAllowAutoRedirect() + The Xamarin.iOS and Mono.Android libraries are not present when running the trimmer analysis during our build. A consuming application will get a warning if these libraries aren't present when trimming the full app. + + + ILLink + IL2035 + member + M:System.Net.Http.HttpClientHandler.SetAllowAutoRedirect(System.Boolean) + The Xamarin.iOS and Mono.Android libraries are not present when running the trimmer analysis during our build. A consuming application will get a warning if these libraries aren't present when trimming the full app. + + + ILLink + IL2035 + member + M:System.Net.Http.HttpClientHandler.GetCredentials() + The Xamarin.iOS and Mono.Android libraries are not present when running the trimmer analysis during our build. A consuming application will get a warning if these libraries aren't present when trimming the full app. + + + ILLink + IL2035 + member + M:System.Net.Http.HttpClientHandler.SetCredentials(System.Net.ICredentials) + The Xamarin.iOS and Mono.Android libraries are not present when running the trimmer analysis during our build. A consuming application will get a warning if these libraries aren't present when trimming the full app. + + + ILLink + IL2035 + member + M:System.Net.Http.HttpClientHandler.GetAutomaticDecompression() + The Xamarin.iOS and Mono.Android libraries are not present when running the trimmer analysis during our build. A consuming application will get a warning if these libraries aren't present when trimming the full app. + + + ILLink + IL2035 + member + M:System.Net.Http.HttpClientHandler.SetAutomaticDecompression(System.Net.DecompressionMethods) + The Xamarin.iOS and Mono.Android libraries are not present when running the trimmer analysis during our build. A consuming application will get a warning if these libraries aren't present when trimming the full app. + + + ILLink + IL2035 + member + M:System.Net.Http.HttpClientHandler.GetUseProxy() + The Xamarin.iOS and Mono.Android libraries are not present when running the trimmer analysis during our build. A consuming application will get a warning if these libraries aren't present when trimming the full app. + + + ILLink + IL2035 + member + M:System.Net.Http.HttpClientHandler.SetUseProxy(System.Boolean) + The Xamarin.iOS and Mono.Android libraries are not present when running the trimmer analysis during our build. A consuming application will get a warning if these libraries aren't present when trimming the full app. + + + ILLink + IL2035 + member + M:System.Net.Http.HttpClientHandler.GetProxy() + The Xamarin.iOS and Mono.Android libraries are not present when running the trimmer analysis during our build. A consuming application will get a warning if these libraries aren't present when trimming the full app. + + + ILLink + IL2035 + member + M:System.Net.Http.HttpClientHandler.SetProxy(System.Net.IWebProxy) + The Xamarin.iOS and Mono.Android libraries are not present when running the trimmer analysis during our build. A consuming application will get a warning if these libraries aren't present when trimming the full app. + + + ILLink + IL2035 + member + M:System.Net.Http.HttpClientHandler.GetPreAuthenticate() + The Xamarin.iOS and Mono.Android libraries are not present when running the trimmer analysis during our build. A consuming application will get a warning if these libraries aren't present when trimming the full app. + + + ILLink + IL2035 + member + M:System.Net.Http.HttpClientHandler.SetPreAuthenticate(System.Boolean) + The Xamarin.iOS and Mono.Android libraries are not present when running the trimmer analysis during our build. A consuming application will get a warning if these libraries aren't present when trimming the full app. + + + ILLink + IL2035 + member + M:System.Net.Http.HttpClientHandler.GetMaxAutomaticRedirections() + The Xamarin.iOS and Mono.Android libraries are not present when running the trimmer analysis during our build. A consuming application will get a warning if these libraries aren't present when trimming the full app. + + + ILLink + IL2035 + member + M:System.Net.Http.HttpClientHandler.SetMaxAutomaticRedirections(System.Int32) The Xamarin.iOS and Mono.Android libraries are not present when running the trimmer analysis during our build. A consuming application will get a warning if these libraries aren't present when trimming the full app. diff --git a/src/libraries/System.Net.Http/src/System.Net.Http.csproj b/src/libraries/System.Net.Http/src/System.Net.Http.csproj index 0bbe56c0d879b..330c6cf161446 100644 --- a/src/libraries/System.Net.Http/src/System.Net.Http.csproj +++ b/src/libraries/System.Net.Http/src/System.Net.Http.csproj @@ -34,12 +34,16 @@ - - - - - - + + + + + + + diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/HttpClient.CreateDefaultHandler.Android.cs b/src/libraries/System.Net.Http/src/System/Net/Http/HttpClient.CreateDefaultHandler.Android.cs deleted file mode 100644 index f770bbe22a2ac..0000000000000 --- a/src/libraries/System.Net.Http/src/System/Net/Http/HttpClient.CreateDefaultHandler.Android.cs +++ /dev/null @@ -1,29 +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.Reflection; - -namespace System.Net.Http -{ - public partial class HttpClient - { - private static MethodInfo? handlerMethod; - - private static HttpMessageHandler CreateDefaultHandler() - { - // Default is to use the Android native handler - if (!IsNativeHandlerEnabled()) - { - return new HttpClientHandler(); - } - - if (handlerMethod == null) - { - Type? androidEnv = Type.GetType("Android.Runtime.AndroidEnvironment, Mono.Android"); - handlerMethod = androidEnv!.GetMethod("GetHttpMessageHandler", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static); - } - - return (HttpMessageHandler)handlerMethod!.Invoke(null, null)!; - } - } -} diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/HttpClient.CreateDefaultHandler.MacCatalyst.cs b/src/libraries/System.Net.Http/src/System/Net/Http/HttpClient.CreateDefaultHandler.MacCatalyst.cs deleted file mode 100644 index dc19e0ed35d87..0000000000000 --- a/src/libraries/System.Net.Http/src/System/Net/Http/HttpClient.CreateDefaultHandler.MacCatalyst.cs +++ /dev/null @@ -1,29 +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.Reflection; - -namespace System.Net.Http -{ - public partial class HttpClient - { - private static MethodInfo? handlerMethod; - - private static HttpMessageHandler CreateDefaultHandler() - { - // Default is to use the iOS native handler - if (!IsNativeHandlerEnabled()) - { - return new HttpClientHandler(); - } - - if (handlerMethod == null) - { - Type? runtimeOptions = Type.GetType("ObjCRuntime.RuntimeOptions, Xamarin.MacCatalyst"); - handlerMethod = runtimeOptions!.GetMethod("GetHttpMessageHandler", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static); - } - - return (HttpMessageHandler)handlerMethod!.Invoke(null, null)!; - } - } -} diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/HttpClient.CreateDefaultHandler.cs b/src/libraries/System.Net.Http/src/System/Net/Http/HttpClient.CreateDefaultHandler.cs deleted file mode 100644 index b1327d9cd0fde..0000000000000 --- a/src/libraries/System.Net.Http/src/System/Net/Http/HttpClient.CreateDefaultHandler.cs +++ /dev/null @@ -1,13 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -namespace System.Net.Http -{ - public partial class HttpClient - { - private static HttpMessageHandler CreateDefaultHandler() - { - return new HttpClientHandler(); - } - } -} diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/HttpClient.CreateDefaultHandler.iOS.cs b/src/libraries/System.Net.Http/src/System/Net/Http/HttpClient.CreateDefaultHandler.iOS.cs deleted file mode 100644 index 03f4f945c9f27..0000000000000 --- a/src/libraries/System.Net.Http/src/System/Net/Http/HttpClient.CreateDefaultHandler.iOS.cs +++ /dev/null @@ -1,29 +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.Reflection; - -namespace System.Net.Http -{ - public partial class HttpClient - { - private static MethodInfo? handlerMethod; - - private static HttpMessageHandler CreateDefaultHandler() - { - // Default is to use the iOS native handler - if (!IsNativeHandlerEnabled()) - { - return new HttpClientHandler(); - } - - if (handlerMethod == null) - { - Type? runtimeOptions = Type.GetType("ObjCRuntime.RuntimeOptions, Xamarin.iOS"); - handlerMethod = runtimeOptions!.GetMethod("GetHttpMessageHandler", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static); - } - - return (HttpMessageHandler)handlerMethod!.Invoke(null, null)!; - } - } -} diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/HttpClient.CreateDefaultHandler.tvOS.cs b/src/libraries/System.Net.Http/src/System/Net/Http/HttpClient.CreateDefaultHandler.tvOS.cs deleted file mode 100644 index e2dfbe0ffc107..0000000000000 --- a/src/libraries/System.Net.Http/src/System/Net/Http/HttpClient.CreateDefaultHandler.tvOS.cs +++ /dev/null @@ -1,29 +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.Reflection; - -namespace System.Net.Http -{ - public partial class HttpClient - { - private static MethodInfo? handlerMethod; - - private static HttpMessageHandler CreateDefaultHandler() - { - // Default is to use the tvOS native handler - if (!IsNativeHandlerEnabled()) - { - return new HttpClientHandler(); - } - - if (handlerMethod == null) - { - Type? runtimeOptions = Type.GetType("ObjCRuntime.RuntimeOptions, Xamarin.TVOS"); - handlerMethod = runtimeOptions!.GetMethod("GetHttpMessageHandler", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static); - } - - return (HttpMessageHandler)handlerMethod!.Invoke(null, null)!; - } - } -} diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/HttpClient.cs b/src/libraries/System.Net.Http/src/System/Net/Http/HttpClient.cs index 27b0c357cc686..2e1434b0b4993 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/HttpClient.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/HttpClient.cs @@ -132,7 +132,7 @@ public long MaxResponseContentBufferSize #region Constructors - public HttpClient() : this(CreateDefaultHandler()) + public HttpClient() : this(new HttpClientHandler()) { } diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.Android.cs b/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.Android.cs new file mode 100644 index 0000000000000..cf9069a9f69b5 --- /dev/null +++ b/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.Android.cs @@ -0,0 +1,237 @@ +// 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.Diagnostics.CodeAnalysis; +using System.Reflection; +using System.Runtime.Versioning; + +namespace System.Net.Http +{ + public partial class HttpClientHandler : HttpMessageHandler + { + private static MethodInfo? _nativeHandlerMethod; + + private const string NativeHandlerType = "Xamarin.Android.Net.AndroidMessageHandler"; + private const string AssemblyName = "Mono.Android"; + + public virtual bool SupportsAutomaticDecompression => true; + public virtual bool SupportsProxy => true; + public virtual bool SupportsRedirectConfiguration => true; + + [UnsupportedOSPlatform("browser")] + [UnsupportedOSPlatform("ios")] + [UnsupportedOSPlatform("tvos")] + [UnsupportedOSPlatform("maccatalyst")] + public DecompressionMethods AutomaticDecompression + { + get + { + if (IsNativeHandlerEnabled) + { + return GetAutomaticDecompression(); + } + else + { + return _socketHandler!.AutomaticDecompression; + } + } + set + { + if (IsNativeHandlerEnabled) + { + SetAutomaticDecompression(value); + } + else + { + _socketHandler!.AutomaticDecompression = value; + } + } + } + + [UnsupportedOSPlatform("browser")] + [UnsupportedOSPlatform("ios")] + [UnsupportedOSPlatform("tvos")] + [UnsupportedOSPlatform("maccatalyst")] + public bool UseProxy + { + get + { + if (IsNativeHandlerEnabled) + { + return GetUseProxy(); + } + else + { + return _socketHandler!.UseProxy; + } + } + set + { + if (IsNativeHandlerEnabled) + { + SetUseProxy(value); + } + else + { + _socketHandler!.UseProxy = value; + } + } + } + + [UnsupportedOSPlatform("browser")] + [UnsupportedOSPlatform("ios")] + [UnsupportedOSPlatform("tvos")] + [UnsupportedOSPlatform("maccatalyst")] + public IWebProxy? Proxy + { + get + { + if (IsNativeHandlerEnabled) + { + return GetProxy(); + } + else + { + return _socketHandler!.Proxy; + } + } + set + { + if (IsNativeHandlerEnabled) + { + SetProxy(value!); + } + else + { + _socketHandler!.Proxy = value; + } + } + } + + [UnsupportedOSPlatform("browser")] + [UnsupportedOSPlatform("ios")] + [UnsupportedOSPlatform("tvos")] + [UnsupportedOSPlatform("maccatalyst")] + public bool PreAuthenticate + { + get + { + if (IsNativeHandlerEnabled) + { + return GetPreAuthenticate(); + } + else + { + return _socketHandler!.PreAuthenticate; + } + } + set + { + if (IsNativeHandlerEnabled) + { + SetPreAuthenticate(value); + } + else + { + _socketHandler!.PreAuthenticate = value; + } + } + } + + [UnsupportedOSPlatform("browser")] + [UnsupportedOSPlatform("ios")] + [UnsupportedOSPlatform("tvos")] + [UnsupportedOSPlatform("maccatalyst")] + public int MaxAutomaticRedirections + { + get + { + if (IsNativeHandlerEnabled) + { + return GetMaxAutomaticRedirections(); + } + else + { + return _socketHandler!.MaxAutomaticRedirections; + } + } + set + { + if (IsNativeHandlerEnabled) + { + SetMaxAutomaticRedirections(value); + } + else + { + _socketHandler!.MaxAutomaticRedirections = value; + } + } + } + + [DynamicDependency("get_MaxAutomaticRedirections", NativeHandlerType, AssemblyName)] + private int GetMaxAutomaticRedirections() => (int)InvokeNativeHandlerMethod("get_MaxAutomaticRedirections"); + + [DynamicDependency("set_MaxAutomaticRedirections", NativeHandlerType, AssemblyName)] + private void SetMaxAutomaticRedirections(int value) => InvokeNativeHandlerMethod("set_MaxAutomaticRedirections", value); + + [DynamicDependency("get_PreAuthenticate", NativeHandlerType, AssemblyName)] + private bool GetPreAuthenticate() => (bool)InvokeNativeHandlerMethod("get_PreAuthenticate"); + + [DynamicDependency("set_PreAuthenticate", NativeHandlerType, AssemblyName)] + private void SetPreAuthenticate(bool value) => InvokeNativeHandlerMethod("set_PreAuthenticate", value); + + [DynamicDependency("get_UseProxy", NativeHandlerType, AssemblyName)] + private bool GetUseProxy() => (bool)InvokeNativeHandlerMethod("get_UseProxy"); + + [DynamicDependency("set_UseProxy", NativeHandlerType, AssemblyName)] + private void SetUseProxy(bool value) => InvokeNativeHandlerMethod("set_UseProxy", value); + + [DynamicDependency("get_Proxy", NativeHandlerType, AssemblyName)] + private IWebProxy GetProxy() => (IWebProxy)InvokeNativeHandlerMethod("get_Proxy"); + + [DynamicDependency("set_Proxy", NativeHandlerType, AssemblyName)] + private void SetProxy(IWebProxy value) => InvokeNativeHandlerMethod("set_Proxy", value); + + [DynamicDependency("get_AutomaticDecompression", NativeHandlerType, AssemblyName)] + private DecompressionMethods GetAutomaticDecompression() => (DecompressionMethods)InvokeNativeHandlerMethod("get_AutomaticDecompression"); + + [DynamicDependency("set_AutomaticDecompression", NativeHandlerType, AssemblyName)] + private void SetAutomaticDecompression(DecompressionMethods value) => InvokeNativeHandlerMethod("set_AutomaticDecompression", value); + + [DynamicDependency("get_UseCookies", NativeHandlerType, AssemblyName)] + private bool GetUseCookies() => (bool)InvokeNativeHandlerMethod("get_UseCookies"); + + [DynamicDependency("set_UseCookies", NativeHandlerType, AssemblyName)] + private void SetUseCookies(bool value) => InvokeNativeHandlerMethod("set_UseCookies", value); + + [DynamicDependency("get_CookieContainer", NativeHandlerType, AssemblyName)] + private CookieContainer GetCookieContainer() => (CookieContainer)InvokeNativeHandlerMethod("get_CookieContainer"); + + [DynamicDependency("set_CookieContainer", NativeHandlerType, AssemblyName)] + private void SetCookieContainer(CookieContainer value) => InvokeNativeHandlerMethod("set_CookieContainer", value); + + [DynamicDependency("get_AllowAutoRedirect", NativeHandlerType, AssemblyName)] + private bool GetAllowAutoRedirect() => (bool)InvokeNativeHandlerMethod("get_AllowAutoRedirect"); + + [DynamicDependency("set_AllowAutoRedirect", NativeHandlerType, AssemblyName)] + private void SetAllowAutoRedirect(bool value) => InvokeNativeHandlerMethod("set_AllowAutoRedirect", value); + + [DynamicDependency("get_Credentials", NativeHandlerType, AssemblyName)] + private ICredentials GetCredentials() => (ICredentials)InvokeNativeHandlerMethod("get_Credentials"); + + [DynamicDependency("set_Credentials", NativeHandlerType, AssemblyName)] + private void SetCredentials(ICredentials? value) => InvokeNativeHandlerMethod("set_Credentials", value); + + private HttpMessageHandler CreateNativeHandler() + { + if (_nativeHandlerMethod == null) + { + Type? androidEnv = Type.GetType("Android.Runtime.AndroidEnvironment, Mono.Android"); + _nativeHandlerMethod = androidEnv!.GetMethod("GetHttpMessageHandler", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static); + } + + return (HttpMessageHandler)_nativeHandlerMethod!.Invoke(null, null)!; + } + } +} \ No newline at end of file diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.AnyMobile.cs b/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.AnyMobile.cs new file mode 100644 index 0000000000000..309e60f65a915 --- /dev/null +++ b/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.AnyMobile.cs @@ -0,0 +1,434 @@ +// 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.Collections.Concurrent; +using System.Collections.Generic; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.Net.Security; +using System.Reflection; +using System.Runtime.Versioning; +using System.Security.Authentication; +using System.Security.Cryptography.X509Certificates; +using System.Threading; +using System.Threading.Tasks; + +namespace System.Net.Http +{ + public partial class HttpClientHandler : HttpMessageHandler + { + private readonly SocketsHttpHandler? _socketHandler; + private readonly DiagnosticsHandler? _diagnosticsHandler; + + private readonly HttpMessageHandler? _nativeHandler; + + private static readonly ConcurrentDictionary s_cachedMethods = + new ConcurrentDictionary(); + + private volatile bool _disposed; + + public HttpClientHandler() + { + HttpMessageHandler handler; + + if (IsNativeHandlerEnabled) + { + _nativeHandler = CreateNativeHandler(); + handler = _nativeHandler; + } + else + { + _socketHandler = new SocketsHttpHandler(); + handler = _socketHandler; + } + + if (DiagnosticsHandler.IsGloballyEnabled()) + { + _diagnosticsHandler = new DiagnosticsHandler(handler, DistributedContextPropagator.Current); + } + } + + protected override void Dispose(bool disposing) + { + if (disposing && !_disposed) + { + _disposed = true; + + if (IsNativeHandlerEnabled) + { + _nativeHandler!.Dispose(); + } + else + { + _socketHandler!.Dispose(); + } + } + + base.Dispose(disposing); + } + + [UnsupportedOSPlatform("browser")] + public bool UseCookies + { + get + { + if (IsNativeHandlerEnabled) + { + return GetUseCookies(); + } + else + { + return _socketHandler!.UseCookies; + } + } + set + { + if (IsNativeHandlerEnabled) + { + SetUseCookies(value); + } + else + { + _socketHandler!.UseCookies = value; + } + } + } + + [UnsupportedOSPlatform("browser")] + public CookieContainer CookieContainer + { + get + { + if (IsNativeHandlerEnabled) + { + return GetCookieContainer(); + } + else + { + return _socketHandler!.CookieContainer; + } + } + set + { + if (value == null) + { + throw new ArgumentNullException(nameof(value)); + } + + if (IsNativeHandlerEnabled) + { + SetCookieContainer(value); + } + else + { + _socketHandler!.CookieContainer = value; + } + } + } + + [UnsupportedOSPlatform("android")] + [UnsupportedOSPlatform("browser")] + [UnsupportedOSPlatform("ios")] + [UnsupportedOSPlatform("tvos")] + [UnsupportedOSPlatform("maccatalyst")] + public ICredentials? DefaultProxyCredentials + { + get => throw new PlatformNotSupportedException(); + set => throw new PlatformNotSupportedException(); + } + + [UnsupportedOSPlatform("browser")] + public bool UseDefaultCredentials + { + // SocketsHttpHandler doesn't have a separate UseDefaultCredentials property. There + // is just a Credentials property. So, we need to map the behavior. + // Same with the native handler. + get + { + ICredentials? creds; + if (IsNativeHandlerEnabled) + { + creds = GetCredentials(); + } + else + { + creds = _socketHandler!.Credentials; + } + + return creds == CredentialCache.DefaultCredentials; + } + set + { + if (value) + { + if (IsNativeHandlerEnabled) + { + SetCredentials(CredentialCache.DefaultCredentials); + } + else + { + _socketHandler!.Credentials = CredentialCache.DefaultCredentials; + } + } + else + { + if (IsNativeHandlerEnabled) + { + ICredentials? creds = GetCredentials(); + + if (creds == CredentialCache.DefaultCredentials) + { + SetCredentials(null!); + } + } + else + { + if (_socketHandler!.Credentials == CredentialCache.DefaultCredentials) + { + _socketHandler!.Credentials = null; + } + } + } + } + } + + [UnsupportedOSPlatform("browser")] + public ICredentials? Credentials + { + get + { + if (IsNativeHandlerEnabled) + { + return GetCredentials(); + } + else + { + return _socketHandler!.Credentials; + } + + } + set + { + if (IsNativeHandlerEnabled) + { + SetCredentials(value!); + } + else + { + _socketHandler!.Credentials = value; + } + } + } + + public bool AllowAutoRedirect + { + get + { + if (IsNativeHandlerEnabled) + { + return GetAllowAutoRedirect(); + } + else + { + return _socketHandler!.AllowAutoRedirect; + } + } + set + { + if (IsNativeHandlerEnabled) + { + SetAllowAutoRedirect(value); + } + else + { + _socketHandler!.AllowAutoRedirect = value; + } + } + } + + [UnsupportedOSPlatform("android")] + [UnsupportedOSPlatform("browser")] + [UnsupportedOSPlatform("ios")] + [UnsupportedOSPlatform("tvos")] + [UnsupportedOSPlatform("maccatalyst")] + public int MaxConnectionsPerServer + { + get => throw new PlatformNotSupportedException(); + set => throw new PlatformNotSupportedException(); + } + + public long MaxRequestContentBufferSize + { + // This property is not supported. In the .NET Framework it was only used when the handler needed to + // automatically buffer the request content. That only happened if neither 'Content-Length' nor + // 'Transfer-Encoding: chunked' request headers were specified. So, the handler thus needed to buffer + // in the request content to determine its length and then would choose 'Content-Length' semantics when + // POST'ing. In .NET Core, the handler will resolve the ambiguity by always choosing + // 'Transfer-Encoding: chunked'. The handler will never automatically buffer in the request content. + get + { + return 0; // Returning zero is appropriate since in .NET Framework it means no limit. + } + + set + { + if (value < 0) + { + throw new ArgumentOutOfRangeException(nameof(value)); + } + + if (value > HttpContent.MaxBufferSize) + { + throw new ArgumentOutOfRangeException(nameof(value), value, + SR.Format(CultureInfo.InvariantCulture, SR.net_http_content_buffersize_limit, + HttpContent.MaxBufferSize)); + } + + CheckDisposed(); + + // No-op on property setter. + } + } + + [UnsupportedOSPlatform("android")] + [UnsupportedOSPlatform("browser")] + [UnsupportedOSPlatform("ios")] + [UnsupportedOSPlatform("tvos")] + [UnsupportedOSPlatform("maccatalyst")] + public int MaxResponseHeadersLength + { + get => throw new PlatformNotSupportedException(); + set => throw new PlatformNotSupportedException(); + } + + [UnsupportedOSPlatform("android")] + [UnsupportedOSPlatform("ios")] + [UnsupportedOSPlatform("tvos")] + [UnsupportedOSPlatform("maccatalyst")] + public ClientCertificateOption ClientCertificateOptions + { + get => throw new PlatformNotSupportedException(); + set => throw new PlatformNotSupportedException(); + } + + [UnsupportedOSPlatform("android")] + [UnsupportedOSPlatform("browser")] + [UnsupportedOSPlatform("ios")] + [UnsupportedOSPlatform("tvos")] + [UnsupportedOSPlatform("maccatalyst")] + public X509CertificateCollection ClientCertificates + { + get + { + throw new PlatformNotSupportedException(); + } + } + + [UnsupportedOSPlatform("android")] + [UnsupportedOSPlatform("browser")] + [UnsupportedOSPlatform("ios")] + [UnsupportedOSPlatform("tvos")] + [UnsupportedOSPlatform("maccatalyst")] + public Func? ServerCertificateCustomValidationCallback + { + get => throw new PlatformNotSupportedException(); + set => throw new PlatformNotSupportedException(); + } + + [UnsupportedOSPlatform("android")] + [UnsupportedOSPlatform("browser")] + [UnsupportedOSPlatform("ios")] + [UnsupportedOSPlatform("tvos")] + [UnsupportedOSPlatform("maccatalyst")] + public bool CheckCertificateRevocationList + { + get => throw new PlatformNotSupportedException(); + set => throw new PlatformNotSupportedException(); + } + + [UnsupportedOSPlatform("android")] + [UnsupportedOSPlatform("browser")] + [UnsupportedOSPlatform("ios")] + [UnsupportedOSPlatform("tvos")] + [UnsupportedOSPlatform("maccatalyst")] + public SslProtocols SslProtocols + { + get => throw new PlatformNotSupportedException(); + set => throw new PlatformNotSupportedException(); + } + + [UnsupportedOSPlatform("android")] + [UnsupportedOSPlatform("ios")] + [UnsupportedOSPlatform("tvos")] + [UnsupportedOSPlatform("maccatalyst")] + public IDictionary Properties => throw new PlatformNotSupportedException(); + + // + // Attributes are commented out due to https://github.com/dotnet/arcade/issues/7585 + // API compat will fail until this is fixed + // + //[UnsupportedOSPlatform("android")] + [UnsupportedOSPlatform("browser")] + //[UnsupportedOSPlatform("ios")] + //[UnsupportedOSPlatform("tvos")] + //[UnsupportedOSPlatform("maccatalyst")] + protected internal override HttpResponseMessage Send(HttpRequestMessage request, + CancellationToken cancellationToken) + { + throw new PlatformNotSupportedException(); + } + + protected internal override Task SendAsync(HttpRequestMessage request, + CancellationToken cancellationToken) + { + if (DiagnosticsHandler.IsGloballyEnabled() && _diagnosticsHandler != null) + { + return _diagnosticsHandler!.SendAsync(request, cancellationToken); + } + + if (IsNativeHandlerEnabled) + { + return _nativeHandler!.SendAsync(request, cancellationToken); + } + else + { + return _socketHandler!.SendAsync(request, cancellationToken); + } + } + + [UnsupportedOSPlatform("android")] + [UnsupportedOSPlatform("browser")] + [UnsupportedOSPlatform("ios")] + [UnsupportedOSPlatform("tvos")] + [UnsupportedOSPlatform("maccatalyst")] + public static Func DangerousAcceptAnyServerCertificateValidator => + throw new PlatformNotSupportedException(); + + private void CheckDisposed() + { + if (_disposed) + { + throw new ObjectDisposedException(GetType().ToString()); + } + } + + private object InvokeNativeHandlerMethod(string name, params object?[] parameters) + { + MethodInfo? method; + + if (!s_cachedMethods.TryGetValue(name, out method)) + { + method = _nativeHandler!.GetType()!.GetMethod(name); + s_cachedMethods[name] = method; + } + + return method!.Invoke(_nativeHandler, parameters)!; + } + + private static bool IsNativeHandlerEnabled => RuntimeSettingParser.QueryRuntimeSettingSwitch( + "System.Net.Http.UseNativeHttpHandler", + false); + } +} \ No newline at end of file diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.Apple.cs b/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.Apple.cs new file mode 100644 index 0000000000000..8569f35116c71 --- /dev/null +++ b/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.Apple.cs @@ -0,0 +1,65 @@ +// 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.Runtime.Versioning; + +namespace System.Net.Http +{ + public partial class HttpClientHandler : HttpMessageHandler + { + public virtual bool SupportsAutomaticDecompression => false; + public virtual bool SupportsProxy => false; + public virtual bool SupportsRedirectConfiguration => true; + + [UnsupportedOSPlatform("browser")] + [UnsupportedOSPlatform("ios")] + [UnsupportedOSPlatform("tvos")] + [UnsupportedOSPlatform("maccatalyst")] + public DecompressionMethods AutomaticDecompression + { + get => throw new PlatformNotSupportedException(); + set => throw new PlatformNotSupportedException(); + } + + [UnsupportedOSPlatform("browser")] + [UnsupportedOSPlatform("ios")] + [UnsupportedOSPlatform("tvos")] + [UnsupportedOSPlatform("maccatalyst")] + public bool UseProxy + { + get => throw new PlatformNotSupportedException(); + set => throw new PlatformNotSupportedException(); + } + + [UnsupportedOSPlatform("browser")] + [UnsupportedOSPlatform("ios")] + [UnsupportedOSPlatform("tvos")] + [UnsupportedOSPlatform("maccatalyst")] + public IWebProxy? Proxy + { + get => throw new PlatformNotSupportedException(); + set => throw new PlatformNotSupportedException(); + } + + [UnsupportedOSPlatform("browser")] + [UnsupportedOSPlatform("ios")] + [UnsupportedOSPlatform("tvos")] + [UnsupportedOSPlatform("maccatalyst")] + public int MaxAutomaticRedirections + { + get => throw new PlatformNotSupportedException(); + set => throw new PlatformNotSupportedException(); + } + + [UnsupportedOSPlatform("browser")] + [UnsupportedOSPlatform("ios")] + [UnsupportedOSPlatform("tvos")] + [UnsupportedOSPlatform("maccatalyst")] + public bool PreAuthenticate + { + get => throw new PlatformNotSupportedException(); + set => throw new PlatformNotSupportedException(); + } + } +} diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.MacCatalyst.cs b/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.MacCatalyst.cs new file mode 100644 index 0000000000000..886e9cd80c3e6 --- /dev/null +++ b/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.MacCatalyst.cs @@ -0,0 +1,52 @@ +// 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.Diagnostics.CodeAnalysis; +using System.Reflection; + +namespace System.Net.Http +{ + public partial class HttpClientHandler : HttpMessageHandler + { + private static MethodInfo? _nativeHandlerMethod; + + private const string NativeHandlerType = "System.Net.Http.NSUrlSessionHandler"; + private const string AssemblyName = "Xamarin.MacCatalyst"; + + [DynamicDependency("get_UseCookies", NativeHandlerType, AssemblyName)] + private bool GetUseCookies() => (bool)InvokeNativeHandlerMethod("get_UseCookies"); + + [DynamicDependency("set_UseCookies", NativeHandlerType, AssemblyName)] + private void SetUseCookies(bool value) => InvokeNativeHandlerMethod("set_UseCookies", value); + + [DynamicDependency("get_CookieContainer", NativeHandlerType, AssemblyName)] + private CookieContainer GetCookieContainer() => (CookieContainer)InvokeNativeHandlerMethod("get_CookieContainer"); + + [DynamicDependency("set_CookieContainer", NativeHandlerType, AssemblyName)] + private void SetCookieContainer(CookieContainer value) => InvokeNativeHandlerMethod("set_CookieContainer", value); + + [DynamicDependency("get_AllowAutoRedirect", NativeHandlerType, AssemblyName)] + private bool GetAllowAutoRedirect() => (bool)InvokeNativeHandlerMethod("get_AllowAutoRedirect"); + + [DynamicDependency("set_AllowAutoRedirect", NativeHandlerType, AssemblyName)] + private void SetAllowAutoRedirect(bool value) => InvokeNativeHandlerMethod("set_AllowAutoRedirect", value); + + [DynamicDependency("get_Credentials", NativeHandlerType, AssemblyName)] + private ICredentials GetCredentials() => (ICredentials)InvokeNativeHandlerMethod("get_Credentials"); + + [DynamicDependency("set_Credentials", NativeHandlerType, AssemblyName)] + private void SetCredentials(ICredentials? value) => InvokeNativeHandlerMethod("set_Credentials", value); + + private HttpMessageHandler CreateNativeHandler() + { + if (_nativeHandlerMethod == null) + { + Type? runtimeOptions = Type.GetType("ObjCRuntime.RuntimeOptions, Xamarin.MacCatalyst"); + _nativeHandlerMethod = runtimeOptions!.GetMethod("GetHttpMessageHandler", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static); + } + + return (HttpMessageHandler)_nativeHandlerMethod!.Invoke(null, null)!; + } + } +} \ No newline at end of file diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.cs b/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.cs index fce5166f279ed..30ff13bd09b99 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.cs @@ -86,6 +86,9 @@ public CookieContainer CookieContainer } [UnsupportedOSPlatform("browser")] + [UnsupportedOSPlatform("ios")] + [UnsupportedOSPlatform("tvos")] + [UnsupportedOSPlatform("maccatalyst")] public DecompressionMethods AutomaticDecompression { get => _underlyingHandler.AutomaticDecompression; @@ -93,6 +96,9 @@ public DecompressionMethods AutomaticDecompression } [UnsupportedOSPlatform("browser")] + [UnsupportedOSPlatform("ios")] + [UnsupportedOSPlatform("tvos")] + [UnsupportedOSPlatform("maccatalyst")] public bool UseProxy { get => _underlyingHandler.UseProxy; @@ -100,13 +106,20 @@ public bool UseProxy } [UnsupportedOSPlatform("browser")] + [UnsupportedOSPlatform("ios")] + [UnsupportedOSPlatform("tvos")] + [UnsupportedOSPlatform("maccatalyst")] public IWebProxy? Proxy { get => _underlyingHandler.Proxy; set => _underlyingHandler.Proxy = value; } + [UnsupportedOSPlatform("android")] [UnsupportedOSPlatform("browser")] + [UnsupportedOSPlatform("ios")] + [UnsupportedOSPlatform("tvos")] + [UnsupportedOSPlatform("maccatalyst")] public ICredentials? DefaultProxyCredentials { get => _underlyingHandler.DefaultProxyCredentials; @@ -114,6 +127,9 @@ public ICredentials? DefaultProxyCredentials } [UnsupportedOSPlatform("browser")] + [UnsupportedOSPlatform("ios")] + [UnsupportedOSPlatform("tvos")] + [UnsupportedOSPlatform("maccatalyst")] public bool PreAuthenticate { get => _underlyingHandler.PreAuthenticate; @@ -157,13 +173,20 @@ public bool AllowAutoRedirect } [UnsupportedOSPlatform("browser")] + [UnsupportedOSPlatform("ios")] + [UnsupportedOSPlatform("tvos")] + [UnsupportedOSPlatform("maccatalyst")] public int MaxAutomaticRedirections { get => _underlyingHandler.MaxAutomaticRedirections; set => _underlyingHandler.MaxAutomaticRedirections = value; } + [UnsupportedOSPlatform("android")] [UnsupportedOSPlatform("browser")] + [UnsupportedOSPlatform("ios")] + [UnsupportedOSPlatform("tvos")] + [UnsupportedOSPlatform("maccatalyst")] public int MaxConnectionsPerServer { get => _underlyingHandler.MaxConnectionsPerServer; @@ -203,13 +226,21 @@ public long MaxRequestContentBufferSize } } + [UnsupportedOSPlatform("android")] [UnsupportedOSPlatform("browser")] + [UnsupportedOSPlatform("ios")] + [UnsupportedOSPlatform("tvos")] + [UnsupportedOSPlatform("maccatalyst")] public int MaxResponseHeadersLength { get => _underlyingHandler.MaxResponseHeadersLength; set => _underlyingHandler.MaxResponseHeadersLength = value; } + [UnsupportedOSPlatform("android")] + [UnsupportedOSPlatform("ios")] + [UnsupportedOSPlatform("tvos")] + [UnsupportedOSPlatform("maccatalyst")] public ClientCertificateOption ClientCertificateOptions { get => _clientCertificateOptions; @@ -243,7 +274,11 @@ public ClientCertificateOption ClientCertificateOptions } } + [UnsupportedOSPlatform("android")] [UnsupportedOSPlatform("browser")] + [UnsupportedOSPlatform("ios")] + [UnsupportedOSPlatform("tvos")] + [UnsupportedOSPlatform("maccatalyst")] public X509CertificateCollection ClientCertificates { get @@ -258,7 +293,11 @@ public X509CertificateCollection ClientCertificates } } + [UnsupportedOSPlatform("android")] [UnsupportedOSPlatform("browser")] + [UnsupportedOSPlatform("ios")] + [UnsupportedOSPlatform("tvos")] + [UnsupportedOSPlatform("maccatalyst")] public Func? ServerCertificateCustomValidationCallback { #if TARGET_BROWSER @@ -276,7 +315,11 @@ public X509CertificateCollection ClientCertificates #endif } + [UnsupportedOSPlatform("android")] [UnsupportedOSPlatform("browser")] + [UnsupportedOSPlatform("ios")] + [UnsupportedOSPlatform("tvos")] + [UnsupportedOSPlatform("maccatalyst")] public bool CheckCertificateRevocationList { get => _underlyingHandler.SslOptions.CertificateRevocationCheckMode == X509RevocationMode.Online; @@ -287,7 +330,11 @@ public bool CheckCertificateRevocationList } } + [UnsupportedOSPlatform("android")] [UnsupportedOSPlatform("browser")] + [UnsupportedOSPlatform("ios")] + [UnsupportedOSPlatform("tvos")] + [UnsupportedOSPlatform("maccatalyst")] public SslProtocols SslProtocols { get => _underlyingHandler.SslOptions.EnabledSslProtocols; @@ -298,9 +345,21 @@ public SslProtocols SslProtocols } } + [UnsupportedOSPlatform("android")] + [UnsupportedOSPlatform("ios")] + [UnsupportedOSPlatform("tvos")] + [UnsupportedOSPlatform("maccatalyst")] public IDictionary Properties => _underlyingHandler.Properties; + // + // Attributes are commented out due to https://github.com/dotnet/arcade/issues/7585 + // API compat will fail until this is fixed + // + //[UnsupportedOSPlatform("android")] [UnsupportedOSPlatform("browser")] + //[UnsupportedOSPlatform("ios")] + //[UnsupportedOSPlatform("tvos")] + //[UnsupportedOSPlatform("maccatalyst")] protected internal override HttpResponseMessage Send(HttpRequestMessage request, CancellationToken cancellationToken) => Handler.Send(request, cancellationToken); @@ -309,7 +368,11 @@ protected internal override Task SendAsync(HttpRequestMessa // lazy-load the validator func so it can be trimmed by the ILLinker if it isn't used. private static Func? s_dangerousAcceptAnyServerCertificateValidator; + [UnsupportedOSPlatform("android")] [UnsupportedOSPlatform("browser")] + [UnsupportedOSPlatform("ios")] + [UnsupportedOSPlatform("tvos")] + [UnsupportedOSPlatform("maccatalyst")] public static Func DangerousAcceptAnyServerCertificateValidator => Volatile.Read(ref s_dangerousAcceptAnyServerCertificateValidator) ?? Interlocked.CompareExchange(ref s_dangerousAcceptAnyServerCertificateValidator, delegate { return true; }, null) ?? diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.iOS.cs b/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.iOS.cs new file mode 100644 index 0000000000000..ff9e9108d2851 --- /dev/null +++ b/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.iOS.cs @@ -0,0 +1,52 @@ +// 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.Diagnostics.CodeAnalysis; +using System.Reflection; + +namespace System.Net.Http +{ + public partial class HttpClientHandler : HttpMessageHandler + { + private static MethodInfo? _nativeHandlerMethod; + + private const string NativeHandlerType = "System.Net.Http.NSUrlSessionHandler"; + private const string AssemblyName = "Xamarin.iOS"; + + [DynamicDependency("get_UseCookies", NativeHandlerType, AssemblyName)] + private bool GetUseCookies() => (bool)InvokeNativeHandlerMethod("get_UseCookies"); + + [DynamicDependency("set_UseCookies", NativeHandlerType, AssemblyName)] + private void SetUseCookies(bool value) => InvokeNativeHandlerMethod("set_UseCookies", value); + + [DynamicDependency("get_CookieContainer", NativeHandlerType, AssemblyName)] + private CookieContainer GetCookieContainer() => (CookieContainer)InvokeNativeHandlerMethod("get_CookieContainer"); + + [DynamicDependency("set_CookieContainer", NativeHandlerType, AssemblyName)] + private void SetCookieContainer(CookieContainer value) => InvokeNativeHandlerMethod("set_CookieContainer", value); + + [DynamicDependency("get_AllowAutoRedirect", NativeHandlerType, AssemblyName)] + private bool GetAllowAutoRedirect() => (bool)InvokeNativeHandlerMethod("get_AllowAutoRedirect"); + + [DynamicDependency("set_AllowAutoRedirect", NativeHandlerType, AssemblyName)] + private void SetAllowAutoRedirect(bool value) => InvokeNativeHandlerMethod("set_AllowAutoRedirect", value); + + [DynamicDependency("get_Credentials", NativeHandlerType, AssemblyName)] + private ICredentials GetCredentials() => (ICredentials)InvokeNativeHandlerMethod("get_Credentials"); + + [DynamicDependency("set_Credentials", NativeHandlerType, AssemblyName)] + private void SetCredentials(ICredentials? value) => InvokeNativeHandlerMethod("set_Credentials", value); + + private HttpMessageHandler CreateNativeHandler() + { + if (_nativeHandlerMethod == null) + { + Type? runtimeOptions = Type.GetType("ObjCRuntime.RuntimeOptions, Xamarin.iOS"); + _nativeHandlerMethod = runtimeOptions!.GetMethod("GetHttpMessageHandler", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static); + } + + return (HttpMessageHandler)_nativeHandlerMethod!.Invoke(null, null)!; + } + } +} \ No newline at end of file diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.tvOS.cs b/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.tvOS.cs new file mode 100644 index 0000000000000..4eaa6a9ad43c0 --- /dev/null +++ b/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.tvOS.cs @@ -0,0 +1,52 @@ +// 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.Diagnostics.CodeAnalysis; +using System.Reflection; + +namespace System.Net.Http +{ + public partial class HttpClientHandler : HttpMessageHandler + { + private static MethodInfo? _nativeHandlerMethod; + + private const string NativeHandlerType = "System.Net.Http.NSUrlSessionHandler"; + private const string AssemblyName = "Xamarin.TVOS"; + + [DynamicDependency("get_UseCookies", NativeHandlerType, AssemblyName)] + private bool GetUseCookies() => (bool)InvokeNativeHandlerMethod("get_UseCookies"); + + [DynamicDependency("set_UseCookies", NativeHandlerType, AssemblyName)] + private void SetUseCookies(bool value) => InvokeNativeHandlerMethod("set_UseCookies", value); + + [DynamicDependency("get_CookieContainer", NativeHandlerType, AssemblyName)] + private CookieContainer GetCookieContainer() => (CookieContainer)InvokeNativeHandlerMethod("get_CookieContainer"); + + [DynamicDependency("set_CookieContainer", NativeHandlerType, AssemblyName)] + private void SetCookieContainer(CookieContainer value) => InvokeNativeHandlerMethod("set_CookieContainer", value); + + [DynamicDependency("get_AllowAutoRedirect", NativeHandlerType, AssemblyName)] + private bool GetAllowAutoRedirect() => (bool)InvokeNativeHandlerMethod("get_AllowAutoRedirect"); + + [DynamicDependency("set_AllowAutoRedirect", NativeHandlerType, AssemblyName)] + private void SetAllowAutoRedirect(bool value) => InvokeNativeHandlerMethod("set_AllowAutoRedirect", value); + + [DynamicDependency("get_Credentials", NativeHandlerType, AssemblyName)] + private ICredentials GetCredentials() => (ICredentials)InvokeNativeHandlerMethod("get_Credentials"); + + [DynamicDependency("set_Credentials", NativeHandlerType, AssemblyName)] + private void SetCredentials(ICredentials? value) => InvokeNativeHandlerMethod("set_Credentials", value); + + private HttpMessageHandler CreateNativeHandler() + { + if (_nativeHandlerMethod == null) + { + Type? runtimeOptions = Type.GetType("ObjCRuntime.RuntimeOptions, Xamarin.TVOS"); + _nativeHandlerMethod = runtimeOptions!.GetMethod("GetHttpMessageHandler", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static); + } + + return (HttpMessageHandler)_nativeHandlerMethod!.Invoke(null, null)!; + } + } +} \ No newline at end of file diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/RuntimeSettingParser.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/RuntimeSettingParser.cs index 2fc23028f9b58..e950e218552a0 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/RuntimeSettingParser.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/RuntimeSettingParser.cs @@ -35,6 +35,22 @@ public static bool QueryRuntimeSettingSwitch(string appCtxSettingName, string en return defaultValue; } + /// + /// Parse a value from an AppContext switch. + /// + public static bool QueryRuntimeSettingSwitch(string appCtxSettingName, bool defaultValue) + { + bool value; + + // First check for the AppContext switch, giving it priority over the environment variable. + if (AppContext.TryGetSwitch(appCtxSettingName, out value)) + { + return value; + } + + return defaultValue; + } + /// /// Parse an environment variable for an value. /// diff --git a/src/libraries/System.Net.Http/tests/UnitTests/System.Net.Http.Unit.Tests.csproj b/src/libraries/System.Net.Http/tests/UnitTests/System.Net.Http.Unit.Tests.csproj index d6a2cc28d1113..0a92e47df32ea 100644 --- a/src/libraries/System.Net.Http/tests/UnitTests/System.Net.Http.Unit.Tests.csproj +++ b/src/libraries/System.Net.Http/tests/UnitTests/System.Net.Http.Unit.Tests.csproj @@ -184,12 +184,6 @@ Link="ProductionCode\System\Net\Http\Headers\WarningHeaderValue.cs" /> - - false false - true + false @@ -31,7 +31,7 @@ - + false true false @@ -39,7 +39,7 @@ false true false - true + false