Remove CurlHandler fallback from HttpClientHandler (dotnet/corefx#42451)
authorMarie Píchová <mapichov@microsoft.com>
Fri, 8 Nov 2019 22:09:47 +0000 (23:09 +0100)
committerStephen Toub <stoub@microsoft.com>
Fri, 8 Nov 2019 22:09:46 +0000 (17:09 -0500)
* Removed native curl usage and CurlHandler.

* More CURL removal in test code.

* More test fixing.

* Addressing PR comments

* Comments and typos.

* Removed constant bool fields with all occurences.

Commit migrated from https://github.com/dotnet/corefx/commit/8888c74e34f9a7df060258664dffe7ac29916443

47 files changed:
src/libraries/Common/src/Interop/Unix/System.Net.Http.Native/Interop.CURLcode.cs [deleted file]
src/libraries/Common/src/Interop/Unix/System.Net.Http.Native/Interop.Easy.cs [deleted file]
src/libraries/Common/src/Interop/Unix/System.Net.Http.Native/Interop.Initialization.cs [deleted file]
src/libraries/Common/src/Interop/Unix/System.Net.Http.Native/Interop.Multi.cs [deleted file]
src/libraries/Common/src/Interop/Unix/System.Net.Http.Native/Interop.SList.cs [deleted file]
src/libraries/Common/src/Interop/Unix/System.Net.Http.Native/Interop.VersionInfo.cs [deleted file]
src/libraries/Native/Unix/CMakeLists.txt
src/libraries/Native/Unix/System.Net.Http.Native/CMakeLists.txt [deleted file]
src/libraries/Native/Unix/System.Net.Http.Native/pal_curlinit.c [deleted file]
src/libraries/Native/Unix/System.Net.Http.Native/pal_curlinit.h [deleted file]
src/libraries/Native/Unix/System.Net.Http.Native/pal_easy.c [deleted file]
src/libraries/Native/Unix/System.Net.Http.Native/pal_easy.h [deleted file]
src/libraries/Native/Unix/System.Net.Http.Native/pal_multi.c [deleted file]
src/libraries/Native/Unix/System.Net.Http.Native/pal_multi.h [deleted file]
src/libraries/Native/Unix/System.Net.Http.Native/pal_slist.c [deleted file]
src/libraries/Native/Unix/System.Net.Http.Native/pal_slist.h [deleted file]
src/libraries/Native/Unix/System.Net.Http.Native/pal_versioninfo.c [deleted file]
src/libraries/Native/Unix/System.Net.Http.Native/pal_versioninfo.h [deleted file]
src/libraries/Native/Unix/configure.cmake
src/libraries/System.Net.Http/src/System.Net.Http.csproj
src/libraries/System.Net.Http/src/System/Net/Http/CurlHandler/CurlException.cs [deleted file]
src/libraries/System.Net.Http/src/System/Net/Http/CurlHandler/CurlHandler.ClientCertificateProvider.cs [deleted file]
src/libraries/System.Net.Http/src/System/Net/Http/CurlHandler/CurlHandler.CurlResponseMessage.cs [deleted file]
src/libraries/System.Net.Http/src/System/Net/Http/CurlHandler/CurlHandler.EasyRequest.cs [deleted file]
src/libraries/System.Net.Http/src/System/Net/Http/CurlHandler/CurlHandler.MultiAgent.cs [deleted file]
src/libraries/System.Net.Http/src/System/Net/Http/CurlHandler/CurlHandler.SslProvider.Linux.cs [deleted file]
src/libraries/System.Net.Http/src/System/Net/Http/CurlHandler/CurlHandler.SslProvider.OSX.cs [deleted file]
src/libraries/System.Net.Http/src/System/Net/Http/CurlHandler/CurlHandler.cs [deleted file]
src/libraries/System.Net.Http/src/System/Net/Http/CurlHandler/CurlResponseHeaderReader.cs [deleted file]
src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.Unix.cs
src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.cs
src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientEKUTest.cs
src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.ClientCertificates.cs
src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.ServerCertificates.Unix.cs [deleted file]
src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.ServerCertificates.Windows.cs [deleted file]
src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.ServerCertificates.cs
src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.SslProtocols.Unix.cs [deleted file]
src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.SslProtocols.Windows.cs [deleted file]
src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.SslProtocols.cs
src/libraries/System.Net.Http/tests/FunctionalTests/PlatformHandlerTest.cs
src/libraries/System.Net.Http/tests/FunctionalTests/SocketsHttpHandlerTest.cs
src/libraries/System.Net.Http/tests/FunctionalTests/System.Net.Http.Functional.Tests.csproj
src/libraries/System.Net.Http/tests/FunctionalTests/TestHelper.cs
src/libraries/System.Net.Http/tests/UnitTests/Headers/CurlResponseHeaderReaderTest.cs [deleted file]
src/libraries/System.Net.Http/tests/UnitTests/System.Net.Http.Unit.Tests.csproj
src/libraries/System.Net.Requests/src/System.Net.Requests.csproj
src/libraries/System.Net.Requests/src/System/Net/WebExceptionPal.Unix.cs

diff --git a/src/libraries/Common/src/Interop/Unix/System.Net.Http.Native/Interop.CURLcode.cs b/src/libraries/Common/src/Interop/Unix/System.Net.Http.Native/Interop.CURLcode.cs
deleted file mode 100644 (file)
index b2d0c5c..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-internal static partial class Interop
-{
-    internal static partial class Http
-    {
-        // Enum for constants defined for the enum CURLcode in curl.h
-        internal enum CURLcode
-        {
-            CURLE_OK = 0,
-            CURLE_UNSUPPORTED_PROTOCOL  =  1,
-            CURLE_FAILED_INIT = 2,
-            CURLE_NOT_BUILT_IN = 4,
-            CURLE_COULDNT_RESOLVE_HOST  =  6,
-            CURLE_OUT_OF_MEMORY = 27,
-            CURLE_OPERATION_TIMEDOUT = 28,
-            CURLE_ABORTED_BY_CALLBACK = 42,
-            CURLE_UNKNOWN_OPTION = 48,
-            CURLE_RECV_ERROR = 56,
-            CURLE_SEND_FAIL_REWIND = 65
-        }
-    }
-}
diff --git a/src/libraries/Common/src/Interop/Unix/System.Net.Http.Native/Interop.Easy.cs b/src/libraries/Common/src/Interop/Unix/System.Net.Http.Native/Interop.Easy.cs
deleted file mode 100644 (file)
index 2bf8f4e..0000000
+++ /dev/null
@@ -1,269 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System;
-using System.Runtime.InteropServices;
-
-internal static partial class Interop
-{
-    internal static partial class Http
-    {
-        [DllImport(Libraries.HttpNative, EntryPoint = "HttpNative_EasyCreate")]
-        public static extern SafeCurlHandle EasyCreate();
-
-        [DllImport(Libraries.HttpNative, EntryPoint = "HttpNative_EasyDestroy")]
-        private static extern void EasyDestroy(IntPtr handle);
-
-        [DllImport(Libraries.HttpNative, EntryPoint = "HttpNative_EasySetOptionString", CharSet = CharSet.Ansi)]
-        public static extern CURLcode EasySetOptionString(SafeCurlHandle curl, CURLoption option, string value);
-
-        [DllImport(Libraries.HttpNative, EntryPoint = "HttpNative_EasySetOptionLong")]
-        public static extern CURLcode EasySetOptionLong(SafeCurlHandle curl, CURLoption option, long value);
-
-        [DllImport(Libraries.HttpNative, EntryPoint = "HttpNative_EasySetOptionPointer")]
-        public static extern CURLcode EasySetOptionPointer(SafeCurlHandle curl, CURLoption option, IntPtr value);
-
-        [DllImport(Libraries.HttpNative, EntryPoint = "HttpNative_EasySetOptionPointer")]
-        public static extern CURLcode EasySetOptionPointer(SafeCurlHandle curl, CURLoption option, SafeHandle value);
-
-        [DllImport(Libraries.HttpNative, EntryPoint = "HttpNative_EasyGetErrorString")]
-        public static extern IntPtr EasyGetErrorString(int code);
-
-        [DllImport(Libraries.HttpNative, EntryPoint = "HttpNative_EasyGetInfoPointer")]
-        public static extern CURLcode EasyGetInfoPointer(IntPtr handle, CURLINFO info, out IntPtr value);
-
-        [DllImport(Libraries.HttpNative, EntryPoint = "HttpNative_EasyGetInfoPointer")]
-        public static extern CURLcode EasyGetInfoPointer(SafeCurlHandle handle, CURLINFO info, out IntPtr value);
-
-        [DllImport(Libraries.HttpNative, EntryPoint = "HttpNative_EasyGetInfoLong")]
-        public static extern CURLcode EasyGetInfoLong(SafeCurlHandle handle, CURLINFO info, out long value);
-
-        [DllImport(Libraries.HttpNative, EntryPoint = "HttpNative_EasyPerform")]
-        public static extern CURLcode EasyPerform(SafeCurlHandle curl);
-
-        [DllImport(Libraries.HttpNative, EntryPoint = "HttpNative_EasyUnpause")]
-        public static extern CURLcode EasyUnpause(SafeCurlHandle easy);
-
-        public delegate CurlSeekResult SeekCallback(IntPtr userPointer, long offset, int origin);
-
-        public delegate ulong ReadWriteCallback(IntPtr buffer, ulong bufferSize, ulong nitems, IntPtr userPointer);
-
-        public delegate CURLcode SslCtxCallback(IntPtr curl, IntPtr sslCtx, IntPtr userPointer);
-
-        public delegate void DebugCallback(IntPtr curl, CurlInfoType type, IntPtr data, ulong size, IntPtr userPointer);
-
-        [DllImport(Libraries.HttpNative, EntryPoint = "HttpNative_RegisterSeekCallback")]
-        public static extern void RegisterSeekCallback(
-            SafeCurlHandle curl,
-            SeekCallback callback,
-            IntPtr userPointer,
-            ref SafeCallbackHandle callbackHandle);
-
-        [DllImport(Libraries.HttpNative, EntryPoint = "HttpNative_RegisterReadWriteCallback")]
-        public static extern void RegisterReadWriteCallback(
-            SafeCurlHandle curl,
-            ReadWriteFunction functionType,
-            ReadWriteCallback callback,
-            IntPtr userPointer,
-            ref SafeCallbackHandle callbackHandle);
-
-        [DllImport(Libraries.HttpNative, EntryPoint = "HttpNative_RegisterSslCtxCallback")]
-        public static extern CURLcode RegisterSslCtxCallback(
-            SafeCurlHandle curl,
-            SslCtxCallback callback,
-            IntPtr userPointer,
-            ref SafeCallbackHandle callbackHandle);
-
-        [DllImport(Libraries.HttpNative, EntryPoint = "HttpNative_RegisterDebugCallback")]
-        public static extern CURLcode RegisterDebugCallback(
-            SafeCurlHandle curl,
-            DebugCallback callback,
-            IntPtr userPointer,
-            ref SafeCallbackHandle callbackHandle);
-
-        [DllImport(Libraries.HttpNative, EntryPoint = "HttpNative_FreeCallbackHandle")]
-        private static extern void FreeCallbackHandle(IntPtr handle);
-
-        // Curl options are of the format <type base> + <n>
-        private const int CurlOptionLongBase = 0;
-        private const int CurlOptionObjectPointBase = 10000;
-        private const int CurlOptionOffTBase = 30000;
-
-        // Enum for constants defined for the enum CURLoption in curl.h
-        internal enum CURLoption
-        {
-            CURLOPT_INFILESIZE = CurlOptionLongBase + 14,
-            CURLOPT_SSLVERSION = CurlOptionLongBase + 32,
-            CURLOPT_VERBOSE = CurlOptionLongBase + 41,
-            CURLOPT_NOBODY = CurlOptionLongBase + 44,
-            CURLOPT_UPLOAD = CurlOptionLongBase + 46,
-            CURLOPT_POST = CurlOptionLongBase + 47,
-            CURLOPT_FOLLOWLOCATION = CurlOptionLongBase + 52,
-            CURLOPT_PROXYPORT = CurlOptionLongBase + 59,
-            CURLOPT_POSTFIELDSIZE = CurlOptionLongBase + 60,
-            CURLOPT_SSL_VERIFYPEER = CurlOptionLongBase + 64,
-            CURLOPT_MAXREDIRS = CurlOptionLongBase + 68,
-            CURLOPT_SSL_VERIFYHOST = CurlOptionLongBase + 81,
-            CURLOPT_HTTP_VERSION = CurlOptionLongBase + 84,
-            CURLOPT_DNS_CACHE_TIMEOUT = CurlOptionLongBase + 92,
-            CURLOPT_NOSIGNAL = CurlOptionLongBase + 99,
-            CURLOPT_PROXYTYPE = CurlOptionLongBase + 101,
-            CURLOPT_HTTPAUTH = CurlOptionLongBase + 107,
-            CURLOPT_TCP_NODELAY = CurlOptionLongBase + 121,
-            CURLOPT_TCP_KEEPALIVE = CurlOptionLongBase + 213,
-            CURLOPT_CONNECTTIMEOUT_MS = CurlOptionLongBase + 156,
-            CURLOPT_ADDRESS_SCOPE = CurlOptionLongBase + 171,
-            CURLOPT_PROTOCOLS = CurlOptionLongBase + 181,
-            CURLOPT_REDIR_PROTOCOLS = CurlOptionLongBase + 182,
-
-            CURLOPT_URL = CurlOptionObjectPointBase + 2,
-            CURLOPT_PROXY = CurlOptionObjectPointBase + 4,
-            CURLOPT_PROXYUSERPWD = CurlOptionObjectPointBase + 6,
-            CURLOPT_COOKIE = CurlOptionObjectPointBase + 22,
-            CURLOPT_HTTPHEADER = CurlOptionObjectPointBase + 23,
-            CURLOPT_CUSTOMREQUEST = CurlOptionObjectPointBase + 36,
-            CURLOPT_ACCEPT_ENCODING = CurlOptionObjectPointBase + 102,
-            CURLOPT_PRIVATE = CurlOptionObjectPointBase + 103,
-            CURLOPT_COPYPOSTFIELDS = CurlOptionObjectPointBase + 165,
-            CURLOPT_USERNAME = CurlOptionObjectPointBase + 173,
-            CURLOPT_PASSWORD = CurlOptionObjectPointBase + 174,
-            CURLOPT_CAPATH = CurlOptionObjectPointBase + 97,
-            CURLOPT_PROXY_CAPATH = CurlOptionObjectPointBase + 247,
-            CURLOPT_CAINFO = CurlOptionObjectPointBase + 65,
-            CURLOPT_PROXY_CAINFO = CurlOptionObjectPointBase + 246,
-
-            CURLOPT_INFILESIZE_LARGE = CurlOptionOffTBase + 115,
-            CURLOPT_POSTFIELDSIZE_LARGE = CurlOptionOffTBase + 120,
-        }
-
-        internal enum ReadWriteFunction
-        {
-            Write = 0,
-            Read = 1,
-            Header = 2,
-        }
-
-        // Curl info are of the format <type base> + <n>
-        private const int CurlInfoStringBase = 0x100000;
-        private const int CurlInfoLongBase = 0x200000;
-
-        // Enum for constants defined for CURL_HTTP_VERSION
-        internal enum CurlHttpVersion
-        {
-            CURL_HTTP_VERSION_NONE = 0,
-            CURL_HTTP_VERSION_1_0 = 1,
-            CURL_HTTP_VERSION_1_1 = 2,
-            CURL_HTTP_VERSION_2TLS = 4,
-        };
-
-        // Enum for constants defined for CURL_SSLVERSION
-        internal enum CurlSslVersion
-        {
-            CURL_SSLVERSION_TLSv1 = 1,   /* TLS 1.x */
-            CURL_SSLVERSION_SSLv2 = 2,   /* SSL 2 */
-            CURL_SSLVERSION_SSLv3 = 3,   /* SSL 3 */
-            CURL_SSLVERSION_TLSv1_0 = 4, /* TLS 1.0 */
-            CURL_SSLVERSION_TLSv1_1 = 5, /* TLS 1.1 */
-            CURL_SSLVERSION_TLSv1_2 = 6, /* TLS 1.2 */
-            CURL_SSLVERSION_TLSv1_3 = 7, /* TLS 1.3 */
-        };
-
-        // Enum for constants defined for the enum CURLINFO in curl.h
-        internal enum CURLINFO
-        {
-            CURLINFO_EFFECTIVE_URL = CurlInfoStringBase + 1,
-            CURLINFO_PRIVATE = CurlInfoStringBase + 21,
-            CURLINFO_HTTPAUTH_AVAIL = CurlInfoLongBase + 23,
-        }
-
-        // AUTH related constants
-        [Flags]
-        internal enum CURLAUTH
-        {
-            None = 0,
-            Basic = 1 << 0,
-            Digest = 1 << 1,
-            Negotiate = 1 << 2,
-            NTLM = 1 << 3,
-        }
-
-        // Enum for constants defined for the enum curl_proxytype in curl.h
-        internal enum curl_proxytype
-        {
-            CURLPROXY_HTTP = 0,
-        }
-
-        [Flags]
-        internal enum CurlProtocols
-        {
-            CURLPROTO_HTTP = (1 << 0),
-            CURLPROTO_HTTPS = (1 << 1),
-        }
-
-        // Enum for constants defined for the results of CURL_SEEKFUNCTION
-        internal enum CurlSeekResult : int
-        {
-            CURL_SEEKFUNC_OK = 0,
-            CURL_SEEKFUNC_FAIL = 1,
-            CURL_SEEKFUNC_CANTSEEK = 2,
-        }
-
-        internal enum CurlInfoType : int
-        {
-            CURLINFO_TEXT = 0,
-            CURLINFO_HEADER_IN = 1,
-            CURLINFO_HEADER_OUT = 2,
-            CURLINFO_DATA_IN = 3,
-            CURLINFO_DATA_OUT = 4,
-            CURLINFO_SSL_DATA_IN = 5,
-            CURLINFO_SSL_DATA_OUT = 6,
-        };
-
-        // constants defined for the results of a CURL_READ or CURL_WRITE function
-        internal const ulong CURL_READFUNC_ABORT = 0x10000000;
-        internal const ulong CURL_READFUNC_PAUSE = 0x10000001;
-        internal const ulong CURL_WRITEFUNC_PAUSE = 0x10000001;
-
-        internal const ulong CURL_MAX_HTTP_HEADER = 100 * 1024;
-
-        internal sealed class SafeCurlHandle : SafeHandle
-        {
-            public SafeCurlHandle() : base(IntPtr.Zero, true)
-            {
-            }
-
-            public override bool IsInvalid
-            {
-                get { return handle == IntPtr.Zero; }
-            }
-
-            protected override bool ReleaseHandle()
-            {
-                EasyDestroy(handle);
-                SetHandle(IntPtr.Zero);
-                return true;
-            }
-        }
-
-        internal sealed class SafeCallbackHandle : SafeHandle
-        {
-            public SafeCallbackHandle()
-                : base(IntPtr.Zero, true)
-            {
-            }
-
-            public override bool IsInvalid
-            {
-                get { return handle == IntPtr.Zero; }
-            }
-
-            protected override bool ReleaseHandle()
-            {
-                FreeCallbackHandle(handle);
-                SetHandle(IntPtr.Zero);
-                return true;
-            }
-        }
-    }
-}
diff --git a/src/libraries/Common/src/Interop/Unix/System.Net.Http.Native/Interop.Initialization.cs b/src/libraries/Common/src/Interop/Unix/System.Net.Http.Native/Interop.Initialization.cs
deleted file mode 100644 (file)
index bf8bef8..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System;
-using System.Runtime.InteropServices;
-
-internal static partial class Interop
-{
-    // Initialization of libcurl is done in a static constructor.
-    // This enables a project simply to include this file, and any usage of any of
-    // the Http functions will trigger initialization.
-
-    internal static partial class Http
-    {
-        static Http()
-        {
-            HttpInitializer.Initialize();
-        }
-    }
-
-    internal static class HttpInitializer
-    {
-        static HttpInitializer()
-        {
-#if !SYSNETHTTP_NO_OPENSSL
-            string opensslVersion = Interop.Http.GetSslVersionDescription();
-            if (string.IsNullOrEmpty(opensslVersion) ||
-                opensslVersion.IndexOf(Interop.Http.OpenSslDescriptionPrefix, StringComparison.OrdinalIgnoreCase) != -1)
-            {
-                // CURL uses OpenSSL which we must initialize first to guarantee thread-safety.
-                // We'll wake up whatever OpenSSL we're going to run against, but might later determine that
-                // they aren't compatible.
-                CryptoInitializer.Initialize();
-            }
-#endif
-
-            if (EnsureCurlIsInitialized() != 0)
-            {
-                throw new InvalidOperationException();
-            }
-        }
-
-        internal static void Initialize()
-        {
-            // No-op that exists to provide a hook for other static constructors
-        }
-
-        [DllImport(Libraries.HttpNative, EntryPoint = "HttpNative_EnsureCurlIsInitialized")]
-        private static extern int EnsureCurlIsInitialized();
-    }
-}
diff --git a/src/libraries/Common/src/Interop/Unix/System.Net.Http.Native/Interop.Multi.cs b/src/libraries/Common/src/Interop/Unix/System.Net.Http.Native/Interop.Multi.cs
deleted file mode 100644 (file)
index f3c058e..0000000
+++ /dev/null
@@ -1,104 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System;
-using System.Runtime.InteropServices;
-using Microsoft.Win32.SafeHandles;
-
-internal static partial class Interop
-{
-    internal static partial class Http
-    {
-        [DllImport(Libraries.HttpNative, EntryPoint = "HttpNative_MultiCreate")]
-        public static extern SafeCurlMultiHandle MultiCreate();
-
-        [DllImport(Libraries.HttpNative, EntryPoint = "HttpNative_MultiDestroy")]
-        private static extern CURLMcode MultiDestroy(IntPtr handle);
-
-        [DllImport(Libraries.HttpNative, EntryPoint = "HttpNative_MultiAddHandle")]
-        public static extern CURLMcode MultiAddHandle(SafeCurlMultiHandle multiHandle, SafeCurlHandle easyHandle);
-
-        [DllImport(Libraries.HttpNative, EntryPoint = "HttpNative_MultiRemoveHandle")]
-        public static extern CURLMcode MultiRemoveHandle(SafeCurlMultiHandle multiHandle, SafeCurlHandle easyHandle);
-
-        [DllImport(Libraries.HttpNative, EntryPoint = "HttpNative_MultiWait")]
-        public static extern CURLMcode MultiWait(
-            SafeCurlMultiHandle multiHandle,
-            SafeFileHandle extraFileDescriptor,
-            out bool isExtraFileDescriptorActive,
-            out bool isTimeout);
-
-        [DllImport(Libraries.HttpNative, EntryPoint = "HttpNative_MultiPerform")]
-        public static extern CURLMcode MultiPerform(SafeCurlMultiHandle multiHandle);
-
-        [DllImport(Libraries.HttpNative, EntryPoint = "HttpNative_MultiInfoRead")]
-        public static extern bool MultiInfoRead(
-            SafeCurlMultiHandle multiHandle,
-            out CURLMSG message,
-            out IntPtr easyHandle,
-            out CURLcode result);
-
-        [DllImport(Libraries.HttpNative, EntryPoint = "HttpNative_MultiGetErrorString")]
-        public static extern IntPtr MultiGetErrorString(int code);
-
-        [DllImport(Libraries.HttpNative, EntryPoint = "HttpNative_MultiSetOptionLong")]
-        public static extern CURLMcode MultiSetOptionLong(SafeCurlMultiHandle curl, CURLMoption option, long value);
-
-        // Enum for constants defined for the enum CURLMcode in multi.h
-        internal enum CURLMcode : int
-        {
-            CURLM_CALL_MULTI_PERFORM = -1,
-            CURLM_OK = 0,
-            CURLM_BAD_HANDLE = 1,
-            CURLM_BAD_EASY_HANDLE = 2,
-            CURLM_OUT_OF_MEMORY = 3,
-            CURLM_INTERNAL_ERROR = 4,
-            CURLM_BAD_SOCKET = 5,
-            CURLM_UNKNOWN_OPTION = 6,
-            CURLM_ADDED_ALREADY = 7,
-        }
-
-        internal enum CURLMoption : int
-        {
-            CURLMOPT_PIPELINING = 3,
-            CURLMOPT_MAX_HOST_CONNECTIONS = 7,
-        }
-
-        internal enum CurlPipe : int
-        {
-            CURLPIPE_MULTIPLEX = 2
-        }
-
-        // Enum for constants defined for the enum CURLMSG in multi.h
-        internal enum CURLMSG : int
-        {
-            CURLMSG_DONE = 1,
-        }
-
-        internal sealed class SafeCurlMultiHandle : SafeHandle
-        {
-            public SafeCurlMultiHandle()
-                : base(IntPtr.Zero, true)
-            {
-            }
-
-            public override bool IsInvalid
-            {
-                get { return this.handle == IntPtr.Zero; }
-            }
-
-            protected override bool ReleaseHandle()
-            {
-                bool result = MultiDestroy(handle) == CURLMcode.CURLM_OK;
-                SetHandle(IntPtr.Zero);
-
-#if !SYSNETHTTP_NO_OPENSSL
-                Interop.Crypto.ErrClearError(); // Ensure that no SSL errors were left on the queue by libcurl.
-#endif
-
-                return result;
-            }
-        }
-    }
-}
diff --git a/src/libraries/Common/src/Interop/Unix/System.Net.Http.Native/Interop.SList.cs b/src/libraries/Common/src/Interop/Unix/System.Net.Http.Native/Interop.SList.cs
deleted file mode 100644 (file)
index 58fe776..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System;
-using System.Runtime.InteropServices;
-
-internal static partial class Interop
-{
-    internal static partial class Http
-    {
-        [DllImport(Libraries.HttpNative, EntryPoint = "HttpNative_SListAppend", CharSet = CharSet.Ansi)]
-        private static extern IntPtr SListAppend(IntPtr slist, string headerValue);
-
-        internal static bool SListAppend(SafeCurlSListHandle slist, string headerValue)
-        {
-            bool gotRef = false;
-            try
-            {
-                slist.DangerousAddRef(ref gotRef);
-                IntPtr newHandle = SListAppend(slist.DangerousGetHandle(), headerValue);
-                if (newHandle != IntPtr.Zero)
-                {
-                    slist.SetHandle(newHandle);
-                    return true;
-                }
-                return false;
-            }
-            finally
-            {
-                if (gotRef)
-                    slist.DangerousRelease();
-            }
-        }
-
-        [DllImport(Libraries.HttpNative, EntryPoint = "HttpNative_SListFreeAll")]
-        private static extern void SListFreeAll(IntPtr slist);
-
-        internal sealed class SafeCurlSListHandle : SafeHandle
-        {
-            public SafeCurlSListHandle() : base(IntPtr.Zero, true)
-            {
-            }
-
-            public override bool IsInvalid
-            {
-                get { return handle == IntPtr.Zero; }
-            }
-
-            public new void SetHandle(IntPtr newHandle)
-            {
-                base.SetHandle(newHandle);
-            }
-
-            protected override bool ReleaseHandle()
-            {
-                SListFreeAll(handle);
-                SetHandle(IntPtr.Zero);
-                return true;
-            }
-        }
-    }
-}
diff --git a/src/libraries/Common/src/Interop/Unix/System.Net.Http.Native/Interop.VersionInfo.cs b/src/libraries/Common/src/Interop/Unix/System.Net.Http.Native/Interop.VersionInfo.cs
deleted file mode 100644 (file)
index d9cb9a0..0000000
+++ /dev/null
@@ -1,114 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System;
-using System.Diagnostics;
-using System.Runtime.InteropServices;
-
-internal static partial class Interop
-{
-    internal static partial class Http
-    {
-        [Flags]
-        internal enum CurlFeatures : int
-        {
-            CURL_VERSION_IPV6 = (1 << 0),
-            CURL_VERSION_KERBEROS4 = (1 << 1),
-            CURL_VERSION_SSL = (1 << 2),
-            CURL_VERSION_LIBZ = (1 << 3),
-            CURL_VERSION_NTLM = (1 << 4),
-            CURL_VERSION_GSSNEGOTIATE = (1 << 5),
-            CURL_VERSION_DEBUG = (1 << 6),
-            CURL_VERSION_ASYNCHDNS = (1 << 7),
-            CURL_VERSION_SPNEGO = (1 << 8),
-            CURL_VERSION_LARGEFILE = (1 << 9),
-            CURL_VERSION_IDN = (1 << 10),
-            CURL_VERSION_SSPI = (1 << 11),
-            CURL_VERSION_CONV = (1 << 12),
-            CURL_VERSION_CURLDEBUG = (1 << 13),
-            CURL_VERSION_TLSAUTH_SRP = (1 << 14),
-            CURL_VERSION_NTLM_WB = (1 << 15),
-            CURL_VERSION_HTTP2 = (1 << 16),
-            CURL_VERSION_GSSAPI = (1 << 17),
-            CURL_VERSION_KERBEROS5 = (1 << 18),
-            CURL_VERSION_UNIX_SOCKETS = (1 << 19),
-            CURL_VERSION_PSL = (1 << 20),
-        };
-
-        [DllImport(Libraries.HttpNative, EntryPoint = "HttpNative_GetSupportedFeatures")]
-        internal static extern CurlFeatures GetSupportedFeatures();
-
-        [DllImport(Libraries.HttpNative, EntryPoint = "HttpNative_GetSupportsHttp2Multiplexing")]
-        internal static extern bool GetSupportsHttp2Multiplexing();
-
-        [DllImport(Libraries.HttpNative, EntryPoint = "HttpNative_GetVersionDescription")]
-        internal static extern string GetVersionDescription();
-
-        [DllImport(Libraries.HttpNative, EntryPoint = "HttpNative_GetSslVersionDescription")]
-        internal static extern string GetSslVersionDescription();
-
-        internal const string OpenSslDescriptionPrefix = "OpenSSL/";
-        internal const string SecureTransportDescription = "SecureTransport";
-        internal const string LibreSslDescription = "LibreSSL";
-
-#if !SYSNETHTTP_NO_OPENSSL
-        private static readonly Lazy<string> s_requiredOpenSslDescription =
-            new Lazy<string>(() => DetermineRequiredOpenSslDescription());
-
-        private static readonly Lazy<bool> s_hasMatchingOpenSsl =
-            new Lazy<bool>(() => RequiredOpenSslDescription == GetSslVersionDescription());
-
-        internal static string RequiredOpenSslDescription => s_requiredOpenSslDescription.Value;
-        internal static bool HasMatchingOpenSslVersion => s_hasMatchingOpenSsl.Value;
-
-        private static string DetermineRequiredOpenSslDescription()
-        {
-            long ver = Interop.OpenSsl.OpenSslVersionNumber();
-
-            // OpenSSL version numbers are encoded as
-            // 0xMNNFFPPS: major (one nybble), minor (one byte, unaligned),
-            // "fix" (one byte, unaligned), patch (one byte, unaligned), status (one nybble)
-            //
-            // e.g. 1.0.2a final is 0x1000201F
-            //
-            // libcurl's OpenSSL vtls backend ignores status in the version string.
-            // Major, minor, and fix are encoded (by libcurl) as unpadded hex
-            // (0 => "0", 15 => "f", 16 => "10").
-            //
-            // Patch is encoded as in the way OpenSSL would do it.
-            // 0x00 => ""
-            // 0x01 => "a"
-            // 0x1a (26) => "z"
-            // 0x1b (27) => "za"
-            // 0x34 (52) => "zz"
-            // 0x35 (53) should probably be "zza", but it never came up, and is not currently
-            // handled correctly by libcurl (which would call it "z{").
-
-            byte patchValue = (byte)((ver & 0xFF0) >> 4);
-            string patch = string.Empty;
-
-            if (patchValue > 52)
-            {
-                Debug.Fail($"OpenSSL version ({ver:8X}) patch value ({patchValue}) is out of range");
-                throw new InvalidOperationException();
-            }
-            else if (patchValue > 26)
-            {
-                Span<char> patchStr = stackalloc char[2];
-                patchStr[0] = 'z';
-                // backtick is ('a'-1)
-                patchStr[1] = (char)('`' + (patchValue - 26));
-                patch = new string(patchStr);
-            }
-            else if (patchValue > 0)
-            {
-                // backtick is ('a'-1)
-                patch = new string((char)('`' + patchValue), 1);
-            }
-
-            return $"{OpenSslDescriptionPrefix}{(ver >> 28) & 0xF:x}.{(byte)(ver >> 20):x}.{(byte)(ver >> 12):x}{patch}";
-        }
-#endif
-    }
-}
index 87e11a3..7664cac 100644 (file)
@@ -269,7 +269,6 @@ endif()
 add_subdirectory(System.Native)
 
 if (NOT CLR_CMAKE_PLATFORM_WASM)
-    add_subdirectory(System.Net.Http.Native)
     add_subdirectory(System.Net.Security.Native)
     add_subdirectory(System.Security.Cryptography.Native)
 endif()
diff --git a/src/libraries/Native/Unix/System.Net.Http.Native/CMakeLists.txt b/src/libraries/Native/Unix/System.Net.Http.Native/CMakeLists.txt
deleted file mode 100644 (file)
index 118491b..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-project(System.Net.Http.Native C)
-
-find_package(CURL)
-if(NOT CURL_FOUND)
-    message(FATAL_ERROR "!!! Cannot find libcurl and System.Net.Http.Native cannot build without it. Try installing libcurl4-openssl-dev (or the appropriate package for your platform) !!!")
-endif(NOT CURL_FOUND)
-
-if(CMAKE_STATIC_LIB_LINK)
-    find_library(CURL_STATIC_LIB NAMES libcurl.a)
-    if(NOT CURL_STATIC_LIB)
-        message(FATAL_ERROR "!!! Cannot find libcurl static lib and System.Net.Http.Native cannot build without it. Try installing libcurl4-openssl-dev (or the appropriate package for your platform) !!!")
-    endif(NOT CURL_STATIC_LIB)
-    set(CURL_LIBRARIES ${CURL_STATIC_LIB})
-    add_compile_options(-DCURL_STATICLIB)
-endif(CMAKE_STATIC_LIB_LINK)
-
-
-set(NATIVEHTTP_SOURCES
-    pal_curlinit.c
-    pal_easy.c
-    pal_multi.c
-    pal_slist.c
-    pal_versioninfo.c
-)
-
-include_directories(${CURL_INCLUDE_DIR})
-
-add_library(System.Net.Http.Native
-    SHARED
-    ${NATIVEHTTP_SOURCES}
-    ${VERSION_FILE_PATH}
-)
-
-add_library(System.Net.Http.Native-Static
-    STATIC
-    ${NATIVEHTTP_SOURCES}
-    ${VERSION_FILE_PATH}
-)
-
-# Disable the "lib" prefix and override default name
-set_target_properties(System.Net.Http.Native-Static PROPERTIES PREFIX "")
-set_target_properties(System.Net.Http.Native-Static PROPERTIES OUTPUT_NAME System.Net.Http.Native CLEAN_DIRECT_OUTPUT 1)
-
-target_link_libraries(System.Net.Http.Native
-  ${CURL_LIBRARIES}
-)
-
-install_library_and_symbols (System.Net.Http.Native)
-install (TARGETS System.Net.Http.Native-Static DESTINATION .)
diff --git a/src/libraries/Native/Unix/System.Net.Http.Native/pal_curlinit.c b/src/libraries/Native/Unix/System.Net.Http.Native/pal_curlinit.c
deleted file mode 100644 (file)
index d7e34df..0000000
+++ /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.
-// See the LICENSE file in the project root for more information.
-
-#include "pal_config.h"
-#include "pal_curlinit.h"
-
-#include <pthread.h>
-#include <stdbool.h>
-#include <curl/curl.h>
-
-int32_t HttpNative_EnsureCurlIsInitialized(void)
-{
-    static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
-    static bool initializationAttempted = false;
-    static int32_t errorCode = -1;
-
-    pthread_mutex_lock(&lock);
-    {
-        if (!initializationAttempted)
-        {
-            errorCode = (int32_t)(curl_global_init(CURL_GLOBAL_ALL));
-            initializationAttempted = true;
-        }
-    }
-    pthread_mutex_unlock(&lock);
-
-    return errorCode;
-}
diff --git a/src/libraries/Native/Unix/System.Net.Http.Native/pal_curlinit.h b/src/libraries/Native/Unix/System.Net.Http.Native/pal_curlinit.h
deleted file mode 100644 (file)
index fc6a00c..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-#pragma once
-
-#include "pal_types.h"
-#include "pal_compiler.h"
-
-/**
- * Initializes curl.
- *
- * Thread-safe and idempotent. Must be called before using any other curl function.
- * EnsureOpenSSLIsInitialized from System.Security.Cryptography.Native must already
- * have been called before calling this.
- *
- * Returns 0 on success and non-zero on failure.
- */
-DLLEXPORT int32_t HttpNative_EnsureCurlIsInitialized(void);
diff --git a/src/libraries/Native/Unix/System.Net.Http.Native/pal_easy.c b/src/libraries/Native/Unix/System.Net.Http.Native/pal_easy.c
deleted file mode 100644 (file)
index 7696127..0000000
+++ /dev/null
@@ -1,360 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-#include "pal_config.h"
-#include "pal_easy.h"
-
-#include <stdlib.h>
-#include <stdbool.h>
-#include <assert.h>
-
-c_static_assert(PAL_CURLOPT_INFILESIZE == CURLOPT_INFILESIZE);
-c_static_assert(PAL_CURLOPT_SSLVERSION == CURLOPT_SSLVERSION);
-c_static_assert(PAL_CURLOPT_VERBOSE == CURLOPT_VERBOSE);
-c_static_assert(PAL_CURLOPT_NOBODY == CURLOPT_NOBODY);
-c_static_assert(PAL_CURLOPT_UPLOAD == CURLOPT_UPLOAD);
-c_static_assert(PAL_CURLOPT_POST == CURLOPT_POST);
-c_static_assert(PAL_CURLOPT_FOLLOWLOCATION == CURLOPT_FOLLOWLOCATION);
-c_static_assert(PAL_CURLOPT_PROXYPORT == CURLOPT_PROXYPORT);
-c_static_assert(PAL_CURLOPT_POSTFIELDSIZE == CURLOPT_POSTFIELDSIZE);
-c_static_assert(PAL_CURLOPT_SSL_VERIFYPEER == CURLOPT_SSL_VERIFYPEER);
-c_static_assert(PAL_CURLOPT_MAXREDIRS == CURLOPT_MAXREDIRS);
-c_static_assert(PAL_CURLOPT_SSL_VERIFYHOST == CURLOPT_SSL_VERIFYHOST);
-c_static_assert(PAL_CURLOPT_HTTP_VERSION == CURLOPT_HTTP_VERSION);
-c_static_assert(PAL_CURLOPT_DNS_CACHE_TIMEOUT == CURLOPT_DNS_CACHE_TIMEOUT);
-c_static_assert(PAL_CURLOPT_NOSIGNAL == CURLOPT_NOSIGNAL);
-c_static_assert(PAL_CURLOPT_PROXYTYPE == CURLOPT_PROXYTYPE);
-c_static_assert(PAL_CURLOPT_HTTPAUTH == CURLOPT_HTTPAUTH);
-c_static_assert(PAL_CURLOPT_TCP_NODELAY == CURLOPT_TCP_NODELAY);
-c_static_assert(PAL_CURLOPT_TCP_KEEPALIVE == CURLOPT_TCP_KEEPALIVE);
-c_static_assert(PAL_CURLOPT_CONNECTTIMEOUT_MS == CURLOPT_CONNECTTIMEOUT_MS);
-c_static_assert(PAL_CURLOPT_ADDRESS_SCOPE == CURLOPT_ADDRESS_SCOPE);
-c_static_assert(PAL_CURLOPT_PROTOCOLS == CURLOPT_PROTOCOLS);
-c_static_assert(PAL_CURLOPT_REDIR_PROTOCOLS == CURLOPT_REDIR_PROTOCOLS);
-
-c_static_assert(PAL_CURLOPT_URL == CURLOPT_URL);
-c_static_assert(PAL_CURLOPT_PROXY == CURLOPT_PROXY);
-c_static_assert(PAL_CURLOPT_PROXYUSERPWD == CURLOPT_PROXYUSERPWD);
-c_static_assert(PAL_CURLOPT_COOKIE == CURLOPT_COOKIE);
-c_static_assert(PAL_CURLOPT_HTTPHEADER == CURLOPT_HTTPHEADER);
-c_static_assert(PAL_CURLOPT_CUSTOMREQUEST == CURLOPT_CUSTOMREQUEST);
-c_static_assert(PAL_CURLOPT_ACCEPT_ENCODING == CURLOPT_ACCEPT_ENCODING);
-c_static_assert(PAL_CURLOPT_PRIVATE == CURLOPT_PRIVATE);
-c_static_assert(PAL_CURLOPT_COPYPOSTFIELDS == CURLOPT_COPYPOSTFIELDS);
-c_static_assert(PAL_CURLOPT_USERNAME == CURLOPT_USERNAME);
-c_static_assert(PAL_CURLOPT_PASSWORD == CURLOPT_PASSWORD);
-c_static_assert(PAL_CURLOPT_CAPATH == CURLOPT_CAPATH);
-#ifdef CURLOPT_PROXY_CAPATH
-c_static_assert(PAL_CURLOPT_PROXY_CAPATH == CURLOPT_PROXY_CAPATH);
-#endif
-c_static_assert(PAL_CURLOPT_CAINFO == CURLOPT_CAINFO);
-#ifdef CURLOPT_PROXY_CAINFO
-c_static_assert(PAL_CURLOPT_PROXY_CAINFO == CURLOPT_PROXY_CAINFO);
-#endif
-
-c_static_assert(PAL_CURLOPT_INFILESIZE_LARGE == CURLOPT_INFILESIZE_LARGE);
-c_static_assert(PAL_CURLOPT_POSTFIELDSIZE_LARGE == CURLOPT_POSTFIELDSIZE_LARGE);
-
-c_static_assert(PAL_CURLE_OK == CURLE_OK);
-c_static_assert(PAL_CURLE_UNSUPPORTED_PROTOCOL == CURLE_UNSUPPORTED_PROTOCOL);
-c_static_assert(PAL_CURLE_FAILED_INIT == CURLE_FAILED_INIT);
-c_static_assert(PAL_CURLE_NOT_BUILT_IN == CURLE_NOT_BUILT_IN);
-c_static_assert(PAL_CURLE_COULDNT_RESOLVE_HOST == CURLE_COULDNT_RESOLVE_HOST);
-c_static_assert(PAL_CURLE_OUT_OF_MEMORY == CURLE_OUT_OF_MEMORY);
-c_static_assert(PAL_CURLE_OPERATION_TIMEDOUT == CURLE_OPERATION_TIMEDOUT);
-c_static_assert(PAL_CURLE_ABORTED_BY_CALLBACK == CURLE_ABORTED_BY_CALLBACK);
-c_static_assert(PAL_CURLE_UNKNOWN_OPTION == CURLE_UNKNOWN_OPTION);
-c_static_assert(PAL_CURLE_RECV_ERROR == CURLE_RECV_ERROR);
-c_static_assert(PAL_CURLE_SEND_FAIL_REWIND == CURLE_SEND_FAIL_REWIND);
-
-c_static_assert(PAL_CURL_HTTP_VERSION_NONE == CURL_HTTP_VERSION_NONE);
-c_static_assert(PAL_CURL_HTTP_VERSION_1_0 == CURL_HTTP_VERSION_1_0);
-c_static_assert(PAL_CURL_HTTP_VERSION_1_1 == CURL_HTTP_VERSION_1_1);
-#if HAVE_CURL_HTTP_VERSION_2TLS
-c_static_assert(PAL_CURL_HTTP_VERSION_2TLS == CURL_HTTP_VERSION_2TLS);
-#endif
-
-c_static_assert(PAL_CURL_SSLVERSION_SSLv2 == CURL_SSLVERSION_SSLv2);
-c_static_assert(PAL_CURL_SSLVERSION_SSLv3 == CURL_SSLVERSION_SSLv3);
-c_static_assert(PAL_CURL_SSLVERSION_TLSv1 == CURL_SSLVERSION_TLSv1);
-#if HAVE_CURL_SSLVERSION_TLSv1_012
-c_static_assert(PAL_CURL_SSLVERSION_TLSv1_0 == CURL_SSLVERSION_TLSv1_0);
-c_static_assert(PAL_CURL_SSLVERSION_TLSv1_1 == CURL_SSLVERSION_TLSv1_1);
-c_static_assert(PAL_CURL_SSLVERSION_TLSv1_2 == CURL_SSLVERSION_TLSv1_2);
-#endif
-
-c_static_assert(PAL_CURLINFO_EFFECTIVE_URL == CURLINFO_EFFECTIVE_URL);
-c_static_assert(PAL_CURLINFO_PRIVATE == CURLINFO_PRIVATE);
-c_static_assert(PAL_CURLINFO_HTTPAUTH_AVAIL == CURLINFO_HTTPAUTH_AVAIL);
-
-c_static_assert(PAL_CURLAUTH_None == CURLAUTH_NONE);
-c_static_assert(PAL_CURLAUTH_Basic == CURLAUTH_BASIC);
-c_static_assert(PAL_CURLAUTH_Digest == CURLAUTH_DIGEST);
-c_static_assert(PAL_CURLAUTH_Negotiate == CURLAUTH_GSSNEGOTIATE);
-c_static_assert(PAL_CURLAUTH_NTLM == CURLAUTH_NTLM);
-
-c_static_assert(PAL_CURLPROXY_HTTP == CURLPROXY_HTTP);
-
-c_static_assert(PAL_CURLPROTO_HTTP == CURLPROTO_HTTP);
-c_static_assert(PAL_CURLPROTO_HTTPS == CURLPROTO_HTTPS);
-
-c_static_assert(PAL_CURL_SEEKFUNC_OK == CURL_SEEKFUNC_OK);
-c_static_assert(PAL_CURL_SEEKFUNC_FAIL == CURL_SEEKFUNC_FAIL);
-c_static_assert(PAL_CURL_SEEKFUNC_CANTSEEK == CURL_SEEKFUNC_CANTSEEK);
-
-c_static_assert(PAL_CURL_READFUNC_ABORT == CURL_READFUNC_ABORT);
-c_static_assert(PAL_CURL_READFUNC_PAUSE == CURL_READFUNC_PAUSE);
-c_static_assert(PAL_CURL_WRITEFUNC_PAUSE == CURL_WRITEFUNC_PAUSE);
-
-c_static_assert(PAL_CURLINFO_TEXT == CURLINFO_TEXT);
-c_static_assert(PAL_CURLINFO_HEADER_IN == CURLINFO_HEADER_IN);
-c_static_assert(PAL_CURLINFO_HEADER_OUT == CURLINFO_HEADER_OUT);
-c_static_assert(PAL_CURLINFO_DATA_IN == CURLINFO_DATA_IN);
-c_static_assert(PAL_CURLINFO_DATA_OUT == CURLINFO_DATA_OUT);
-c_static_assert(PAL_CURLINFO_SSL_DATA_IN == CURLINFO_SSL_DATA_IN);
-c_static_assert(PAL_CURLINFO_SSL_DATA_OUT == CURLINFO_SSL_DATA_OUT);
-
-c_static_assert(PAL_CURL_MAX_HTTP_HEADER == CURL_MAX_HTTP_HEADER);
-
-CURL* HttpNative_EasyCreate()
-{
-    return curl_easy_init();
-}
-
-void HttpNative_EasyDestroy(CURL* handle)
-{
-    curl_easy_cleanup(handle);
-}
-
-inline static CURLoption ConvertOption(PAL_CURLoption option)
-{
-    return (CURLoption)option;
-}
-
-int32_t HttpNative_EasySetOptionString(CURL* handle, PAL_CURLoption option, const char* value)
-{
-    return (int32_t)(curl_easy_setopt(handle, ConvertOption(option), value));
-}
-
-int32_t HttpNative_EasySetOptionLong(CURL* handle, PAL_CURLoption option, int64_t value)
-{
-    CURLoption curlOpt = ConvertOption(option);
-
-    // The HttpNative_EasySetOptionLong entrypoint is used for both curl_easy_setopt(..., long) and
-    // curl_easy_setopt(..., curl_off_t).  As they'll likely be different sizes on 32-bit platforms, 
-    // we map anything >= CurlOptionOffTBase to use curl_off_t.
-    if (option >= CurlOptionOffTBase)
-    {
-        return (int32_t)(curl_easy_setopt(handle, curlOpt, (curl_off_t)value));
-    }
-    else
-    {
-        return (int32_t)(curl_easy_setopt(handle, curlOpt, (long)value));
-    }
-}
-
-int32_t HttpNative_EasySetOptionPointer(CURL* handle, PAL_CURLoption option, void* value)
-{
-    return (int32_t)(curl_easy_setopt(handle, ConvertOption(option), value));
-}
-
-const char* HttpNative_EasyGetErrorString(PAL_CURLcode code)
-{
-    return curl_easy_strerror((CURLcode)code);
-}
-
-inline static CURLINFO ConvertInfo(PAL_CURLINFO info)
-{
-    return (CURLINFO)info;
-}
-
-int32_t HttpNative_EasyGetInfoPointer(CURL* handle, PAL_CURLINFO info, void** value)
-{
-    return (int32_t)(curl_easy_getinfo(handle, ConvertInfo(info), value));
-}
-
-int32_t HttpNative_EasyGetInfoLong(CURL* handle, PAL_CURLINFO info, int64_t* value)
-{
-    return (int32_t)(curl_easy_getinfo(handle, ConvertInfo(info), value));
-}
-
-int32_t HttpNative_EasyPerform(CURL* handle)
-{
-    return (int32_t)(curl_easy_perform(handle));
-}
-
-int32_t HttpNative_EasyUnpause(CURL* handle)
-{
-    return (int32_t)(curl_easy_pause(handle, CURLPAUSE_CONT));
-}
-
-struct CallbackHandle
-{
-    SeekCallback seekCallback;
-    void* seekUserPointer;
-
-    ReadWriteCallback writeCallback;
-    void* writeUserPointer;
-
-    ReadWriteCallback readCallback;
-    void* readUserPointer;
-
-    ReadWriteCallback headerCallback;
-    void* headerUserPointer;
-
-    SslCtxCallback sslCtxCallback;
-    void* sslUserPointer;
-
-    DebugCallback debugCallback;
-    void* debugUserPointer;
-};
-
-static inline bool EnsureCallbackHandle(CallbackHandle** callbackHandle)
-{
-    assert(callbackHandle != NULL);
-
-    if (*callbackHandle == NULL)
-    {
-        *callbackHandle = (CallbackHandle*)malloc(sizeof(CallbackHandle));
-    }
-
-    return *callbackHandle != NULL;
-}
-
-static int seek_callback(void* userp, curl_off_t offset, int origin)
-{
-    CallbackHandle* handle = (CallbackHandle*)userp;
-    return handle->seekCallback(handle->seekUserPointer, offset, origin);
-}
-
-void
-HttpNative_RegisterSeekCallback(CURL* curl, SeekCallback callback, void* userPointer, CallbackHandle** callbackHandle)
-{
-    if (EnsureCallbackHandle(callbackHandle))
-    {
-        CallbackHandle* handle = *callbackHandle;
-        handle->seekCallback = callback;
-        handle->seekUserPointer = userPointer;
-
-        curl_easy_setopt(curl, CURLOPT_SEEKDATA, handle);
-        curl_easy_setopt(curl, CURLOPT_SEEKFUNCTION, &seek_callback);
-    }
-}
-
-static size_t write_callback(char* buffer, size_t size, size_t nitems, void* instream)
-{
-    CallbackHandle* handle = (CallbackHandle*)instream;
-    return (size_t)(handle->writeCallback((uint8_t*)buffer, size, nitems, handle->writeUserPointer));
-}
-
-static size_t read_callback(char* buffer, size_t size, size_t nitems, void* instream)
-{
-    CallbackHandle* handle = (CallbackHandle*)instream;
-    return (size_t)(handle->readCallback((uint8_t*)buffer, size, nitems, handle->readUserPointer));
-}
-
-static size_t header_callback(char* buffer, size_t size, size_t nitems, void* instream)
-{
-    CallbackHandle* handle = (CallbackHandle*)instream;
-    return (size_t)(handle->headerCallback((uint8_t*)buffer, size, nitems, handle->headerUserPointer));
-}
-
-void HttpNative_RegisterReadWriteCallback(CURL* curl,
-                                                     ReadWriteFunction functionType,
-                                                     ReadWriteCallback callback,
-                                                     void* userPointer,
-                                                     CallbackHandle** callbackHandle)
-{
-    if (EnsureCallbackHandle(callbackHandle))
-    {
-        CallbackHandle* handle = *callbackHandle;
-
-        switch (functionType)
-        {
-        case Write:
-            handle->writeCallback = callback;
-            handle->writeUserPointer = userPointer;
-            curl_easy_setopt(curl, CURLOPT_WRITEDATA, handle);
-            curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &write_callback);
-            break;
-
-        case Read:
-            handle->readCallback = callback;
-            handle->readUserPointer = userPointer;
-            curl_easy_setopt(curl, CURLOPT_READDATA, handle);
-            curl_easy_setopt(curl, CURLOPT_READFUNCTION, &read_callback);
-            break;
-
-        case Header:
-            handle->headerCallback = callback;
-            handle->headerUserPointer = userPointer;
-            curl_easy_setopt(curl, CURLOPT_HEADERDATA, handle);
-            curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, &header_callback);
-            break;
-        }
-    }
-}
-
-static CURLcode ssl_ctx_callback(CURL* curl, void* sslCtx, void* userPointer)
-{
-    CallbackHandle* handle = (CallbackHandle*)userPointer;
-
-    int32_t result = handle->sslCtxCallback(curl, sslCtx, handle->sslUserPointer);
-    return (CURLcode)result;
-}
-
-int32_t HttpNative_RegisterSslCtxCallback(CURL* curl,
-                                                     SslCtxCallback callback,
-                                                     void* userPointer,
-                                                     CallbackHandle** callbackHandle)
-{
-    if (!EnsureCallbackHandle(callbackHandle))
-    {
-        return CURLE_OUT_OF_MEMORY;
-    }
-
-    CallbackHandle* handle = *callbackHandle;
-    handle->sslCtxCallback = callback;
-    handle->sslUserPointer = userPointer;
-
-    curl_easy_setopt(curl, CURLOPT_SSL_CTX_DATA, handle);
-    return (int32_t)(curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, &ssl_ctx_callback));
-}
-
-static int debug_callback(CURL* curl, curl_infotype type, char* data, size_t size, void* userPointer)
-{
-    assert(userPointer != NULL);
-    CallbackHandle* handle = (CallbackHandle*)userPointer;
-    handle->debugCallback(curl, (PAL_CurlInfoType)type, data, size, handle->debugUserPointer);
-    return 0;
-}
-
-int32_t HttpNative_RegisterDebugCallback(CURL* curl, 
-                                                    DebugCallback callback, 
-                                                    void* userPointer, 
-                                                    CallbackHandle** callbackHandle)
-{
-    if (!EnsureCallbackHandle(callbackHandle))
-    {
-        return CURLE_OUT_OF_MEMORY;
-    }
-
-    CallbackHandle* handle = *callbackHandle;
-    handle->debugCallback = callback;
-    handle->debugUserPointer = userPointer;
-
-    CURLcode rv = curl_easy_setopt(curl, CURLOPT_DEBUGDATA, handle);
-    return rv == CURLE_OK ?
-        (int32_t)(curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, &debug_callback)) :
-        (int32_t)rv;
-}
-
-void HttpNative_FreeCallbackHandle(CallbackHandle* callbackHandle)
-{
-    assert(callbackHandle != NULL);
-    if (callbackHandle != NULL)
-    {
-        free(callbackHandle);
-    }
-}
diff --git a/src/libraries/Native/Unix/System.Net.Http.Native/pal_easy.h b/src/libraries/Native/Unix/System.Net.Http.Native/pal_easy.h
deleted file mode 100644 (file)
index b4ff2ab..0000000
+++ /dev/null
@@ -1,278 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-#pragma once
-
-#include "pal_types.h"
-#include "pal_compiler.h"
-
-#include <curl/curl.h>
-
-enum
-{
-    CurlOptionLongBase = 0,
-    CurlOptionObjectPointBase = 10000,
-    CurlOptionOffTBase = 30000,
-};
-
-typedef enum
-{
-    PAL_CURLOPT_INFILESIZE = CurlOptionLongBase + 14,
-    PAL_CURLOPT_SSLVERSION = CurlOptionLongBase + 32,
-    PAL_CURLOPT_VERBOSE = CurlOptionLongBase + 41,
-    PAL_CURLOPT_NOBODY = CurlOptionLongBase + 44,
-    PAL_CURLOPT_UPLOAD = CurlOptionLongBase + 46,
-    PAL_CURLOPT_POST = CurlOptionLongBase + 47,
-    PAL_CURLOPT_FOLLOWLOCATION = CurlOptionLongBase + 52,
-    PAL_CURLOPT_PROXYPORT = CurlOptionLongBase + 59,
-    PAL_CURLOPT_POSTFIELDSIZE = CurlOptionLongBase + 60,
-    PAL_CURLOPT_SSL_VERIFYPEER = CurlOptionLongBase + 64,
-    PAL_CURLOPT_MAXREDIRS = CurlOptionLongBase + 68,
-    PAL_CURLOPT_SSL_VERIFYHOST = CurlOptionLongBase + 81,
-    PAL_CURLOPT_HTTP_VERSION = CurlOptionLongBase + 84,
-    PAL_CURLOPT_DNS_CACHE_TIMEOUT = CurlOptionLongBase + 92,
-    PAL_CURLOPT_NOSIGNAL = CurlOptionLongBase + 99,
-    PAL_CURLOPT_PROXYTYPE = CurlOptionLongBase + 101,
-    PAL_CURLOPT_HTTPAUTH = CurlOptionLongBase + 107,
-    PAL_CURLOPT_TCP_NODELAY = CurlOptionLongBase + 121,
-    PAL_CURLOPT_TCP_KEEPALIVE = CurlOptionLongBase + 213,
-    PAL_CURLOPT_CONNECTTIMEOUT_MS = CurlOptionLongBase + 156,
-    PAL_CURLOPT_ADDRESS_SCOPE = CurlOptionLongBase + 171,
-    PAL_CURLOPT_PROTOCOLS = CurlOptionLongBase + 181,
-    PAL_CURLOPT_REDIR_PROTOCOLS = CurlOptionLongBase + 182,
-
-    PAL_CURLOPT_URL = CurlOptionObjectPointBase + 2,
-    PAL_CURLOPT_PROXY = CurlOptionObjectPointBase + 4,
-    PAL_CURLOPT_PROXYUSERPWD = CurlOptionObjectPointBase + 6,
-    PAL_CURLOPT_COOKIE = CurlOptionObjectPointBase + 22,
-    PAL_CURLOPT_HTTPHEADER = CurlOptionObjectPointBase + 23,
-    PAL_CURLOPT_CUSTOMREQUEST = CurlOptionObjectPointBase + 36,
-    PAL_CURLOPT_ACCEPT_ENCODING = CurlOptionObjectPointBase + 102,
-    PAL_CURLOPT_PRIVATE = CurlOptionObjectPointBase + 103,
-    PAL_CURLOPT_COPYPOSTFIELDS = CurlOptionObjectPointBase + 165,
-    PAL_CURLOPT_USERNAME = CurlOptionObjectPointBase + 173,
-    PAL_CURLOPT_PASSWORD = CurlOptionObjectPointBase + 174,
-    PAL_CURLOPT_CAPATH = CurlOptionObjectPointBase + 97,
-    PAL_CURLOPT_PROXY_CAPATH = CurlOptionObjectPointBase + 247,
-    PAL_CURLOPT_CAINFO = CurlOptionObjectPointBase + 65,
-    PAL_CURLOPT_PROXY_CAINFO = CurlOptionObjectPointBase + 246,
-
-    PAL_CURLOPT_INFILESIZE_LARGE = CurlOptionOffTBase + 115,
-    PAL_CURLOPT_POSTFIELDSIZE_LARGE = CurlOptionOffTBase + 120,
-} PAL_CURLoption;
-
-typedef enum
-{
-    Write = 0,
-    Read = 1,
-    Header = 2,
-} ReadWriteFunction;
-
-typedef enum
-{
-    PAL_CURLE_OK = 0,
-    PAL_CURLE_UNSUPPORTED_PROTOCOL = 1,
-    PAL_CURLE_FAILED_INIT = 2,
-    PAL_CURLE_NOT_BUILT_IN = 4,
-    PAL_CURLE_COULDNT_RESOLVE_HOST = 6,
-    PAL_CURLE_OUT_OF_MEMORY = 27,
-    PAL_CURLE_OPERATION_TIMEDOUT = 28,
-    PAL_CURLE_ABORTED_BY_CALLBACK = 42,
-    PAL_CURLE_UNKNOWN_OPTION = 48,
-    PAL_CURLE_RECV_ERROR = 56,
-    PAL_CURLE_SEND_FAIL_REWIND = 65,
-} PAL_CURLcode;
-
-enum
-{
-    CurlInfoStringBase = 0x100000,
-    CurlInfoLongBase = 0x200000,
-};
-
-typedef enum
-{
-    PAL_CURL_HTTP_VERSION_NONE = 0,
-    PAL_CURL_HTTP_VERSION_1_0 = 1,
-    PAL_CURL_HTTP_VERSION_1_1 = 2,
-    PAL_CURL_HTTP_VERSION_2TLS = 4
-} PAL_CURL_HTTP_VERSION;
-
-typedef enum
-{
-    PAL_CURL_SSLVERSION_TLSv1 = 1,
-    PAL_CURL_SSLVERSION_SSLv2 = 2,
-    PAL_CURL_SSLVERSION_SSLv3 = 3,
-    PAL_CURL_SSLVERSION_TLSv1_0 = 4,
-    PAL_CURL_SSLVERSION_TLSv1_1 = 5,
-    PAL_CURL_SSLVERSION_TLSv1_2 = 6,
-} PAL_CURL_SSLVERSION;
-
-typedef enum
-{
-    PAL_CURLINFO_EFFECTIVE_URL = CurlInfoStringBase + 1,
-    PAL_CURLINFO_PRIVATE = CurlInfoStringBase + 21,
-    PAL_CURLINFO_HTTPAUTH_AVAIL = CurlInfoLongBase + 23,
-} PAL_CURLINFO;
-
-typedef enum
-{
-    PAL_CURLAUTH_None = 0,
-    PAL_CURLAUTH_Basic = 1 << 0,
-    PAL_CURLAUTH_Digest = 1 << 1,
-    PAL_CURLAUTH_Negotiate = 1 << 2,
-    PAL_CURLAUTH_NTLM = 1 << 3,
-} PAL_CURLAUTH;
-
-typedef enum
-{
-    PAL_CURLPROXY_HTTP = 0,
-} PAL_CURLPROXYTYPE;
-
-typedef enum
-{
-    PAL_CURLPROTO_HTTP = (1 << 0),
-    PAL_CURLPROTO_HTTPS = (1 << 1),
-} PAL_CURLPROTO;
-
-typedef enum
-{
-    PAL_CURL_SEEKFUNC_OK = 0,
-    PAL_CURL_SEEKFUNC_FAIL = 1,
-    PAL_CURL_SEEKFUNC_CANTSEEK = 2,
-} PAL_CurlSeekResult;
-
-typedef enum
-{
-    PAL_CURLINFO_TEXT = 0,
-    PAL_CURLINFO_HEADER_IN = 1,
-    PAL_CURLINFO_HEADER_OUT = 2,
-    PAL_CURLINFO_DATA_IN = 3,
-    PAL_CURLINFO_DATA_OUT = 4,
-    PAL_CURLINFO_SSL_DATA_IN = 5,
-    PAL_CURLINFO_SSL_DATA_OUT = 6,
-} PAL_CurlInfoType;
-
-enum {
-    PAL_CURL_READFUNC_ABORT = 0x10000000,
-    PAL_CURL_READFUNC_PAUSE = 0x10000001,
-    PAL_CURL_WRITEFUNC_PAUSE = 0x10000001,
-    PAL_CURL_MAX_HTTP_HEADER = 100 * 1024
-};
-
-/*
-Creates a new CURL instance.
-
-Returns the new CURL instance or nullptr if something went wrong.
-*/
-DLLEXPORT CURL* HttpNative_EasyCreate(void);
-
-/*
-Cleans up and deletes a CURL instance.
-
-No-op if handle is null.
-The given CURL pointer is invalid after this call.
-*/
-DLLEXPORT void HttpNative_EasyDestroy(CURL* handle);
-
-/*
-Shims the curl_easy_setopt function, which takes a variable number of
-arguments, but must be a long, a function pointer, an object pointer or a curl_off_t,
-depending on what option is supplied.
-*/
-DLLEXPORT int32_t HttpNative_EasySetOptionString(CURL* handle, PAL_CURLoption option, const char* value);
-DLLEXPORT int32_t HttpNative_EasySetOptionLong(CURL* handle, PAL_CURLoption option, int64_t value);
-DLLEXPORT int32_t HttpNative_EasySetOptionPointer(CURL* handle, PAL_CURLoption option, void* value);
-
-/*
-Returns a string describing the CURLcode error code.
-*/
-DLLEXPORT const char* HttpNative_EasyGetErrorString(PAL_CURLcode code);
-
-/*
-Shims the curl_easy_setopt function, which takes a variable number of
-arguments.
-*/
-DLLEXPORT int32_t HttpNative_EasyGetInfoPointer(CURL* handle, PAL_CURLINFO info, void** value);
-DLLEXPORT int32_t HttpNative_EasyGetInfoLong(CURL* handle, PAL_CURLINFO info, int64_t* value);
-
-/*
-Shims the curl_easy_perform function.
-
-Returns CURLE_OK (0) if everything was ok, non-zero means an error occurred.
-*/
-DLLEXPORT int32_t HttpNative_EasyPerform(CURL* handle);
-
-/*
-Unpauses the CURL request.
-
-Returns CURLE_OK (0) if everything was ok, non-zero means an error occurred.
-*/
-DLLEXPORT int32_t HttpNative_EasyUnpause(CURL* handle);
-
-// the function pointer definition for the callback used in RegisterSeekCallback
-typedef int32_t (*SeekCallback)(void* userPointer, int64_t offset, int32_t origin);
-
-// the function pointer definition for the callback used in RegisterReadWriteCallback
-typedef uint64_t (*ReadWriteCallback)(uint8_t* buffer, uint64_t bufferSize, uint64_t nitems, void* userPointer);
-
-// the function pointer definition for the callback used in RegisterSslCtxCallback
-typedef int32_t (*SslCtxCallback)(CURL* curl, void* sslCtx, void* userPointer);
-
-// the function pointer definition for the callback used for debugging callbacks
-typedef void(*DebugCallback)(CURL* curl, PAL_CurlInfoType type, char* data, uint64_t size, void* userPointer);
-
-/*
-The object that is returned from RegisterXXXCallback functions.
-This holds the data necessary to know what managed callback to invoke and with what args.
-*/
-typedef struct CallbackHandle CallbackHandle;
-
-/*
-Registers a callback in libcurl for seeking in an input stream.
-
-This function gets called by libcurl to seek to a certain position in the input stream
-and can be used to fast forward a file in a resumed upload.
-*/
-DLLEXPORT void
-HttpNative_RegisterSeekCallback(CURL* curl, SeekCallback callback, void* userPointer, CallbackHandle** callbackHandle);
-
-/*
-Registers a callback in libcurl for reading/writing input/output streams.
-*/
-DLLEXPORT void HttpNative_RegisterReadWriteCallback(CURL* curl,
-                                                    ReadWriteFunction functionType,
-                                                    ReadWriteCallback callback,
-                                                    void* userPointer,
-                                                    CallbackHandle** callbackHandle);
-
-/*
-Registers a callback in libcurl for initializing SSL connections.
-
-This callback function gets called by libcurl just before the initialization of an SSL connection
-after having processed all other SSL related options to give a last chance to an application
-to modify the behaviour of the SSL initialization.
-
-Returns a CURLcode that describes whether registering the callback was successful or not.
-*/
-DLLEXPORT int32_t HttpNative_RegisterSslCtxCallback(CURL* curl,
-                                                    SslCtxCallback callback,
-                                                    void* userPointer,
-                                                    CallbackHandle** callbackHandle);
-
-/*
-Registers a callback in libcurl for outputting debug information.
-
-This callback function gets called by libcurl each time it has debug information to report.
-
-Returns a CURLcode that describes whether registering the callback was successful or not.
-*/
-DLLEXPORT int32_t HttpNative_RegisterDebugCallback(CURL* curl,
-                                                   DebugCallback callback,
-                                                   void* userPointer,
-                                                   CallbackHandle** callbackHandle);
-
-/*
-Frees the CallbackHandle created by a RegisterXXXCallback function.
-*/
-DLLEXPORT void HttpNative_FreeCallbackHandle(CallbackHandle* callbackHandle);
diff --git a/src/libraries/Native/Unix/System.Net.Http.Native/pal_multi.c b/src/libraries/Native/Unix/System.Net.Http.Native/pal_multi.c
deleted file mode 100644 (file)
index 98c5f9e..0000000
+++ /dev/null
@@ -1,145 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-#include "pal_config.h"
-#include "pal_multi.h"
-#include "pal_utilities.h"
-
-#include <assert.h>
-#include <poll.h>
-
-c_static_assert(PAL_CURLM_CALL_MULTI_PERFORM == CURLM_CALL_MULTI_PERFORM);
-c_static_assert(PAL_CURLM_OK == CURLM_OK);
-c_static_assert(PAL_CURLM_BAD_HANDLE == CURLM_BAD_HANDLE);
-c_static_assert(PAL_CURLM_BAD_EASY_HANDLE == CURLM_BAD_EASY_HANDLE);
-c_static_assert(PAL_CURLM_OUT_OF_MEMORY == CURLM_OUT_OF_MEMORY);
-c_static_assert(PAL_CURLM_INTERNAL_ERROR == CURLM_INTERNAL_ERROR);
-c_static_assert(PAL_CURLM_BAD_SOCKET == CURLM_BAD_SOCKET);
-c_static_assert(PAL_CURLM_UNKNOWN_OPTION == CURLM_UNKNOWN_OPTION);
-#if HAVE_CURLM_ADDED_ALREADY
-c_static_assert(PAL_CURLM_ADDED_ALREADY == CURLM_ADDED_ALREADY);
-#endif
-c_static_assert(PAL_CURLMOPT_PIPELINING == CURLMOPT_PIPELINING);
-#ifdef CURLMOPT_MAX_HOST_CONNECTIONS
-c_static_assert(PAL_CURLMOPT_MAX_HOST_CONNECTIONS == CURLMOPT_MAX_HOST_CONNECTIONS);
-#endif
-#if HAVE_CURLPIPE_MULTIPLEX
-c_static_assert(PAL_CURLPIPE_MULTIPLEX == CURLPIPE_MULTIPLEX);
-#endif
-
-c_static_assert(PAL_CURLMSG_DONE == CURLMSG_DONE);
-
-CURLM* HttpNative_MultiCreate()
-{
-    return curl_multi_init();
-}
-
-int32_t HttpNative_MultiDestroy(CURLM* multiHandle)
-{
-    return curl_multi_cleanup(multiHandle);
-}
-
-int32_t HttpNative_MultiAddHandle(CURLM* multiHandle, CURL* easyHandle)
-{
-    return curl_multi_add_handle(multiHandle, easyHandle);
-}
-
-int32_t HttpNative_MultiRemoveHandle(CURLM* multiHandle, CURL* easyHandle)
-{
-    return curl_multi_remove_handle(multiHandle, easyHandle);
-}
-
-int32_t HttpNative_MultiWait(CURLM* multiHandle,
-                                        intptr_t extraFileDescriptor,
-                                        int32_t* isExtraFileDescriptorActive,
-                                        int32_t* isTimeout)
-{
-    assert(isExtraFileDescriptorActive != NULL);
-    assert(isTimeout != NULL);
-
-    struct curl_waitfd extraFds = {.fd = ToFileDescriptor(extraFileDescriptor), .events = CURL_WAIT_POLLIN, .revents = 0};
-
-    // Even with our cancellation mechanism, we specify a timeout so that
-    // just in case something goes wrong we can recover gracefully.  This timeout is relatively long.
-    // Note, though, that libcurl has its own internal timeout, which can be requested separately
-    // via curl_multi_timeout, but which is used implicitly by curl_multi_wait if it's shorter
-    // than the value we provide.
-    const int FailsafeTimeoutMilliseconds = 1000;
-
-    int numFds;
-    CURLMcode result = curl_multi_wait(multiHandle, &extraFds, 1, FailsafeTimeoutMilliseconds, &numFds);
-
-    if (numFds == 0)
-    {
-        *isTimeout = true;
-        *isExtraFileDescriptorActive = false;
-    }
-    else
-    {
-        *isTimeout = false;
-
-        //
-        // Prior to libcurl version 7.32.0, the revents field was not returned properly for "extra" file descriptors
-        // passed to curl_multi_wait.  See https://github.com/dotnet/corefx/issues/9751.  So if we have a libcurl
-        // prior to that version, we need to do our own poll to get the status of the extra file descriptor.
-        //
-        if (curl_version_info(CURLVERSION_NOW)->version_num >= 0x072000)
-        {
-            *isExtraFileDescriptorActive = (extraFds.revents & CURL_WAIT_POLLIN) != 0;
-        }
-        else
-        {
-            struct pollfd pfd = { .fd = ToFileDescriptor(extraFileDescriptor),.events = POLLIN,.revents = 0 };
-            poll(&pfd, 1, 0);
-
-            //
-            // We ignore any failure in poll(), to preserve the result from curl_multi_wait.  If poll() fails, it should
-            // leave revents cleared.
-            //
-            *isExtraFileDescriptorActive = (pfd.revents & POLLIN) != 0;
-        }
-    }
-
-    return result;
-}
-
-int32_t HttpNative_MultiPerform(CURLM* multiHandle)
-{
-    int running_handles;
-    return curl_multi_perform(multiHandle, &running_handles);
-}
-
-int32_t HttpNative_MultiInfoRead(CURLM* multiHandle, int32_t* message, CURL** easyHandle, int32_t* result)
-{
-    assert(message != NULL);
-    assert(easyHandle != NULL);
-    assert(result != NULL);
-
-    int msgs_in_queue;
-    CURLMsg* curlMessage = curl_multi_info_read(multiHandle, &msgs_in_queue);
-    if (curlMessage == NULL)
-    {
-        *message = 0;
-        *easyHandle = NULL;
-        *result = 0;
-
-        return 0;
-    }
-
-    *message = (int32_t)(curlMessage->msg);
-    *easyHandle = curlMessage->easy_handle;
-    *result = (int32_t)(curlMessage->data.result);
-
-    return 1;
-}
-
-const char* HttpNative_MultiGetErrorString(PAL_CURLMcode code)
-{
-    return curl_multi_strerror((CURLMcode)code);
-}
-
-int32_t HttpNative_MultiSetOptionLong(CURLM* handle, PAL_CURLMoption option, int64_t value)
-{
-    return curl_multi_setopt(handle, (CURLMoption)option, value);
-}
diff --git a/src/libraries/Native/Unix/System.Net.Http.Native/pal_multi.h b/src/libraries/Native/Unix/System.Net.Http.Native/pal_multi.h
deleted file mode 100644 (file)
index 7e541af..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-#pragma once
-
-#include "pal_types.h"
-#include "pal_compiler.h"
-
-#include <curl/curl.h>
-
-typedef enum
-{
-    PAL_CURLM_CALL_MULTI_PERFORM = -1,
-    PAL_CURLM_OK = 0,
-    PAL_CURLM_BAD_HANDLE = 1,
-    PAL_CURLM_BAD_EASY_HANDLE = 2,
-    PAL_CURLM_OUT_OF_MEMORY = 3,
-    PAL_CURLM_INTERNAL_ERROR = 4,
-    PAL_CURLM_BAD_SOCKET = 5,
-    PAL_CURLM_UNKNOWN_OPTION = 6,
-    PAL_CURLM_ADDED_ALREADY = 7, // Added in libcurl 7.32.1
-} PAL_CURLMcode;
-
-typedef enum
-{
-    PAL_CURLMOPT_PIPELINING = 3,
-    PAL_CURLMOPT_MAX_HOST_CONNECTIONS = 7,
-} PAL_CURLMoption;
-
-typedef enum
-{
-    PAL_CURLPIPE_MULTIPLEX = 2,
-} PAL_CurlPipe;
-
-typedef enum
-{
-    PAL_CURLMSG_DONE = 1,
-} PAL_CURLMSG;
-
-/*
-Creates a new CURLM instance.
-
-Returns the new CURLM instance or nullptr if something went wrong.
-*/
-DLLEXPORT CURLM* HttpNative_MultiCreate(void);
-
-/*
-Cleans up and removes a whole multi stack.
-
-Returns CURLM_OK on success, otherwise an error code.
-*/
-DLLEXPORT int32_t HttpNative_MultiDestroy(CURLM* multiHandle);
-
-/*
-Shims the curl_multi_add_handle function.
-
-Returns CURLM_OK on success, otherwise an error code.
-*/
-DLLEXPORT int32_t HttpNative_MultiAddHandle(CURLM* multiHandle, CURL* easyHandle);
-
-/*
-Shims the curl_multi_remove_handle function.
-
-Returns CURLM_OK on success, otherwise an error code.
-*/
-DLLEXPORT int32_t HttpNative_MultiRemoveHandle(CURLM* multiHandle, CURL* easyHandle);
-
-/*
-Shims the curl_multi_wait function.
-
-Returns CURLM_OK on success, otherwise an error code.
-
-isExtraFileDescriptorActive is set to a value indicating whether extraFileDescriptor has new data received.
-isTimeout is set to a value indicating whether a timeout was encountered before any file descriptors had events occur.
-*/
-DLLEXPORT int32_t HttpNative_MultiWait(CURLM* multiHandle,
-                                        intptr_t extraFileDescriptor,
-                                        int32_t* isExtraFileDescriptorActive,
-                                        int32_t* isTimeout);
-
-/*
-Reads/writes available data from each easy handle.
-Shims the curl_multi_perform function.
-
-Returns CURLM_OK on success, otherwise an error code.
-*/
-DLLEXPORT int32_t HttpNative_MultiPerform(CURLM* multiHandle);
-
-/*
-Ask the multi handle if there are any messages/informationals from the individual transfers.
-Shims the curl_multi_info_read function.
-
-Returns 1 if a CURLMsg was retrieved and the out variables are set,
-otherwise 0 when there are no more messages to retrieve.
-*/
-DLLEXPORT int32_t HttpNative_MultiInfoRead(CURLM* multiHandle, int32_t* message, CURL** easyHandle, int32_t* result);
-
-/*
-Returns a string describing the CURLMcode error code.
-*/
-DLLEXPORT const char* HttpNative_MultiGetErrorString(PAL_CURLMcode code);
-
-/*
-Shims the curl_multi_setopt function
-*/
-DLLEXPORT int32_t HttpNative_MultiSetOptionLong(CURLM* handle, PAL_CURLMoption option, int64_t value);
diff --git a/src/libraries/Native/Unix/System.Net.Http.Native/pal_slist.c b/src/libraries/Native/Unix/System.Net.Http.Native/pal_slist.c
deleted file mode 100644 (file)
index d6c86ce..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-#include "pal_slist.h"
-
-struct curl_slist* HttpNative_SListAppend(struct curl_slist* list, const char* headerValue)
-{
-    return curl_slist_append(list, headerValue);
-}
-
-void HttpNative_SListFreeAll(struct curl_slist* list)
-{
-    curl_slist_free_all(list);
-}
diff --git a/src/libraries/Native/Unix/System.Net.Http.Native/pal_slist.h b/src/libraries/Native/Unix/System.Net.Http.Native/pal_slist.h
deleted file mode 100644 (file)
index d068f4e..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-#pragma once
-
-#include "pal_types.h"
-#include "pal_compiler.h"
-
-#include <curl/curl.h>
-
-/*
-Appends a specified string to a linked list of strings.
-
-Returns a null pointer if anything went wrong, otherwise the new list pointer.
-*/
-DLLEXPORT struct curl_slist* HttpNative_SListAppend(struct curl_slist* list, const char* headerValue);
-
-/*
-Removes all traces of a previously built curl_slist linked list.
-*/
-DLLEXPORT void HttpNative_SListFreeAll(struct curl_slist* list);
diff --git a/src/libraries/Native/Unix/System.Net.Http.Native/pal_versioninfo.c b/src/libraries/Native/Unix/System.Net.Http.Native/pal_versioninfo.c
deleted file mode 100644 (file)
index dd7b055..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-#include "pal_config.h"
-#include "pal_versioninfo.h"
-
-#include <string.h>
-#include <curl/curl.h>
-
-c_static_assert(PAL_CURL_VERSION_IPV6 == CURL_VERSION_IPV6);
-c_static_assert(PAL_CURL_VERSION_KERBEROS4 == CURL_VERSION_KERBEROS4);
-c_static_assert(PAL_CURL_VERSION_SSL == CURL_VERSION_SSL);
-c_static_assert(PAL_CURL_VERSION_LIBZ == CURL_VERSION_LIBZ);
-c_static_assert(PAL_CURL_VERSION_NTLM == CURL_VERSION_NTLM);
-c_static_assert(PAL_CURL_VERSION_GSSNEGOTIATE == CURL_VERSION_GSSNEGOTIATE);
-c_static_assert(PAL_CURL_VERSION_DEBUG == CURL_VERSION_DEBUG);
-c_static_assert(PAL_CURL_VERSION_ASYNCHDNS == CURL_VERSION_ASYNCHDNS);
-c_static_assert(PAL_CURL_VERSION_SPNEGO == CURL_VERSION_SPNEGO);
-c_static_assert(PAL_CURL_VERSION_LARGEFILE == CURL_VERSION_LARGEFILE);
-c_static_assert(PAL_CURL_VERSION_IDN == CURL_VERSION_IDN);
-c_static_assert(PAL_CURL_VERSION_SSPI == CURL_VERSION_SSPI);
-c_static_assert(PAL_CURL_VERSION_CONV == CURL_VERSION_CONV);
-c_static_assert(PAL_CURL_VERSION_CURLDEBUG == CURL_VERSION_CURLDEBUG);
-c_static_assert(PAL_CURL_VERSION_TLSAUTH_SRP == CURL_VERSION_TLSAUTH_SRP);
-c_static_assert(PAL_CURL_VERSION_NTLM_WB == CURL_VERSION_NTLM_WB);
-#ifdef CURL_VERSION_HTTP2
-c_static_assert(PAL_CURL_VERSION_HTTP2 == CURL_VERSION_HTTP2);
-#endif
-#ifdef CURL_VERSION_GSSAPI
-c_static_assert(PAL_CURL_VERSION_GSSAPI == CURL_VERSION_GSSAPI);
-#endif
-#ifdef CURL_VERSION_KERBEROS5
-c_static_assert(PAL_CURL_VERSION_KERBEROS5 == CURL_VERSION_KERBEROS5);
-#endif
-#ifdef CURL_VERSION_UNIX_SOCKETS
-c_static_assert(PAL_CURL_VERSION_UNIX_SOCKETS == CURL_VERSION_UNIX_SOCKETS);
-#endif
-#ifdef CURL_VERSION_PSL
-c_static_assert(PAL_CURL_VERSION_PSL == CURL_VERSION_PSL);
-#endif
-
-// Based on docs/libcurl/symbols-in-versions in libcurl source tree,
-// the CURL_VERSION_HTTP2 was introduced in libcurl 7.33.0 and
-// the CURLPIPE_MULTIPLEX was introduced in libcurl 7.43.0.
-#define MIN_VERSION_WITH_CURLPIPE_MULTIPLEX 0x072B00
-
-int32_t HttpNative_GetSupportedFeatures()
-{
-    curl_version_info_data* info = curl_version_info(CURLVERSION_NOW);
-    return info != NULL ? info->features : 0;
-}
-
-int32_t HttpNative_GetSupportsHttp2Multiplexing()
-{
-    curl_version_info_data* info = curl_version_info(CURLVERSION_NOW);
-    return info != NULL &&
-        (info->version_num >= MIN_VERSION_WITH_CURLPIPE_MULTIPLEX) && 
-        ((info->features & PAL_CURL_VERSION_HTTP2) == PAL_CURL_VERSION_HTTP2) ? 1 : 0;
-}
-
-char* HttpNative_GetVersionDescription()
-{
-    curl_version_info_data* info = curl_version_info(CURLVERSION_NOW);
-    return info != NULL && info->version != NULL ? strdup(info->version) : NULL;
-}
-
-char* HttpNative_GetSslVersionDescription()
-{
-    curl_version_info_data* info = curl_version_info(CURLVERSION_NOW);
-    return info != NULL && info->ssl_version != NULL ? strdup(info->ssl_version) : NULL;
-}
diff --git a/src/libraries/Native/Unix/System.Net.Http.Native/pal_versioninfo.h b/src/libraries/Native/Unix/System.Net.Http.Native/pal_versioninfo.h
deleted file mode 100644 (file)
index fb2dce6..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-#pragma once
-#include "pal_types.h"
-#include "pal_compiler.h"
-
-/**
-* Constants from curl.h for supported features
-*/
-typedef enum
-{
-    PAL_CURL_VERSION_IPV6 =         (1<<0),
-    PAL_CURL_VERSION_KERBEROS4 =    (1<<1),
-    PAL_CURL_VERSION_SSL =          (1<<2),
-    PAL_CURL_VERSION_LIBZ =         (1<<3),
-    PAL_CURL_VERSION_NTLM =         (1<<4),
-    PAL_CURL_VERSION_GSSNEGOTIATE = (1<<5),
-    PAL_CURL_VERSION_DEBUG =        (1<<6),
-    PAL_CURL_VERSION_ASYNCHDNS =    (1<<7),
-    PAL_CURL_VERSION_SPNEGO =       (1<<8),
-    PAL_CURL_VERSION_LARGEFILE =    (1<<9),
-    PAL_CURL_VERSION_IDN =          (1<<10),
-    PAL_CURL_VERSION_SSPI =         (1<<11),
-    PAL_CURL_VERSION_CONV =         (1<<12),
-    PAL_CURL_VERSION_CURLDEBUG =    (1<<13),
-    PAL_CURL_VERSION_TLSAUTH_SRP =  (1<<14),
-    PAL_CURL_VERSION_NTLM_WB =      (1<<15),
-    PAL_CURL_VERSION_HTTP2 =        (1<<16),
-    PAL_CURL_VERSION_GSSAPI =       (1<<17),
-    PAL_CURL_VERSION_KERBEROS5 =    (1<<18),
-    PAL_CURL_VERSION_UNIX_SOCKETS = (1<<19),
-    PAL_CURL_VERSION_PSL =          (1<<20),
-} CurlFeatures;
-
-/*
-Gets the features supported by libcurl.
-
-Returns 1 if multiplexing is supported, otherwise 0.
-*/
-DLLEXPORT int32_t HttpNative_GetSupportedFeatures(void);
-
-/*
-Gets the features supported by libcurl.
-
-Returns 1 if multiplexing is supported, otherwise 0.
-*/
-DLLEXPORT int32_t HttpNative_GetSupportsHttp2Multiplexing(void);
-
-/*
-Gets a string description of the version in use.
-*/
-DLLEXPORT char* HttpNative_GetVersionDescription(void);
-
-/*
-Gets a string description of the SSL version in use.
-*/
-DLLEXPORT char* HttpNative_GetSslVersionDescription(void);
index 9109927..5cf0d7e 100644 (file)
@@ -736,40 +736,6 @@ elseif (CMAKE_SYSTEM_NAME STREQUAL Linux)
     message(FATAL_ERROR "Cannot find inotify functions on a Linux platform.")
 endif()
 
-check_c_source_compiles(
-    "
-    #include <curl/multi.h>
-    int main(void) { int i = CURLM_ADDED_ALREADY; return 0; }
-    "
-    HAVE_CURLM_ADDED_ALREADY)
-
-check_c_source_compiles(
-    "
-    #include <curl/multi.h>
-    int main(void) { int i = CURL_HTTP_VERSION_2TLS; return 0; }
-    "
-    HAVE_CURL_HTTP_VERSION_2TLS)
-
-check_c_source_compiles(
-    "
-    #include <curl/multi.h>
-    int main(void) { int i = CURLPIPE_MULTIPLEX; return 0; }
-    "
-    HAVE_CURLPIPE_MULTIPLEX)
-
-check_c_source_compiles(
-    "
-    #include <curl/curl.h>
-    int main(void)
-    {
-        int i = CURL_SSLVERSION_TLSv1_0;
-        i = CURL_SSLVERSION_TLSv1_1;
-        i = CURL_SSLVERSION_TLSv1_2;
-        return 0;
-    }
-    "
-    HAVE_CURL_SSLVERSION_TLSv1_012)
-
 option(HeimdalGssApi "use heimdal implementation of GssApi" OFF)
 
 if (HeimdalGssApi)
index e8f9468..3419270 100644 (file)
     <Compile Include="System\Net\Http\HttpClientHandler.Core.cs" />
     <Compile Include="System\Net\Http\HttpClientHandler.netcoreapp.cs" />
     <Compile Include="System\Net\Http\HttpClientHandler.Unix.cs" />
-    <Compile Include="System\Net\Http\CurlHandler\CurlHandler.cs" />
-    <Compile Include="System\Net\Http\CurlHandler\CurlHandler.EasyRequest.cs" />
-    <Compile Include="System\Net\Http\CurlHandler\CurlHandler.MultiAgent.cs" />
-    <Compile Include="System\Net\Http\CurlHandler\CurlException.cs" />
-    <Compile Include="System\Net\Http\CurlHandler\CurlHandler.CurlResponseMessage.cs" />
-    <Compile Include="System\Net\Http\CurlHandler\CurlResponseHeaderReader.cs" />
     <Compile Include="$(CommonPath)\System\StrongToWeakReference.cs">
       <Link>Common\Interop\Unix\StrongToWeakReference.cs</Link>
     </Compile>
     <Compile Include="$(CommonPath)\CoreLib\Interop\Unix\System.Native\Interop.Write.cs">
       <Link>Common\Interop\Unix\libc\Interop.Write.cs</Link>
     </Compile>
-    <Compile Include="$(CommonPath)\Interop\Unix\System.Net.Http.Native\Interop.CURLcode.cs">
-      <Link>Common\Interop\Unix\System.Net.Http.Native\Interop.CURLcode.cs</Link>
-    </Compile>
-    <Compile Include="$(CommonPath)\Interop\Unix\System.Net.Http.Native\Interop.Easy.cs">
-      <Link>Common\Interop\Unix\System.Net.Http.Native\Interop.Easy.cs</Link>
-    </Compile>
-    <Compile Include="$(CommonPath)\Interop\Unix\System.Net.Http.Native\Interop.Initialization.cs">
-      <Link>Common\Interop\Unix\System.Net.Http.Native\Interop.Initialization.cs</Link>
-    </Compile>
-    <Compile Include="$(CommonPath)\Interop\Unix\System.Net.Http.Native\Interop.Multi.cs">
-      <Link>Common\Interop\Unix\System.Net.Http.Native\Interop.Multi.cs</Link>
-    </Compile>
-    <Compile Include="$(CommonPath)\Interop\Unix\System.Net.Http.Native\Interop.SList.cs">
-      <Link>Common\Interop\Unix\System.Net.Http.Native\Interop.SList.cs</Link>
-    </Compile>
-    <Compile Include="$(CommonPath)\Interop\Unix\System.Net.Http.Native\Interop.VersionInfo.cs">
-      <Link>Common\Interop\Unix\System.Net.Http.Native\Interop.VersionInfo.cs</Link>
-    </Compile>
     <Compile Include="$(CommonPath)\System\CharArrayHelpers.cs">
       <Link>Common\System\CharArrayHelpers.cs</Link>
     </Compile>
     <Compile Include="$(CommonPath)\System\Net\Security\CertificateValidation.Unix.cs">
       <Link>Common\System\Net\Security\CertificateValidation.Unix.cs</Link>
     </Compile>
-    <Compile Include="System\Net\Http\CurlHandler\CurlHandler.ClientCertificateProvider.cs" />
-    <Compile Include="System\Net\Http\CurlHandler\CurlHandler.SslProvider.Linux.cs" />
-  </ItemGroup>
-  <ItemGroup Condition=" '$(TargetsOSX)' == 'true' ">
-    <Compile Include="System\Net\Http\CurlHandler\CurlHandler.SslProvider.OSX.cs" />
   </ItemGroup>
   <ItemGroup>
     <Reference Include="Microsoft.Win32.Primitives" />
diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/CurlHandler/CurlException.cs b/src/libraries/System.Net.Http/src/System/Net/Http/CurlHandler/CurlException.cs
deleted file mode 100644 (file)
index 67da37e..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Runtime.InteropServices;
-
-namespace System.Net.Http
-{
-    internal sealed class CurlException : Exception
-    {
-        internal CurlException(int error, string message) : base(message)
-        {
-            HResult = error;
-        }
-
-        internal CurlException(int error, Exception innerException) : base(GetCurlErrorString(error, isMulti:false), innerException)
-        {
-            HResult = error;
-        }
-
-        internal CurlException(int error, bool isMulti) : this(error, GetCurlErrorString(error, isMulti))
-        {
-        }
-
-        internal static string GetCurlErrorString(int code, bool isMulti)
-        {
-            IntPtr ptr = isMulti ? Interop.Http.MultiGetErrorString(code) : Interop.Http.EasyGetErrorString(code);
-            return Marshal.PtrToStringAnsi(ptr);
-        }
-    }
-}
diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/CurlHandler/CurlHandler.ClientCertificateProvider.cs b/src/libraries/System.Net.Http/src/System/Net/Http/CurlHandler/CurlHandler.ClientCertificateProvider.cs
deleted file mode 100644 (file)
index a5e1986..0000000
+++ /dev/null
@@ -1,192 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Runtime.InteropServices;
-using System.Security.Cryptography.X509Certificates;
-using System.Security.Cryptography;
-using Microsoft.Win32.SafeHandles;
-
-namespace System.Net.Http
-{
-    internal partial class CurlHandler : HttpMessageHandler
-    {
-        internal sealed class ClientCertificateProvider : IDisposable
-        {
-            internal GCHandle _gcHandle;
-            internal readonly Interop.Ssl.ClientCertCallback _callback;
-            private readonly X509Certificate2Collection _clientCertificates;
-
-            internal ClientCertificateProvider(X509Certificate2Collection clientCertificates)
-            {
-                _gcHandle = GCHandle.Alloc(this);
-                _callback = TlsClientCertCallback;
-                _clientCertificates = clientCertificates;
-            }
-
-            private int TlsClientCertCallback(IntPtr ssl, out IntPtr certHandle, out IntPtr privateKeyHandle)
-            {
-                EventSourceTrace("SSL: {0}", ssl);
-                const int CertificateSet = 1, NoCertificateSet = 0, SuspendHandshake = -1;
-
-                certHandle = IntPtr.Zero;
-                privateKeyHandle = IntPtr.Zero;
-
-                if (ssl == IntPtr.Zero)
-                {
-                    Debug.Fail("Expected valid SSL pointer");
-                    EventSourceTrace("Invalid SSL pointer in callback");
-                    return NoCertificateSet;
-                }
-
-                SafeSslHandle sslHandle = null;
-                X509Chain chain = null;
-                X509Certificate2 certificate = null;
-                try
-                {
-                    sslHandle = new SafeSslHandle(ssl, ownsHandle: false);
-
-                    ISet<string> issuerNames = GetRequestCertificateAuthorities(sslHandle);
-
-                    if (_clientCertificates != null) // manual mode
-                    {
-                        // If there's one certificate, just use it. Otherwise, try to find the best one.
-                        int certCount = _clientCertificates.Count;
-                        if (certCount == 1)
-                        {
-                            EventSourceTrace("Single certificate.  Building chain.");
-                            certificate = _clientCertificates[0];
-                            chain = TLSCertificateExtensions.BuildNewChain(certificate, includeClientApplicationPolicy: false);
-                        }
-                        else
-                        {
-                            EventSourceTrace("Finding the best of {0} certificates", certCount);
-                            if (!_clientCertificates.TryFindClientCertificate(issuerNames, out certificate, out chain))
-                            {
-                                EventSourceTrace("No certificate set.");
-                                return NoCertificateSet;
-                            }
-                        }
-                        EventSourceTrace("Chain built.");
-                    }
-                    else if (!GetAutomaticClientCertificate(issuerNames, out certificate, out chain)) // automatic mode
-                    {
-                        EventSourceTrace("No automatic certificate or chain.");
-                        return NoCertificateSet;
-                    }
-
-                    SafeEvpPKeyHandle privateKeySafeHandle = null;
-                    Interop.Crypto.CheckValidOpenSslHandle(certificate.Handle);
-                    using (RSAOpenSsl rsa = certificate.GetRSAPrivateKey() as RSAOpenSsl)
-                    {
-                        if (rsa != null)
-                        {
-                            privateKeySafeHandle = rsa.DuplicateKeyHandle();
-                            EventSourceTrace("RSA key");
-                        }
-                        else
-                        {
-                            using (ECDsaOpenSsl ecdsa = certificate.GetECDsaPrivateKey() as ECDsaOpenSsl)
-                            {
-                                if (ecdsa != null)
-                                {
-                                    privateKeySafeHandle = ecdsa.DuplicateKeyHandle();
-                                    EventSourceTrace("ECDsa key");
-                                }
-                            }
-                        }
-                    }
-
-                    if (privateKeySafeHandle == null || privateKeySafeHandle.IsInvalid)
-                    {
-                        EventSourceTrace("Invalid private key");
-                        return NoCertificateSet;
-                    }
-
-                    SafeX509Handle certSafeHandle = Interop.Crypto.X509UpRef(certificate.Handle);
-                    Interop.Crypto.CheckValidOpenSslHandle(certSafeHandle);
-                    if (chain != null)
-                    {
-                        if (!Interop.Ssl.AddExtraChainCertificates(sslHandle, chain))
-                        {
-                            EventSourceTrace("Failed to add extra chain certificate");
-                            return SuspendHandshake;
-                        }
-                    }
-
-                    certHandle = certSafeHandle.DangerousGetHandle();
-                    privateKeyHandle = privateKeySafeHandle.DangerousGetHandle();
-                    EventSourceTrace("Client certificate set: {0}", certificate);
-
-                    // Ownership has been transferred to OpenSSL; do not free these handles
-                    certSafeHandle.SetHandleAsInvalid();
-                    privateKeySafeHandle.SetHandleAsInvalid();
-
-                    return CertificateSet;
-                }
-                finally
-                {
-                    if (_clientCertificates == null) certificate?.Dispose(); // only dispose cert if it's automatic / newly created
-                    chain?.Dispose();
-                    sslHandle?.Dispose();
-                }
-            }
-
-            public void Dispose()
-            {
-                _gcHandle.Free();
-            }
-
-            private static ISet<string> GetRequestCertificateAuthorities(SafeSslHandle sslHandle)
-            {
-                using (SafeSharedX509NameStackHandle names = Interop.Ssl.SslGetClientCAList(sslHandle))
-                {
-                    if (names.IsInvalid)
-                    {
-                        return new HashSet<string>();
-                    }
-
-                    int nameCount = Interop.Crypto.GetX509NameStackFieldCount(names);
-                    var clientAuthorityNames = new HashSet<string>(nameCount);
-                    for (int i = 0; i < nameCount; i++)
-                    {
-                        using (SafeSharedX509NameHandle nameHandle = Interop.Crypto.GetX509NameStackField(names, i))
-                        {
-                            X500DistinguishedName dn = Interop.Crypto.LoadX500Name(nameHandle);
-                            clientAuthorityNames.Add(dn.Name);
-                        }
-                    }
-                    return clientAuthorityNames;
-                }
-            }
-
-            private static bool GetAutomaticClientCertificate(ISet<string> allowedIssuers, out X509Certificate2 certificate, out X509Chain chain)
-            {
-                using (X509Store myStore = new X509Store(StoreName.My, StoreLocation.CurrentUser))
-                {
-                    // Get the certs from the store.
-                    myStore.Open(OpenFlags.ReadOnly);
-                    X509Certificate2Collection certs = myStore.Certificates;
-
-                    // Find a matching one.
-                    bool gotCert = certs.TryFindClientCertificate(allowedIssuers, out certificate, out chain);
-
-                    // Dispose all but the matching cert.
-                    for (int i = 0; i < certs.Count; i++)
-                    {
-                        X509Certificate2 cert = certs[i];
-                        if (cert != certificate)
-                        {
-                            cert.Dispose();
-                        }
-                    }
-
-                    // Return whether we got one.
-                    return gotCert;
-                }
-            }
-        }
-    }
-}
diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/CurlHandler/CurlHandler.CurlResponseMessage.cs b/src/libraries/System.Net.Http/src/System/Net/Http/CurlHandler/CurlHandler.CurlResponseMessage.cs
deleted file mode 100644 (file)
index a762de2..0000000
+++ /dev/null
@@ -1,530 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Diagnostics;
-using System.IO;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace System.Net.Http
-{
-    internal partial class CurlHandler : HttpMessageHandler
-    {
-        private sealed class CurlResponseMessage : HttpResponseMessage
-        {
-            internal uint _headerBytesReceived;
-
-            internal CurlResponseMessage(EasyRequest easy)
-            {
-                Debug.Assert(easy != null, "Expected non-null EasyRequest");
-                RequestMessage = easy._requestMessage;
-                ResponseStream = new CurlResponseStream(easy);
-                Content = new NoWriteNoSeekStreamContent(ResponseStream);
-
-                // On Windows, we pass the equivalent of the easy._cancellationToken
-                // in to StreamContent's ctor.  This in turn passes that token through
-                // to ReadAsync operations on the stream response stream when HttpClient
-                // reads from the response stream to buffer it with ResponseContentRead.
-                // We don't need to do that here in the Unix implementation as, until the
-                // SendAsync task completes, the handler will have registered with the
-                // CancellationToken with an action that will cancel all work related to
-                // the easy handle if cancellation occurs, and that includes canceling any
-                // pending reads on the response stream.  It wouldn't hurt anything functionally
-                // to still pass easy._cancellationToken here, but it will increase costs
-                // a bit, as each read will then need to allocate a larger state object as
-                // well as register with and unregister from the cancellation token.
-            }
-
-            internal CurlResponseStream ResponseStream { get; }
-        }
-
-        /// <summary>
-        /// Provides a response stream that allows libcurl to transfer data asynchronously to a reader.
-        /// When writing data to the response stream, either all or none of the data will be transferred,
-        /// and if none, libcurl will pause the connection until a reader is waiting to consume the data.
-        /// Readers consume the data via ReadAsync, which registers a read state with the stream, to be
-        /// filled in by a pending write.  Read is just a thin wrapper around ReadAsync, since the underlying
-        /// mechanism must be asynchronous to prevent blocking libcurl's processing.
-        /// </summary>
-        private sealed class CurlResponseStream : Stream
-        {
-            /// <summary>
-            /// A sentinel object used in the <see cref="_completed"/> field to indicate that
-            /// the stream completed successfully.
-            /// </summary>
-            private static readonly Exception s_completionSentinel = new Exception(nameof(s_completionSentinel));
-
-            /// <summary>A object used to synchronize all access to state on this response stream.</summary>
-            private readonly object _lockObject = new object();
-
-            /// <summary>The associated EasyRequest.</summary>
-            private readonly EasyRequest _easy;
-
-            /// <summary>Stores whether Dispose has been called on the stream.</summary>
-            private bool _disposed = false;
-
-            /// <summary>
-            /// Null if the Stream has not been completed, non-null if it has been completed.
-            /// If non-null, it'll either be the <see cref="s_completionSentinel"/> object, meaning the stream completed
-            /// successfully, or it'll be an Exception object representing the error that caused completion.
-            /// That error will be transferred to any subsequent read requests.
-            /// </summary>
-            private Exception _completed;
-
-            /// <summary>
-            /// The state associated with a pending read request. When a reader requests data, it puts
-            /// its state here for the writer to fill in when data is available.
-            /// </summary>
-            private ReadState _pendingReadRequest;
-
-            /// <summary>
-            /// When data is provided by libcurl, it must be consumed all or nothing: either all of the data is consumed, or
-            /// we must pause the connection.  Since a read could need to be satisfied with only some of the data provided,
-            /// we store the rest here until all reads can consume it.  If a subsequent write callback comes in to provide
-            /// more data, the connection will then be paused until this buffer is entirely consumed.
-            /// </summary>
-            private byte[] _remainingData;
-
-            /// <summary>
-            /// The offset into <see cref="_remainingData"/> from which the next read should occur.
-            /// </summary>
-            private int _remainingDataOffset;
-
-            /// <summary>
-            /// The remaining number of bytes in <see cref="_remainingData"/> available to be read.
-            /// </summary>
-            private int _remainingDataCount;
-
-            internal CurlResponseStream(EasyRequest easy)
-            {
-                Debug.Assert(easy != null, "Expected non-null associated EasyRequest");
-                _easy = easy;
-            }
-
-            public override bool CanRead => !_disposed;
-            public override bool CanWrite => false;
-            public override bool CanSeek => false;
-
-            public override long Length
-            {
-                get
-                {
-                    CheckDisposed();
-                    throw new NotSupportedException();
-                }
-            }
-
-            public override long Position
-            {
-                get
-                {
-                    CheckDisposed();
-                    throw new NotSupportedException();
-                }
-
-                set
-                {
-                    CheckDisposed();
-                    throw new NotSupportedException();
-                }
-            }
-
-            public override long Seek(long offset, SeekOrigin origin)
-            {
-                CheckDisposed();
-                throw new NotSupportedException();
-            }
-
-            public override void SetLength(long value)
-            {
-                CheckDisposed();
-                throw new NotSupportedException();
-            }
-
-            public override void Write(byte[] buffer, int offset, int count)
-            {
-                CheckDisposed();
-                throw new NotSupportedException();
-            }
-
-            public override void Flush()
-            {
-                // Nothing to do.
-            }
-
-            /// <summary>
-            /// Writes the <paramref name="length"/> bytes starting at <paramref name="pointer"/> to the stream.
-            /// </summary>
-            /// <returns>
-            /// <paramref name="length"/> if all of the data was written, or
-            /// <see cref="Interop.Http.CURL_WRITEFUNC_PAUSE"/> if the data wasn't copied and the connection
-            /// should be paused until a reader is available.
-            /// </returns>
-            internal ulong TransferDataToResponseStream(IntPtr pointer, long length)
-            {
-                Debug.Assert(pointer != IntPtr.Zero, "Expected a non-null pointer");
-                Debug.Assert(length >= 0, "Expected a non-negative length");
-                EventSourceTrace("Length: {0}", length);
-
-                CheckDisposed();
-
-                // If there's no data to write, consider everything transferred.
-                if (length == 0)
-                {
-                    return 0;
-                }
-
-                lock (_lockObject)
-                {
-                    VerifyInvariants();
-
-                    // If there's existing data in the remaining data buffer, or if there's no pending read request,
-                    // we need to pause until the existing data is consumed or until there's a waiting read.
-                    if (_remainingDataCount > 0)
-                    {
-                        EventSourceTrace("Pausing transfer to response stream. Remaining bytes: {0}", _remainingDataCount);
-                        return Interop.Http.CURL_WRITEFUNC_PAUSE;
-                    }
-                    else if (_pendingReadRequest == null)
-                    {
-                        EventSourceTrace("Pausing transfer to response stream. No pending read request");
-                        return Interop.Http.CURL_WRITEFUNC_PAUSE;
-                    }
-
-                    // There's no data in the buffer and there is a pending read request.
-                    // Transfer as much data as we can to the read request, completing it.
-                    int numBytesForTask = (int)Math.Min(length, _pendingReadRequest._buffer.Length);
-                    Debug.Assert(numBytesForTask > 0, "We must be copying a positive amount.");
-                    unsafe { new Span<byte>((byte*)pointer, numBytesForTask).CopyTo(_pendingReadRequest._buffer.Span); }
-                    EventSourceTrace("Completing pending read with {0} bytes", numBytesForTask);
-                    _pendingReadRequest.SetResult(numBytesForTask);
-                    ClearPendingReadRequest();
-
-                    // If there's any data left, transfer it to our remaining buffer. libcurl does not support
-                    // partial transfers of data, so since we just took some of it to satisfy the read request
-                    // we must take the rest of it. (If libcurl then comes back to us subsequently with more data
-                    // before this buffered data has been consumed, at that point we won't consume any of the
-                    // subsequent offering and will ask libcurl to pause.)
-                    if (numBytesForTask < length)
-                    {
-                        IntPtr remainingPointer = pointer + numBytesForTask;
-                        _remainingDataCount = checked((int)(length - numBytesForTask));
-                        _remainingDataOffset = 0;
-
-                        // Make sure our remaining data buffer exists and is big enough to hold the data
-                        if (_remainingData == null)
-                        {
-                            _remainingData = new byte[_remainingDataCount];
-                        }
-                        else if (_remainingData.Length < _remainingDataCount)
-                        {
-                            _remainingData = new byte[Math.Max(_remainingData.Length * 2, _remainingDataCount)];
-                        }
-
-                        // Copy the remaining data to the buffer
-                        EventSourceTrace("Storing {0} bytes for later", _remainingDataCount);
-                        Marshal.Copy(remainingPointer, _remainingData, 0, _remainingDataCount);
-                    }
-
-                    // All of the data from libcurl was consumed.
-                    return (ulong)length;
-                }
-            }
-
-            public override int Read(byte[] buffer, int offset, int count) =>
-                ReadAsync(buffer, offset, count, CancellationToken.None).GetAwaiter().GetResult();
-
-            public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state) =>
-                TaskToApm.Begin(ReadAsync(buffer, offset, count, CancellationToken.None), callback, state);
-
-            public override int EndRead(IAsyncResult asyncResult) =>
-                TaskToApm.End<int>(asyncResult);
-
-            public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
-            {
-                if (buffer == null) throw new ArgumentNullException(nameof(buffer));
-                if (offset < 0) throw new ArgumentOutOfRangeException(nameof(offset));
-                if (count < 0) throw new ArgumentOutOfRangeException(nameof(count));
-                if (offset > buffer.Length - count) throw new ArgumentException(SR.net_http_buffer_insufficient_length, nameof(buffer));
-
-                return ReadAsync(new Memory<byte>(buffer, offset, count), cancellationToken).AsTask();
-            }
-
-            public override ValueTask<int> ReadAsync(Memory<byte> buffer, CancellationToken cancellationToken = default)
-            {
-                CheckDisposed();
-
-                EventSourceTrace("Buffer: {0}", buffer.Length);
-
-                // Check for cancellation
-                if (cancellationToken.IsCancellationRequested)
-                {
-                    EventSourceTrace("Canceled");
-                    return new ValueTask<int>(Task.FromCanceled<int>(cancellationToken));
-                }
-
-                lock (_lockObject)
-                {
-                    VerifyInvariants();
-
-                    // If there's currently a pending read, fail this read, as we don't support concurrent reads.
-                    if (_pendingReadRequest != null)
-                    {
-                        EventSourceTrace("Failing due to existing pending read; concurrent reads not supported.");
-                        return new ValueTask<int>(Task.FromException<int>(new InvalidOperationException(SR.net_http_content_no_concurrent_reads)));
-                    }
-
-                    // If the stream was already completed with failure, complete the read as a failure.
-                    if (_completed != null && _completed != s_completionSentinel)
-                    {
-                        EventSourceTrace("Failing read with error: {0}", _completed);
-
-                        OperationCanceledException oce = _completed as OperationCanceledException;
-                        return new ValueTask<int>((oce != null && oce.CancellationToken.IsCancellationRequested) ?
-                            Task.FromCanceled<int>(oce.CancellationToken) :
-                            Task.FromException<int>(MapToReadWriteIOException(_completed, isRead: true)));
-                    }
-
-                    // Quick check for if no data was actually requested.  We do this after the check
-                    // for errors so that we can still fail the read and transfer the exception if we should.
-                    if (buffer.Length == 0)
-                    {
-                        return new ValueTask<int>(0);
-                    }
-
-                    // If there's any data left over from a previous call, grab as much as we can.
-                    if (_remainingDataCount > 0)
-                    {
-                        int bytesToCopy = Math.Min(buffer.Length, _remainingDataCount);
-                        new Span<byte>(_remainingData, _remainingDataOffset, bytesToCopy).CopyTo(buffer.Span);
-
-                        _remainingDataOffset += bytesToCopy;
-                        _remainingDataCount -= bytesToCopy;
-                        Debug.Assert(_remainingDataCount >= 0, "The remaining count should never go negative");
-                        Debug.Assert(_remainingDataOffset <= _remainingData.Length, "The remaining offset should never exceed the buffer size");
-
-                        EventSourceTrace("Read {0} bytes", bytesToCopy);
-                        return new ValueTask<int>(bytesToCopy);
-                    }
-
-                    // If the stream has already been completed, complete the read immediately.
-                    if (_completed == s_completionSentinel)
-                    {
-                        EventSourceTrace("Stream already completed");
-                        return new ValueTask<int>(0);
-                    }
-
-                    // Finally, the stream is still alive, and we want to read some data, but there's no data
-                    // in the buffer so we need to register ourself to get the next write.
-                    if (cancellationToken.CanBeCanceled)
-                    {
-                        // If the cancellation token is cancelable, then we need to register for cancellation.
-                        // We create a special CancelableReadState that carries with it additional info:
-                        // the cancellation token and the registration with that token.  When cancellation
-                        // is requested, we schedule a work item that tries to remove the read state
-                        // from being pending, canceling it in the process.  This needs to happen under the
-                        // lock, which is why we schedule the operation to run asynchronously: if it ran
-                        // synchronously, it could deadlock due to code on another thread holding the lock
-                        // and calling Dispose on the registration concurrently with the call to Cancel
-                        // the cancellation token.  Dispose on the registration won't return until the action
-                        // associated with the registration has completed, but if that action is currently
-                        // executing and is blocked on the lock that's held while calling Dispose... deadlock.
-                        var crs = new CancelableReadState(buffer, this, cancellationToken);
-                        crs._registration = cancellationToken.Register(s1 =>
-                        {
-                            ((CancelableReadState)s1)._stream.EventSourceTrace("Cancellation invoked. Queueing work item to cancel read state");
-                            Task.Factory.StartNew(s2 =>
-                            {
-                                var crsRef = (CancelableReadState)s2;
-                                lock (crsRef._stream._lockObject)
-                                {
-                                    Debug.Assert(crsRef._token.IsCancellationRequested, "We should only be here if cancellation was requested.");
-                                    if (crsRef._stream._pendingReadRequest == crsRef)
-                                    {
-                                        crsRef._stream.EventSourceTrace("Canceling");
-                                        crsRef.TrySetCanceled(crsRef._token);
-                                        crsRef._stream.ClearPendingReadRequest();
-                                    }
-                                }
-                            }, s1, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default);
-                        }, crs);
-                        _pendingReadRequest = crs;
-                    }
-                    else
-                    {
-                        // The token isn't cancelable.  Just create a normal read state.
-                        _pendingReadRequest = new ReadState(buffer);
-                    }
-
-                    _easy._associatedMultiAgent.RequestUnpause(_easy);
-                    _easy._selfStrongToWeakReference.MakeStrong(); // convert from a weak to a strong ref to keep the easy alive during the read
-                    return new ValueTask<int>(_pendingReadRequest.Task);
-                }
-            }
-
-            /// <summary>Notifies the stream that no more data will be written.</summary>
-            internal void SignalComplete(Exception error = null, bool forceCancel = false)
-            {
-                lock (_lockObject)
-                {
-                    VerifyInvariants();
-
-                    // If we already completed, nothing more to do
-                    if (_completed != null)
-                    {
-                        EventSourceTrace("Already completed");
-                        return;
-                    }
-
-                    // Mark ourselves as being completed
-                    EventSourceTrace("Marking as complete");
-                    _completed = error ?? s_completionSentinel;
-
-                    // If the request wasn't already completed, and if requested, send a cancellation
-                    // request to ensure that the connection gets cleaned up.  This is only necessary
-                    // to do if this method is being called for a reason other than the request/response
-                    // completing naturally, e.g. if the response stream is being disposed of before
-                    // all of the response has been downloaded.
-                    if (forceCancel)
-                    {
-                        EventSourceTrace("Completing the response stream prematurely.");
-                        _easy._associatedMultiAgent.RequestCancel(_easy);
-                    }
-
-                    // If there's a pending read request, complete it, either with 0 bytes for success
-                    // or with the exception/CancellationToken for failure.
-                    ReadState pendingRead = _pendingReadRequest;
-                    if (pendingRead != null)
-                    {
-                        if (_completed == s_completionSentinel)
-                        {
-                            EventSourceTrace("Completing pending read with 0 bytes");
-                            pendingRead.TrySetResult(0);
-                        }
-                        else
-                        {
-                            EventSourceTrace("Failing pending read task with error: {0}", _completed);
-                            OperationCanceledException oce = _completed as OperationCanceledException;
-                            if (oce != null)
-                            {
-                                pendingRead.TrySetCanceled(oce.CancellationToken);
-                            }
-                            else
-                            {
-                                pendingRead.TrySetException(MapToReadWriteIOException(_completed, isRead: true));
-                            }
-                        }
-
-                        ClearPendingReadRequest();
-                    }
-                }
-            }
-
-            /// <summary>
-            /// Clears a pending read request, making sure any cancellation registration is unregistered and
-            /// ensuring that the EasyRequest has dropped its strong reference to itself, which should only
-            /// exist while an active async operation is going.
-            /// </summary>
-            private void ClearPendingReadRequest()
-            {
-                Debug.Assert(Monitor.IsEntered(_lockObject), "Lock object must be held to manipulate _pendingReadRequest");
-                Debug.Assert(_pendingReadRequest != null, "Should only be clearing the pending read request if there is one");
-                Debug.Assert(_pendingReadRequest.Task.IsCompleted, "The pending request should have been completed");
-
-                (_pendingReadRequest as CancelableReadState)?._registration.Dispose();
-                _pendingReadRequest = null;
-
-                // The async operation has completed.  We no longer want to be holding a strong reference.
-                _easy._selfStrongToWeakReference.MakeWeak();
-            }
-
-            ~CurlResponseStream()
-            {
-                Dispose(disposing: false);
-            }
-
-            protected override void Dispose(bool disposing)
-            {
-                // disposing is ignored.  We need to SignalComplete whether this is due to Dispose
-                // or due to finalization, so that we don't leave Tasks uncompleted, don't leave
-                // connections paused, etc.
-
-                if (!_disposed)
-                {
-                    EventSourceTrace("Disposing response stream");
-                    _disposed = true;
-                    SignalComplete(forceCancel: true);
-                }
-
-                base.Dispose(disposing);
-            }
-
-            private void CheckDisposed()
-            {
-                if (_disposed)
-                {
-                    throw new ObjectDisposedException(GetType().FullName);
-                }
-            }
-
-            private void EventSourceTrace<TArg0>(string formatMessage, TArg0 arg0, [CallerMemberName] string memberName = null)
-            {
-                CurlHandler.EventSourceTrace(formatMessage, arg0, agent: null, easy: _easy, memberName: memberName);
-            }
-
-            private void EventSourceTrace<TArg0, TArg1, TArg2>(string formatMessage, TArg0 arg0, TArg1 arg1, TArg2 arg2, [CallerMemberName] string memberName = null)
-            {
-                CurlHandler.EventSourceTrace(formatMessage, arg0, arg1, arg2, agent: null, easy: _easy, memberName: memberName);
-            }
-
-            private void EventSourceTrace(string message, [CallerMemberName] string memberName = null)
-            {
-                CurlHandler.EventSourceTrace(message, agent: null, easy: _easy, memberName: memberName);
-            }
-
-            /// <summary>Verifies various invariants that must be true about our state.</summary>
-            [Conditional("DEBUG")]
-            private void VerifyInvariants()
-            {
-                Debug.Assert(Monitor.IsEntered(_lockObject), "Can only verify invariants while holding the lock");
-
-                Debug.Assert(_remainingDataCount >= 0, "Remaining data count should never be negative.");
-                Debug.Assert(_remainingDataCount == 0 || _remainingData != null, "If there's remaining data, there must be a buffer to store it.");
-                Debug.Assert(_remainingData == null || _remainingDataCount <= _remainingData.Length, "The buffer must be large enough for the data length.");
-                Debug.Assert(_remainingData == null || _remainingDataOffset <= _remainingData.Length, "The offset must not walk off the buffer.");
-
-                Debug.Assert(!((_remainingDataCount > 0) && (_pendingReadRequest != null)), "We can't have both remaining data and a pending request.");
-                Debug.Assert(!((_completed != null) && (_pendingReadRequest != null)), "We can't both be completed and have a pending request.");
-                Debug.Assert(_pendingReadRequest == null || !_pendingReadRequest.Task.IsCompleted, "A pending read request must not have been completed yet.");
-            }
-
-            /// <summary>State associated with a pending read request.</summary>
-            private class ReadState : TaskCompletionSource<int>
-            {
-                internal readonly Memory<byte> _buffer;
-
-                internal ReadState(Memory<byte> buffer) :  base(TaskCreationOptions.RunContinuationsAsynchronously)
-                {
-                    _buffer = buffer;
-                }
-            }
-
-            /// <summary>State associated with a pending read request that's cancelable.</summary>
-            private sealed class CancelableReadState : ReadState
-            {
-                internal readonly CurlResponseStream _stream;
-                internal readonly CancellationToken _token;
-                internal CancellationTokenRegistration _registration;
-
-                internal CancelableReadState(Memory<byte> buffer, CurlResponseStream responseStream, CancellationToken cancellationToken) : base(buffer)
-                {
-                    _stream = responseStream;
-                    _token = cancellationToken;
-                }
-            }
-        }
-    }
-}
diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/CurlHandler/CurlHandler.EasyRequest.cs b/src/libraries/System.Net.Http/src/System/Net/Http/CurlHandler/CurlHandler.EasyRequest.cs
deleted file mode 100644 (file)
index b45e637..0000000
+++ /dev/null
@@ -1,1019 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Buffers;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.IO;
-using System.Net.Http.Headers;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-using System.Threading;
-using System.Threading.Tasks;
-
-using CURLAUTH = Interop.Http.CURLAUTH;
-using CURLcode = Interop.Http.CURLcode;
-using CURLoption = Interop.Http.CURLoption;
-using CurlProtocols = Interop.Http.CurlProtocols;
-using CURLProxyType = Interop.Http.curl_proxytype;
-using SafeCurlHandle = Interop.Http.SafeCurlHandle;
-using SafeCurlSListHandle = Interop.Http.SafeCurlSListHandle;
-using SafeCallbackHandle = Interop.Http.SafeCallbackHandle;
-using SeekCallback = Interop.Http.SeekCallback;
-using ReadWriteCallback = Interop.Http.ReadWriteCallback;
-using ReadWriteFunction = Interop.Http.ReadWriteFunction;
-using SslCtxCallback = Interop.Http.SslCtxCallback;
-using DebugCallback = Interop.Http.DebugCallback;
-
-namespace System.Net.Http
-{
-    internal partial class CurlHandler : HttpMessageHandler
-    {
-        /// <summary>Provides all of the state associated with a single request/response, referred to as an "easy" request in libcurl parlance.</summary>
-        private sealed class EasyRequest : TaskCompletionSource<HttpResponseMessage>
-        {
-            /// <summary>Maximum content length where we'll use COPYPOSTFIELDS to let libcurl dup the content.</summary>
-            private const int InMemoryPostContentLimit = 32 * 1024; // arbitrary limit; could be tweaked in the future based on experimentation
-            /// <summary>Debugging flag used to enable CURLOPT_VERBOSE to dump to stderr when not redirecting it to the event source.</summary>
-            private static readonly bool s_curlDebugLogging = Environment.GetEnvironmentVariable("CURLHANDLER_DEBUG_VERBOSE") == "true";
-
-            internal readonly CurlHandler _handler;
-            internal readonly MultiAgent _associatedMultiAgent;
-            internal readonly HttpRequestMessage _requestMessage;
-            internal readonly CurlResponseMessage _responseMessage;
-            internal readonly CancellationToken _cancellationToken;
-            internal Stream _requestContentStream;
-            internal long? _requestContentStreamStartingPosition;
-            internal bool _inMemoryPostContent;
-
-            internal SafeCurlHandle _easyHandle;
-            private SafeCurlSListHandle _requestHeaders;
-
-            internal SendTransferState _sendTransferState;
-            internal StrongToWeakReference<EasyRequest> _selfStrongToWeakReference;
-
-            private SafeCallbackHandle _callbackHandle;
-
-            public EasyRequest(CurlHandler handler, MultiAgent agent, HttpRequestMessage requestMessage, CancellationToken cancellationToken) :
-                base(TaskCreationOptions.RunContinuationsAsynchronously)
-            {
-                Debug.Assert(handler != null, $"Expected non-null {nameof(handler)}");
-                Debug.Assert(agent != null, $"Expected non-null {nameof(agent)}");
-                Debug.Assert(requestMessage != null, $"Expected non-null {nameof(requestMessage)}");
-
-                _handler = handler;
-                _associatedMultiAgent = agent;
-                _requestMessage = requestMessage;
-
-                _cancellationToken = cancellationToken;
-                _responseMessage = new CurlResponseMessage(this);
-            }
-
-            /// <summary>
-            /// Initialize the underlying libcurl support for this EasyRequest.
-            /// This is separated out of the constructor so that we can take into account
-            /// any additional configuration needed based on the request message
-            /// after the EasyRequest is configured and so that error handling
-            /// can be better handled in the caller.
-            /// </summary>
-            internal void InitializeCurl()
-            {
-                // Create the underlying easy handle
-                SafeCurlHandle easyHandle = Interop.Http.EasyCreate();
-                if (easyHandle.IsInvalid)
-                {
-                    throw new OutOfMemoryException();
-                }
-                _easyHandle = easyHandle;
-
-                EventSourceTrace("Configuring request.");
-
-                // Before setting any other options, turn on curl's debug tracing
-                // if desired.  CURLOPT_VERBOSE may also be set subsequently if
-                // EventSource tracing is enabled.
-                if (s_curlDebugLogging)
-                {
-                    SetCurlOption(CURLoption.CURLOPT_VERBOSE, 1L);
-                }
-
-                // Before actually configuring the handle based on the state of the request,
-                // do any necessary cleanup of the request object.
-                SanitizeRequestMessage();
-
-                // Configure the handle
-                SetUrl();
-                SetNetworkingOptions();
-                SetMultithreading();
-                SetTimeouts();
-                SetRedirection();
-                SetVerb();
-                SetVersion();
-                SetDecompressionOptions();
-                SetProxyOptions(_requestMessage.RequestUri);
-                SetCredentialsOptions(_handler._useDefaultCredentials ? GetDefaultCredentialAndAuth() : _handler.GetCredentials(_requestMessage.RequestUri));
-                SetCookieOption(_requestMessage.RequestUri);
-                SetRequestHeaders(copyAuthHeaders:true);
-                SetSslOptions();
-
-                EventSourceTrace("Done configuring request.");
-            }
-
-            public void EnsureResponseMessagePublished()
-            {
-                // If the response message hasn't been published yet, do any final processing of it before it is.
-                if (!Task.IsCompleted)
-                {
-                    EventSourceTrace("Publishing response message");
-
-                    // On Windows, if the response was automatically decompressed, Content-Encoding and Content-Length
-                    // headers are removed from the response. Do the same thing here.
-                    DecompressionMethods dm = _handler.AutomaticDecompression;
-                    if (dm != DecompressionMethods.None)
-                    {
-                        HttpContentHeaders contentHeaders = _responseMessage.Content.Headers;
-                        IEnumerable<string> encodings;
-                        if (contentHeaders.TryGetValues(HttpKnownHeaderNames.ContentEncoding, out encodings))
-                        {
-                            foreach (string encoding in encodings)
-                            {
-                                if (((dm & DecompressionMethods.GZip) != 0 && string.Equals(encoding, EncodingNameGzip, StringComparison.OrdinalIgnoreCase)) ||
-                                    ((dm & DecompressionMethods.Deflate) != 0 && string.Equals(encoding, EncodingNameDeflate, StringComparison.OrdinalIgnoreCase)))
-                                {
-                                    contentHeaders.Remove(HttpKnownHeaderNames.ContentEncoding);
-                                    contentHeaders.Remove(HttpKnownHeaderNames.ContentLength);
-                                    break;
-                                }
-                            }
-                        }
-                    }
-                }
-
-                // Now ensure it's published.
-                bool completedTask = TrySetResult(_responseMessage);
-                Debug.Assert(completedTask || Task.IsCompletedSuccessfully,
-                    "If the task was already completed, it should have been completed successfully; " +
-                    "we shouldn't be completing as successful after already completing as failed.");
-
-                // If we successfully transitioned it to be completed, we also handed off lifetime ownership
-                // of the response to the owner of the task.  Transition our reference on the EasyRequest
-                // to be weak instead of strong, so that we don't forcibly keep it alive.
-                if (completedTask)
-                {
-                    Debug.Assert(_selfStrongToWeakReference != null, "Expected non-null wrapper");
-                    _selfStrongToWeakReference.MakeWeak();
-                }
-            }
-
-            public void CleanupAndFailRequest(Exception error)
-            {
-                try
-                {
-                    Cleanup();
-                }
-                catch (Exception exc)
-                {
-                    // This would only happen in an aggregious case, such as a Stream failing to seek when
-                    // it claims to be able to, but in case something goes very wrong, make sure we don't
-                    // lose the exception information.
-                    error = new AggregateException(error, exc);
-                }
-                finally
-                {
-                    FailRequest(error);
-                }
-            }
-
-            public void FailRequest(Exception error)
-            {
-                Debug.Assert(error != null, "Expected non-null exception");
-                EventSourceTrace("Failing request: {0}", error);
-
-                var oce = error as OperationCanceledException;
-                if (oce != null)
-                {
-                    TrySetCanceled(oce.CancellationToken);
-                }
-                else
-                {
-                    if (error is InvalidOperationException || error is IOException || error is CurlException || error == null)
-                    {
-                        error = CreateHttpRequestException(error);
-                    }
-                    TrySetException(error);
-                }
-                // There's not much we can reasonably assert here about the result of TrySet*.
-                // It's possible that the task wasn't yet completed (e.g. a failure while initiating the request),
-                // it's possible that the task was already completed as success (e.g. a failure sending back the response),
-                // and it's possible that the task was already completed as failure (e.g. we handled the exception and
-                // faulted the task, but then tried to fault it again while finishing processing in the main loop).
-
-                // Make sure the exception is available on the response stream so that it's propagated
-                // from any attempts to read from the stream.
-                _responseMessage.ResponseStream.SignalComplete(error);
-            }
-
-            public void Cleanup() // not called Dispose because the request may still be in use after it's cleaned up
-            {
-                // Don't dispose of the ResponseMessage.ResponseStream as it may still be in use
-                // by code reading data stored in the stream. Also don't dispose of the request content
-                // stream; that'll be handled by the disposal of the request content by the HttpClient,
-                // and doing it here prevents reuse by an intermediate handler sitting between the client
-                // and this handler.
-
-                // However, if we got an original position for the request stream, we seek back to that position,
-                // for the corner case where the stream does get reused before it's disposed by the HttpClient
-                // (if the same request object is used multiple times from an intermediate handler, we'll be using
-                // ReadAsStreamAsync, which on the same request object will return the same stream object, which
-                // we've already advanced).
-                if (_requestContentStream != null && _requestContentStream.CanSeek)
-                {
-                    Debug.Assert(_requestContentStreamStartingPosition.HasValue, "The stream is seekable, but we don't have a starting position?");
-                    _requestContentStream.Position = _requestContentStreamStartingPosition.GetValueOrDefault();
-                }
-
-                // Dispose of the underlying easy handle.  We're no longer processing it.
-                _easyHandle?.Dispose();
-
-                // Dispose of the request headers if we had any.  We had to keep this handle
-                // alive as long as the easy handle was using it.  We didn't need to do any
-                // ref counting on the safe handle, though, as the only processing happens
-                // in Process, which ensures the handle will be rooted while libcurl is
-                // doing any processing that assumes it's valid.
-                _requestHeaders?.Dispose();
-
-                // Dispose native callback resources
-                _callbackHandle?.Dispose();
-
-                // Release any send transfer state, which will return its buffer to the pool
-                _sendTransferState?.Dispose();
-            }
-
-            private void SanitizeRequestMessage()
-            {
-                // Make sure Transfer-Encoding and Content-Length make sense together.
-                if (_requestMessage.Content != null)
-                {
-                    SetChunkedModeForSend(_requestMessage);
-                }
-            }
-
-            private void SetUrl()
-            {
-                Uri requestUri = _requestMessage.RequestUri;
-
-                long scopeId;
-                string url;
-
-                EventSourceTrace("Url: {0}", requestUri);
-                SetCurlOption(CURLoption.CURLOPT_PROTOCOLS, (long)(CurlProtocols.CURLPROTO_HTTP | CurlProtocols.CURLPROTO_HTTPS));
-
-                if (IsLinkLocal(requestUri, out scopeId))
-                {
-                    // Uri.AbsoluteUri doesn't include the ScopeId/ZoneID, so if it is link-local,
-                    // we separately pass the scope to libcurl.
-                    EventSourceTrace("ScopeId: {0}", scopeId);
-                    try
-                    {
-                        SetCurlOption(CURLoption.CURLOPT_ADDRESS_SCOPE, scopeId);
-                    }
-                    catch (CurlException)
-                    {
-                        // libCurl has a bug regarding long scope-ids:
-                        //     https://github.com/curl/curl/issues/3713
-                        // Workaround the problem by percent-encoding the scope separator ('%')
-                        url = new UriBuilder(requestUri) { Host = requestUri.IdnHost}.ToString().Replace("%", "%25");
-                        SetCurlOption(CURLoption.CURLOPT_URL, url);
-                        return;
-                    }
-                }
-
-                string idnHost = requestUri.IdnHost;
-                url = requestUri.Host == idnHost ?
-                         requestUri.AbsoluteUri :
-                         new UriBuilder(requestUri) { Host = idnHost }.Uri.AbsoluteUri;
-
-                SetCurlOption(CURLoption.CURLOPT_URL, url);
-            }
-
-            private static bool IsLinkLocal(Uri url, out long scopeId)
-            {
-                IPAddress ip;
-                if (IPAddress.TryParse(url.DnsSafeHost, out ip) && ip.IsIPv6LinkLocal)
-                {
-                    scopeId = ip.ScopeId;
-                    return true;
-                }
-
-                scopeId = 0;
-                return false;
-            }
-
-            private void SetNetworkingOptions()
-            {
-                // Disable the TCP Nagle algorithm.  It's disabled by default starting with libcurl 7.50.2,
-                // and when enabled has a measurably negative impact on latency in key scenarios
-                // (e.g. POST'ing small-ish data).
-                SetCurlOption(CURLoption.CURLOPT_TCP_NODELAY, 1L);
-                // Enable TCP keep-alive.
-                SetCurlOption(CURLoption.CURLOPT_TCP_KEEPALIVE, 1L);
-            }
-
-            private void SetMultithreading()
-            {
-                SetCurlOption(CURLoption.CURLOPT_NOSIGNAL, 1L);
-            }
-
-            private void SetTimeouts()
-            {
-                // Set timeout limit on the connect phase. curl has bug on ARM so use max - 1s.
-                SetCurlOption(CURLoption.CURLOPT_CONNECTTIMEOUT_MS, int.MaxValue - 1000);
-
-                // Override the default DNS cache timeout.  libcurl defaults to a 1 minute
-                // timeout, but we extend that to match the Windows timeout of 10 minutes.
-                const int DnsCacheTimeoutSeconds = 10 * 60;
-                SetCurlOption(CURLoption.CURLOPT_DNS_CACHE_TIMEOUT, DnsCacheTimeoutSeconds);
-            }
-
-            private void SetRedirection()
-            {
-                if (!_handler._automaticRedirection)
-                {
-                    return;
-                }
-
-                SetCurlOption(CURLoption.CURLOPT_FOLLOWLOCATION, 1L);
-
-                CurlProtocols redirectProtocols = string.Equals(_requestMessage.RequestUri.Scheme, UriSchemeHttps, StringComparison.OrdinalIgnoreCase) ?
-                    CurlProtocols.CURLPROTO_HTTPS : // redirect only to another https
-                    CurlProtocols.CURLPROTO_HTTP | CurlProtocols.CURLPROTO_HTTPS; // redirect to http or to https
-                SetCurlOption(CURLoption.CURLOPT_REDIR_PROTOCOLS, (long)redirectProtocols);
-
-                SetCurlOption(CURLoption.CURLOPT_MAXREDIRS, _handler._maxAutomaticRedirections);
-                EventSourceTrace("Max automatic redirections: {0}", _handler._maxAutomaticRedirections);
-            }
-
-            /// <summary>
-            /// When a Location header is received along with a 3xx status code, it's an indication
-            /// that we're likely to redirect.  Prepare the easy handle in case we do.
-            /// </summary>
-            internal void SetPossibleRedirectForLocationHeader(string location)
-            {
-                // Reset cookies in case we redirect.  Below we'll set new cookies for the
-                // new location if we have any.
-                if (_handler._useCookies)
-                {
-                    SetCurlOption(CURLoption.CURLOPT_COOKIE, IntPtr.Zero);
-                }
-
-                // Parse the location string into a relative or absolute Uri, then combine that
-                // with the current request Uri to get the new location.
-                var updatedCredentials = default(KeyValuePair<NetworkCredential, CURLAUTH>);
-                Uri newUri;
-                if (Uri.TryCreate(_requestMessage.RequestUri, location.Trim(), out newUri))
-                {
-                    // Just as with WinHttpHandler, for security reasons, we drop the server credential if it is
-                    // anything other than a CredentialCache. We allow credentials in a CredentialCache since they
-                    // are specifically tied to URIs.
-                    updatedCredentials = _handler._useDefaultCredentials ?
-                        GetDefaultCredentialAndAuth() :
-                        GetCredentials(newUri, _handler.Credentials as CredentialCache, s_orderedAuthTypes);
-
-                    // Reset proxy - it is possible that the proxy has different credentials for the new URI
-                    SetProxyOptions(newUri);
-
-                    // Set up new cookies
-                    if (_handler._useCookies)
-                    {
-                        SetCookieOption(newUri);
-                    }
-
-                    if (newUri.Scheme == Uri.UriSchemeHttp && _requestMessage.RequestUri.Scheme == Uri.UriSchemeHttps)
-                    {
-                        EventSourceTrace("Insecure https to http redirect: {0}", (_requestMessage.RequestUri, newUri));
-                    }
-                }
-
-                // Set up the new credentials, either for the new Uri if we were able to get it,
-                // or to empty creds if we couldn't.
-                SetCredentialsOptions(updatedCredentials);
-
-                // Set the headers again. This is a workaround for libcurl's limitation in handling
-                // headers with empty values.
-                SetRequestHeaders(copyAuthHeaders:false);
-            }
-
-            private void SetContentLength(CURLoption lengthOption)
-            {
-                Debug.Assert(lengthOption == CURLoption.CURLOPT_POSTFIELDSIZE || lengthOption == CURLoption.CURLOPT_INFILESIZE);
-
-                if (_requestMessage.Content == null)
-                {
-                    // Tell libcurl there's no data to be sent.
-                    SetCurlOption(lengthOption, 0L);
-                    return;
-                }
-
-                long? contentLengthOpt = _requestMessage.Content.Headers.ContentLength;
-                if (contentLengthOpt != null)
-                {
-                    long contentLength = contentLengthOpt.GetValueOrDefault();
-                    if (contentLength <= int.MaxValue)
-                    {
-                        // Tell libcurl how much data we expect to send.
-                        SetCurlOption(lengthOption, contentLength);
-                    }
-                    else
-                    {
-                        // Similarly, tell libcurl how much data we expect to send.  However,
-                        // as the amount is larger than a 32-bit value, switch to the "_LARGE"
-                        // equivalent libcurl options.
-                        SetCurlOption(
-                            lengthOption == CURLoption.CURLOPT_INFILESIZE ? CURLoption.CURLOPT_INFILESIZE_LARGE : CURLoption.CURLOPT_POSTFIELDSIZE_LARGE,
-                            contentLength);
-                    }
-                    EventSourceTrace("Set content length: {0}", contentLength);
-                    return;
-                }
-
-                // There is content but we couldn't determine its size.  Don't set anything.
-            }
-
-            private void SetVerb()
-            {
-                EventSourceTrace<string>("Verb: {0}", _requestMessage.Method.Method);
-
-                if (_requestMessage.Method == HttpMethod.Put)
-                {
-                    SetCurlOption(CURLoption.CURLOPT_UPLOAD, 1L);
-                    SetContentLength(CURLoption.CURLOPT_INFILESIZE);
-                }
-                else if (_requestMessage.Method == HttpMethod.Head)
-                {
-                    SetCurlOption(CURLoption.CURLOPT_NOBODY, 1L);
-                }
-                else if (_requestMessage.Method == HttpMethod.Post)
-                {
-                    SetCurlOption(CURLoption.CURLOPT_POST, 1L);
-
-                    // Set the content length if we have one available. We must set POSTFIELDSIZE before setting
-                    // COPYPOSTFIELDS, as the setting of COPYPOSTFIELDS uses the size to know how much data to read
-                    // out; if POSTFIELDSIZE is not done before, COPYPOSTFIELDS will look for a null terminator, and
-                    // we don't necessarily have one.
-                    SetContentLength(CURLoption.CURLOPT_POSTFIELDSIZE);
-
-                    // For most content types and most HTTP methods, we use a callback that lets libcurl
-                    // get data from us if/when it wants it.  However, as an optimization, for POSTs that
-                    // use content already known to be entirely in memory, we hand that data off to libcurl
-                    // ahead of time.  This not only saves on costs associated with all of the async transfer
-                    // between the content and libcurl, it also lets libcurl do larger writes that can, for
-                    // example, enable fewer packets to be sent on the wire.
-                    var inMemContent = _requestMessage.Content as ByteArrayContent;
-                    ArraySegment<byte> contentSegment;
-                    if (inMemContent != null &&
-                        inMemContent.TryGetBuffer(out contentSegment) &&
-                        contentSegment.Count <= InMemoryPostContentLimit) // skip if we'd be forcing libcurl to allocate/copy a large buffer
-                    {
-                        // Only pre-provide the content if the content still has its ContentLength
-                        // and if that length matches the segment.  If it doesn't, something has been overridden,
-                        // and we should rely on reading from the content stream to get the data.
-                        long? contentLength = inMemContent.Headers.ContentLength;
-                        if (contentLength.HasValue && contentLength.GetValueOrDefault() == contentSegment.Count)
-                        {
-                            _inMemoryPostContent = true;
-
-                            // Debug double-check array segment; this should all have been validated by the ByteArrayContent
-                            Debug.Assert(contentSegment.Array != null, "Expected non-null byte content array");
-                            Debug.Assert(contentSegment.Count >= 0, $"Expected non-negative byte content count {contentSegment.Count}");
-                            Debug.Assert(contentSegment.Offset >= 0, $"Expected non-negative byte content offset {contentSegment.Offset}");
-                            Debug.Assert(contentSegment.Array.Length - contentSegment.Offset >= contentSegment.Count,
-                                $"Expected offset {contentSegment.Offset} + count {contentSegment.Count} to be within array length {contentSegment.Array.Length}");
-
-                            // Hand the data off to libcurl with COPYPOSTFIELDS for it to copy out the data. (The alternative
-                            // is to use POSTFIELDS, which would mean we'd need to pin the array in the ByteArrayContent for the
-                            // duration of the request.  Often with a ByteArrayContent, the data will be small and the copy cheap.)
-                            unsafe
-                            {
-                                fixed (byte* inMemContentPtr = contentSegment.Array)
-                                {
-                                    SetCurlOption(CURLoption.CURLOPT_COPYPOSTFIELDS, new IntPtr(inMemContentPtr + contentSegment.Offset));
-                                    EventSourceTrace("Set post fields rather than using send content callback");
-                                }
-                            }
-                        }
-                    }
-                }
-                else if (_requestMessage.Method == HttpMethod.Trace)
-                {
-                    SetCurlOption(CURLoption.CURLOPT_CUSTOMREQUEST, _requestMessage.Method.Method);
-                    SetCurlOption(CURLoption.CURLOPT_NOBODY, 1L);
-                }
-                else
-                {
-                    SetCurlOption(CURLoption.CURLOPT_CUSTOMREQUEST, _requestMessage.Method.Method);
-                    if (_requestMessage.Content != null)
-                    {
-                        SetCurlOption(CURLoption.CURLOPT_UPLOAD, 1L);
-                        SetContentLength(CURLoption.CURLOPT_INFILESIZE);
-                    }
-                }
-            }
-
-            private void SetVersion()
-            {
-                Version v = _requestMessage.Version;
-                if (v != null)
-                {
-                    // Try to use the requested version, if a known version was explicitly requested.
-                    // If an unknown version was requested, we simply use libcurl's default.
-                    // Only allow HTTP/2 when making https requests.
-                    var curlVersion =
-                        (v.Major == 1 && v.Minor == 1) ? Interop.Http.CurlHttpVersion.CURL_HTTP_VERSION_1_1 :
-                        (v.Major == 1 && v.Minor == 0) ? Interop.Http.CurlHttpVersion.CURL_HTTP_VERSION_1_0 :
-                        (v.Major == 2 && v.Minor == 0) ? Interop.Http.CurlHttpVersion.CURL_HTTP_VERSION_2TLS :
-                        Interop.Http.CurlHttpVersion.CURL_HTTP_VERSION_NONE;
-
-                    if (curlVersion != Interop.Http.CurlHttpVersion.CURL_HTTP_VERSION_NONE)
-                    {
-                        // Ask libcurl to use the specified version if possible.
-                        CURLcode c = Interop.Http.EasySetOptionLong(_easyHandle, CURLoption.CURLOPT_HTTP_VERSION, (long)curlVersion);
-                        if (c == CURLcode.CURLE_OK)
-                        {
-                            // Success.  The requested version will be used.
-                            EventSourceTrace("HTTP version: {0}", v);
-                        }
-                        else if (c == CURLcode.CURLE_UNSUPPORTED_PROTOCOL)
-                        {
-                            // The requested version is unsupported.  Fall back to using the default version chosen by libcurl.
-                            EventSourceTrace("Unsupported protocol: {0}", v);
-                        }
-                        else
-                        {
-                            // Some other error. Fail.
-                            ThrowIfCURLEError(c);
-                        }
-                    }
-                }
-            }
-
-            private void SetDecompressionOptions()
-            {
-                if (!_handler.SupportsAutomaticDecompression)
-                {
-                    return;
-                }
-
-                DecompressionMethods autoDecompression = _handler.AutomaticDecompression;
-                bool gzip = (autoDecompression & DecompressionMethods.GZip) != 0;
-                bool deflate = (autoDecompression & DecompressionMethods.Deflate) != 0;
-                if (gzip || deflate)
-                {
-                    string encoding = (gzip && deflate) ? EncodingNameGzip + "," + EncodingNameDeflate :
-                                       gzip ? EncodingNameGzip :
-                                       EncodingNameDeflate;
-                    SetCurlOption(CURLoption.CURLOPT_ACCEPT_ENCODING, encoding);
-                    EventSourceTrace<string>("Encoding: {0}", encoding);
-                }
-            }
-
-            internal void SetProxyOptions(Uri requestUri)
-            {
-                if (!_handler._useProxy)
-                {
-                    // Explicitly disable the use of a proxy.  This will prevent libcurl from using
-                    // any proxy, including ones set via environment variable.
-                    SetCurlOption(CURLoption.CURLOPT_PROXY, string.Empty);
-                    EventSourceTrace("UseProxy false, disabling proxy");
-                    return;
-                }
-
-                if (_handler.Proxy == null)
-                {
-                    // UseProxy was true, but Proxy was null.  Let libcurl do its default handling,
-                    // which includes checking the http_proxy environment variable.
-                    EventSourceTrace("UseProxy true, Proxy null, using default proxy");
-
-                    // Since that proxy set in an environment variable might require a username and password,
-                    // use the default proxy credentials if there are any.  Currently only NetworkCredentials
-                    // are used, as we can't query by the proxy Uri, since we don't know it.
-                    SetProxyCredentials(_handler.DefaultProxyCredentials as NetworkCredential);
-
-                    return;
-                }
-
-                // Custom proxy specified.
-                Uri proxyUri;
-                try
-                {
-                    // Should we bypass a proxy for this URI?
-                    if (_handler.Proxy.IsBypassed(requestUri))
-                    {
-                        SetCurlOption(CURLoption.CURLOPT_PROXY, string.Empty);
-                        EventSourceTrace("Proxy's IsBypassed returned true, bypassing proxy");
-                        return;
-                    }
-
-                    // Get the proxy Uri for this request.
-                    proxyUri = _handler.Proxy.GetProxy(requestUri);
-                    if (proxyUri == null)
-                    {
-                        EventSourceTrace("GetProxy returned null, using default.");
-                        return;
-                    }
-                }
-                catch (PlatformNotSupportedException)
-                {
-                    // WebRequest.DefaultWebProxy throws PlatformNotSupportedException,
-                    // in which case we should use the default rather than the custom proxy.
-                    EventSourceTrace("PlatformNotSupportedException from proxy, using default");
-                    return;
-                }
-
-                // Configure libcurl with the gathered proxy information
-
-                // uri.AbsoluteUri/ToString() omit IPv6 scope IDs.  SerializationInfoString ensures these details
-                // are included, but does not properly handle international hosts.  As a workaround we check whether
-                // the host is a link-local IP address, and based on that either return the SerializationInfoString
-                // or the AbsoluteUri. (When setting the request Uri itself, we instead use CURLOPT_ADDRESS_SCOPE to
-                // set the scope id and the url separately, avoiding these issues and supporting versions of libcurl
-                // prior to v7.37 that don't support parsing scope IDs out of the url's host.  As similar feature
-                // doesn't exist for proxies.)
-                IPAddress ip;
-                string proxyUrl = IPAddress.TryParse(proxyUri.DnsSafeHost, out ip) && ip.IsIPv6LinkLocal ?
-                    proxyUri.GetComponents(UriComponents.SerializationInfoString, UriFormat.UriEscaped) :
-                    proxyUri.AbsoluteUri;
-
-                EventSourceTrace<string>("Proxy: {0}", proxyUrl);
-                SetCurlOption(CURLoption.CURLOPT_PROXYTYPE, (long)CURLProxyType.CURLPROXY_HTTP);
-                SetCurlOption(CURLoption.CURLOPT_PROXY, proxyUrl);
-                SetCurlOption(CURLoption.CURLOPT_PROXYPORT, proxyUri.Port);
-
-                KeyValuePair<NetworkCredential, CURLAUTH> credentialScheme = GetCredentials(
-                    proxyUri, _handler.Proxy.Credentials, s_orderedAuthTypes);
-                SetProxyCredentials(credentialScheme.Key);
-            }
-
-            private void SetProxyCredentials(NetworkCredential credentials)
-            {
-                if (credentials == CredentialCache.DefaultCredentials)
-                {
-                    EventSourceTrace("DefaultCredentials set for proxy. Skipping.");
-                }
-                else if (credentials != null)
-                {
-                    if (string.IsNullOrEmpty(credentials.UserName))
-                    {
-                        throw new ArgumentException(SR.net_http_argument_empty_string, "UserName");
-                    }
-
-                    // Unlike normal credentials, proxy credentials are URL decoded by libcurl, so we URL encode
-                    // them in order to allow, for example, a colon in the username.
-                    string credentialText = string.IsNullOrEmpty(credentials.Domain) ?
-                        WebUtility.UrlEncode(credentials.UserName) + ":" + WebUtility.UrlEncode(credentials.Password) :
-                        string.Format("{2}\\{0}:{1}", WebUtility.UrlEncode(credentials.UserName), WebUtility.UrlEncode(credentials.Password), WebUtility.UrlEncode(credentials.Domain));
-
-                    EventSourceTrace("Proxy credentials set.");
-                    SetCurlOption(CURLoption.CURLOPT_PROXYUSERPWD, credentialText);
-                }
-            }
-
-            internal void SetCredentialsOptions(KeyValuePair<NetworkCredential, CURLAUTH> credentialSchemePair)
-            {
-                if (credentialSchemePair.Key == null)
-                {
-                    EventSourceTrace("Credentials cleared.");
-                    SetCurlOption(CURLoption.CURLOPT_USERNAME, IntPtr.Zero);
-                    SetCurlOption(CURLoption.CURLOPT_PASSWORD, IntPtr.Zero);
-                    return;
-                }
-
-                NetworkCredential credentials = credentialSchemePair.Key;
-                CURLAUTH authScheme = credentialSchemePair.Value;
-                string userName = string.IsNullOrEmpty(credentials.Domain) ?
-                    credentials.UserName :
-                    credentials.Domain + "\\" + credentials.UserName;
-
-                SetCurlOption(CURLoption.CURLOPT_USERNAME, userName);
-                SetCurlOption(CURLoption.CURLOPT_HTTPAUTH, (long)authScheme);
-                if (credentials.Password != null)
-                {
-                    SetCurlOption(CURLoption.CURLOPT_PASSWORD, credentials.Password);
-                }
-
-                EventSourceTrace("Credentials set.");
-            }
-
-            private static KeyValuePair<NetworkCredential, CURLAUTH> GetDefaultCredentialAndAuth() =>
-                new KeyValuePair<NetworkCredential, CURLAUTH>(CredentialCache.DefaultNetworkCredentials, CURLAUTH.Negotiate);
-
-            internal void SetCookieOption(Uri uri)
-            {
-                if (!_handler._useCookies)
-                {
-                    return;
-                }
-
-                string cookieValues = _handler.CookieContainer.GetCookieHeader(uri);
-                if (!string.IsNullOrEmpty(cookieValues))
-                {
-                    SetCurlOption(CURLoption.CURLOPT_COOKIE, cookieValues);
-                    EventSourceTrace<string>("Cookies: {0}", cookieValues);
-                }
-            }
-
-            internal void SetRequestHeaders(bool copyAuthHeaders)
-            {
-                var slist = new SafeCurlSListHandle();
-
-                bool suppressContentType;
-                if (_requestMessage.Content != null)
-                {
-                    // Add content request headers
-                    AddRequestHeaders(_requestMessage.Content.Headers, slist, copyAuthHeaders);
-                    suppressContentType = _requestMessage.Content.Headers.ContentType == null;
-                }
-                else
-                {
-                    suppressContentType = true;
-                }
-
-                if (suppressContentType)
-                {
-                    // Remove the Content-Type header libcurl adds by default.
-                    ThrowOOMIfFalse(Interop.Http.SListAppend(slist, NoContentType));
-                }
-
-                // Add request headers
-                AddRequestHeaders(_requestMessage.Headers, slist, copyAuthHeaders);
-
-                // Since libcurl always adds a Transfer-Encoding header, we need to explicitly block
-                // it if caller specifically does not want to set the header
-                if (_requestMessage.Headers.TransferEncodingChunked.HasValue &&
-                    !_requestMessage.Headers.TransferEncodingChunked.Value)
-                {
-                    ThrowOOMIfFalse(Interop.Http.SListAppend(slist, NoTransferEncoding));
-                }
-
-                // Since libcurl adds an Expect header if it sees enough post data, we need to explicitly block
-                // it unless the caller has explicitly opted-in to it.
-                if (!_requestMessage.Headers.ExpectContinue.GetValueOrDefault())
-                {
-                    ThrowOOMIfFalse(Interop.Http.SListAppend(slist, NoExpect));
-                }
-
-                if (!slist.IsInvalid)
-                {
-                    SafeCurlSListHandle prevList = _requestHeaders;
-                    _requestHeaders = slist;
-                    SetCurlOption(CURLoption.CURLOPT_HTTPHEADER, slist);
-                    prevList?.Dispose();
-                }
-                else
-                {
-                    slist.Dispose();
-                }
-            }
-
-            private void SetSslOptions()
-            {
-                // SSL Options should be set regardless of the type of the original request,
-                // in case an http->https redirection occurs.
-                //
-                // While this does slow down the theoretical best path of the request the code
-                // to decide that we need to register the callback is more complicated than, and
-                // potentially more expensive than, just always setting the callback.
-                SslProvider.SetSslOptions(this, _handler.ClientCertificateOptions);
-            }
-
-            internal bool ServerCertificateValidationCallbackAcceptsAll => ReferenceEquals(
-                _handler.ServerCertificateCustomValidationCallback,
-                HttpClientHandler.DangerousAcceptAnyServerCertificateValidator);
-
-            internal void SetCurlCallbacks(
-                IntPtr easyGCHandle,
-                ReadWriteCallback receiveHeadersCallback,
-                ReadWriteCallback sendCallback,
-                SeekCallback seekCallback,
-                ReadWriteCallback receiveBodyCallback,
-                DebugCallback debugCallback)
-            {
-                if (_callbackHandle == null)
-                {
-                    _callbackHandle = new SafeCallbackHandle();
-                }
-
-                // Add callback for processing headers
-                Interop.Http.RegisterReadWriteCallback(
-                    _easyHandle,
-                    ReadWriteFunction.Header,
-                    receiveHeadersCallback,
-                    easyGCHandle,
-                    ref _callbackHandle);
-                ThrowOOMIfInvalid(_callbackHandle);
-
-                // If we're sending data as part of the request and it wasn't already added as
-                // in-memory data, add callbacks for sending request data.
-                if (!_inMemoryPostContent && _requestMessage.Content != null)
-                {
-                    Interop.Http.RegisterReadWriteCallback(
-                        _easyHandle,
-                        ReadWriteFunction.Read,
-                        sendCallback,
-                        easyGCHandle,
-                        ref _callbackHandle);
-                    Debug.Assert(!_callbackHandle.IsInvalid, $"Should have been allocated (or failed) when originally adding handlers");
-
-                    Interop.Http.RegisterSeekCallback(
-                        _easyHandle,
-                        seekCallback,
-                        easyGCHandle,
-                        ref _callbackHandle);
-                    Debug.Assert(!_callbackHandle.IsInvalid, $"Should have been allocated (or failed) when originally adding handlers");
-                }
-
-                // If we're expecting any data in response, add a callback for receiving body data
-                if (_requestMessage.Method != HttpMethod.Head)
-                {
-                    Interop.Http.RegisterReadWriteCallback(
-                        _easyHandle,
-                        ReadWriteFunction.Write,
-                        receiveBodyCallback,
-                        easyGCHandle,
-                        ref _callbackHandle);
-                    Debug.Assert(!_callbackHandle.IsInvalid, $"Should have been allocated (or failed) when originally adding handlers");
-                }
-
-                if (NetEventSource.IsEnabled)
-                {
-                    SetCurlOption(CURLoption.CURLOPT_VERBOSE, 1L);
-                    CURLcode curlResult = Interop.Http.RegisterDebugCallback(
-                        _easyHandle,
-                        debugCallback,
-                        easyGCHandle,
-                        ref _callbackHandle);
-                    Debug.Assert(!_callbackHandle.IsInvalid, $"Should have been allocated (or failed) when originally adding handlers");
-                    if (curlResult != CURLcode.CURLE_OK)
-                    {
-                        EventSourceTrace("Failed to register debug callback.");
-                    }
-                }
-            }
-
-            internal CURLcode SetSslCtxCallback(SslCtxCallback callback, IntPtr userPointer)
-            {
-                if (_callbackHandle == null)
-                {
-                    _callbackHandle = new SafeCallbackHandle();
-                }
-
-                return Interop.Http.RegisterSslCtxCallback(_easyHandle, callback, userPointer, ref _callbackHandle);
-            }
-
-            private static void AddRequestHeaders(HttpHeaders headers, SafeCurlSListHandle handle, bool copyAuthHeaders)
-            {
-                foreach (KeyValuePair<string, IEnumerable<string>> header in headers)
-                {
-                    if (string.Equals(header.Key, HttpKnownHeaderNames.ContentLength, StringComparison.OrdinalIgnoreCase) ||
-                        (!copyAuthHeaders && string.Equals(header.Key, HttpKnownHeaderNames.Authorization, StringComparison.OrdinalIgnoreCase)))
-                    {
-                        // avoid overriding libcurl's handling via INFILESIZE/POSTFIELDSIZE
-                        continue;
-                    }
-
-                    string headerKeyAndValue;
-                    string[] values = header.Value as string[];
-                    Debug.Assert(values != null, "Implementation detail, but expected Value to be a string[]");
-                    if (values != null && values.Length < 2)
-                    {
-                        // 0 or 1 values
-                        headerKeyAndValue = values.Length == 0 || string.IsNullOrEmpty(values[0]) ?
-                            header.Key + ";" : // semicolon used by libcurl to denote empty value that should be sent
-                            header.Key + ": " + values[0];
-                    }
-                    else
-                    {
-                        // Either Values wasn't a string[], or it had 2 or more items. Both are handled by GetHeaderString.
-                        string headerValue = headers.GetHeaderString(header.Key);
-                        headerKeyAndValue = string.IsNullOrEmpty(headerValue) ?
-                            header.Key + ";" : // semicolon needed by libcurl; see above
-                            header.Key + ": " + headerValue;
-                    }
-
-                    ThrowOOMIfFalse(Interop.Http.SListAppend(handle, headerKeyAndValue));
-                }
-            }
-
-            internal void SetCurlOption(CURLoption option, string value)
-            {
-                ThrowIfCURLEError(Interop.Http.EasySetOptionString(_easyHandle, option, value));
-            }
-
-            internal CURLcode TrySetCurlOption(CURLoption option, string value)
-            {
-                return Interop.Http.EasySetOptionString(_easyHandle, option, value);
-            }
-
-            internal void SetCurlOption(CURLoption option, long value)
-            {
-                ThrowIfCURLEError(Interop.Http.EasySetOptionLong(_easyHandle, option, value));
-            }
-
-            internal void SetCurlOption(CURLoption option, IntPtr value)
-            {
-                ThrowIfCURLEError(Interop.Http.EasySetOptionPointer(_easyHandle, option, value));
-            }
-
-            internal void SetCurlOption(CURLoption option, SafeHandle value)
-            {
-                ThrowIfCURLEError(Interop.Http.EasySetOptionPointer(_easyHandle, option, value));
-            }
-
-            private static void ThrowOOMIfFalse(bool appendResult)
-            {
-                if (!appendResult)
-                {
-                    ThrowOOM();
-                }
-            }
-
-            private static void ThrowOOMIfInvalid(SafeHandle handle)
-            {
-                if (handle.IsInvalid)
-                {
-                    ThrowOOM();
-                }
-            }
-
-            private static void ThrowOOM()
-            {
-                throw CreateHttpRequestException(new CurlException((int)CURLcode.CURLE_OUT_OF_MEMORY, isMulti: false));
-            }
-
-            internal sealed class SendTransferState : IDisposable
-            {
-                internal byte[] Buffer { get; private set; }
-                internal int Offset { get; set; }
-                internal int Count { get; set; }
-                internal Task<int> Task { get; private set; }
-
-                public SendTransferState(int bufferLength)
-                {
-                    Debug.Assert(bufferLength > 0 && bufferLength <= MaxRequestBufferSize, $"Expected 0 < bufferLength <= {MaxRequestBufferSize}, got {bufferLength}");
-                    Buffer = ArrayPool<byte>.Shared.Rent(bufferLength);
-                }
-
-                public void Dispose()
-                {
-                    byte[] b = Buffer;
-                    if (b != null)
-                    {
-                        Buffer = null;
-                        ArrayPool<byte>.Shared.Return(b);
-                    }
-                }
-
-                public void SetTaskOffsetCount(Task<int> task, int offset, int count)
-                {
-                    Debug.Assert(offset >= 0, "Offset should never be negative");
-                    Debug.Assert(count >= 0, "Count should never be negative");
-                    Debug.Assert(offset <= count, "Offset should never be greater than count");
-
-                    Task = task;
-                    Offset = offset;
-                    Count = count;
-                }
-            }
-
-            internal void StoreLastEffectiveUri()
-            {
-                IntPtr urlCharPtr; // do not free; will point to libcurl private memory
-                CURLcode urlResult = Interop.Http.EasyGetInfoPointer(_easyHandle, Interop.Http.CURLINFO.CURLINFO_EFFECTIVE_URL, out urlCharPtr);
-                if (urlResult == CURLcode.CURLE_OK && urlCharPtr != IntPtr.Zero)
-                {
-                    string url = Marshal.PtrToStringAnsi(urlCharPtr);
-                    if (url != _requestMessage.RequestUri.OriginalString)
-                    {
-                        Uri finalUri;
-                        if (Uri.TryCreate(url, UriKind.Absolute, out finalUri))
-                        {
-                            _requestMessage.RequestUri = finalUri;
-                        }
-                    }
-                    return;
-                }
-
-                Debug.Fail("Expected to be able to get the last effective Uri from libcurl");
-            }
-
-            private void EventSourceTrace<TArg0>(string formatMessage, TArg0 arg0, [CallerMemberName] string memberName = null)
-            {
-                CurlHandler.EventSourceTrace(formatMessage, arg0, easy: this, memberName: memberName);
-            }
-
-            private void EventSourceTrace(string message, [CallerMemberName] string memberName = null)
-            {
-                CurlHandler.EventSourceTrace(message, easy: this, memberName: memberName);
-            }
-        }
-    }
-}
diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/CurlHandler/CurlHandler.MultiAgent.cs b/src/libraries/System.Net.Http/src/System/Net/Http/CurlHandler/CurlHandler.MultiAgent.cs
deleted file mode 100644 (file)
index 2485084..0000000
+++ /dev/null
@@ -1,1429 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.IO;
-using System.Runtime.CompilerServices;
-using System.Runtime.ExceptionServices;
-using System.Runtime.InteropServices;
-using System.Threading;
-using System.Threading.Tasks;
-using Microsoft.Win32.SafeHandles;
-
-using CURLcode = Interop.Http.CURLcode;
-using CURLMcode = Interop.Http.CURLMcode;
-using CURLINFO = Interop.Http.CURLINFO;
-
-namespace System.Net.Http
-{
-    internal partial class CurlHandler : HttpMessageHandler
-    {
-        /// <summary>Provides a multi handle and the associated processing for all requests on the handle.</summary>
-        private sealed class MultiAgent : IDisposable
-        {
-            /// <summary>
-            /// Amount of time in milliseconds to keep a multiagent worker alive when there's no work to be done.
-            /// Increasing this value makes it more likely that a worker will end up getting reused for subsequent
-            /// requests, saving on the costs associated with spinning up a new worker, but at the same time it
-            /// burns a thread for that period of time.
-            /// </summary>
-            private const int KeepAliveMilliseconds = 50;
-
-            private static readonly Interop.Http.ReadWriteCallback s_receiveHeadersCallback = CurlReceiveHeadersCallback;
-            private static readonly Interop.Http.ReadWriteCallback s_sendCallback = CurlSendCallback;
-            private static readonly Interop.Http.SeekCallback s_seekCallback = CurlSeekCallback;
-            private static readonly Interop.Http.ReadWriteCallback s_receiveBodyCallback = CurlReceiveBodyCallback;
-            private static readonly Interop.Http.DebugCallback s_debugCallback = CurlDebugFunction;
-
-            /// <summary>CurlHandler that created this MultiAgent.  If null, this is a shared handler.</summary>
-            private readonly CurlHandler _creatingHandler;
-
-            /// <summary>
-            /// A collection of not-yet-processed incoming requests for work to be done
-            /// by this multi agent.  This can include making new requests, canceling
-            /// active requests, or unpausing active requests.
-            /// Protected by a lock on <see cref="_incomingRequests"/>.
-            /// </summary>
-            private readonly Queue<IncomingRequest> _incomingRequests = new Queue<IncomingRequest>();
-
-            /// <summary>Map of activeOperations, indexed by a GCHandle to a StrongToWeakReference{EasyRequest}.</summary>
-            private readonly Dictionary<IntPtr, ActiveRequest> _activeOperations = new Dictionary<IntPtr, ActiveRequest>();
-
-            /// <summary>
-            /// Special file descriptor used to wake-up curl_multi_wait calls.  This is the read
-            /// end of a pipe, with the write end written to when work is queued or when cancellation
-            /// is requested. This is only valid while the worker is executing.
-            /// </summary>
-            private SafeFileHandle _wakeupRequestedPipeFd;
-
-            /// <summary>
-            /// Write end of the pipe connected to <see cref="_wakeupRequestedPipeFd"/>.
-            /// This is only valid while the worker is executing.
-            /// </summary>
-            private SafeFileHandle _requestWakeupPipeFd;
-
-            /// <summary>
-            /// Task for the currently running worker, or null if there is no current worker.
-            /// Protected by a lock on <see cref="_incomingRequests"/>.
-            /// </summary>
-            private Task _runningWorker;
-
-            /// <summary>
-            /// Multi handle used to service all requests on this agent.  It's lazily
-            /// created when it's first needed, so that it can utilize all of the settings
-            /// from the associated handler, and it's kept open for the duration of this
-            /// agent so that all of the resources it pools (connection pool, DNS cache, etc.)
-            /// can be used for all requests on this agent.
-            /// </summary>
-            private Interop.Http.SafeCurlMultiHandle _multiHandle;
-
-            /// <summary>Set when Dispose has been called.</summary>
-            private bool _disposed;
-
-            /// <summary>Initializes the MultiAgent.</summary>
-            /// <param name="handler">The handler that created this agent, or null if it's shared.</param>
-            public MultiAgent(CurlHandler handler)
-            {
-                _creatingHandler = handler;
-            }
-
-            /// <summary>Disposes of the agent.</summary>
-            public void Dispose()
-            {
-                EventSourceTrace(null);
-                _disposed = true;
-                QueueIfRunning(new IncomingRequest { Type = IncomingRequestType.Shutdown });
-                _multiHandle?.Dispose();
-            }
-
-            /// <summary>Queues a request for the multi handle to process.</summary>
-            public void Queue(IncomingRequest request)
-            {
-                lock (_incomingRequests)
-                {
-                    // Add the request, then initiate processing.
-                    _incomingRequests.Enqueue(request);
-                    EnsureWorkerIsRunning();
-                }
-            }
-
-            /// <summary>Queues a request for the multi handle to process, but only if there's already an active worker running.</summary>
-            public void QueueIfRunning(IncomingRequest request)
-            {
-                lock (_incomingRequests)
-                {
-                    if (_runningWorker != null)
-                    {
-                        _incomingRequests.Enqueue(request);
-                        if (_incomingRequests.Count == 1)
-                        {
-                            RequestWakeup();
-                        }
-                    }
-                }
-            }
-
-            /// <summary>Gets the ID of the currently running worker, or null if there isn't one.</summary>
-            internal int? RunningWorkerId => _runningWorker?.Id;
-
-            /// <summary>Schedules the processing worker if one hasn't already been scheduled.</summary>
-            private void EnsureWorkerIsRunning()
-            {
-                Debug.Assert(Monitor.IsEntered(_incomingRequests), "Needs to be called under _incomingRequests lock");
-
-                if (_runningWorker == null)
-                {
-                    EventSourceTrace("MultiAgent worker queueing");
-
-                    // Ensure we've created the multi handle for this agent.
-                    if (_multiHandle == null)
-                    {
-                        _multiHandle = CreateAndConfigureMultiHandle();
-                    }
-
-                    // Create pipe used to forcefully wake up curl_multi_wait calls when something important changes.
-                    // This is created here so that the pipe is available immediately for subsequent queue calls to use.
-                    Debug.Assert(_wakeupRequestedPipeFd == null, "Read pipe should have been cleared");
-                    Debug.Assert(_requestWakeupPipeFd == null, "Write pipe should have been cleared");
-                    unsafe
-                    {
-                        int* fds = stackalloc int[2];
-                        Interop.CheckIo(Interop.Sys.Pipe(fds));
-                        _wakeupRequestedPipeFd = new SafeFileHandle((IntPtr)fds[Interop.Sys.ReadEndOfPipe], true);
-                        _requestWakeupPipeFd = new SafeFileHandle((IntPtr)fds[Interop.Sys.WriteEndOfPipe], true);
-                    }
-
-                    // Create the processing task.  It's "DenyChildAttach" to avoid any surprises if
-                    // code happens to create attached tasks, and it's LongRunning because this thread
-                    // is likely going to sit around for a while in a wait loop (and the more requests
-                    // are concurrently issued to the same agent, the longer the thread will be around).
-                    _runningWorker = new Task(s => ((MultiAgent)s).WorkerBody(), this,
-                        CancellationToken.None, TaskCreationOptions.DenyChildAttach | TaskCreationOptions.LongRunning);
-
-                    // We want to avoid situations where a Dispose occurs while we're in the middle
-                    // of processing requests and causes us to tear out the multi handle while it's
-                    // in active use.  To avoid that, we add-ref it here, and release it at the end
-                    // of the worker loop.
-                    bool ignored = false;
-                    _multiHandle.DangerousAddRef(ref ignored);
-
-                    // Kick off the processing task.  This is done after both setting _runningWorker
-                    // to non-null and add-refing the handle, both to avoid race conditions.  The worker
-                    // body needs to see _runningWorker as non-null and assumes that it's free to use
-                    // the multi handle, without fear of it having been disposed.
-                    _runningWorker.Start(TaskScheduler.Default);
-                }
-                else // _runningWorker != null
-                {
-                    // The worker is already running.  If there are already queued requests, we're done.
-                    // However, if there aren't any queued requests, Process could be blocked inside of
-                    // curl_multi_wait, and we want to make sure it wakes up to see that there additional
-                    // requests waiting to be handled.  So we write to the wakeup pipe.
-                    Debug.Assert(_incomingRequests.Count >= 1, "We just queued a request, so the count should be at least 1");
-                    if (_incomingRequests.Count == 1)
-                    {
-                        RequestWakeup();
-                    }
-                }
-            }
-
-            /// <summary>Write a byte to the wakeup pipe.</summary>
-            private unsafe void RequestWakeup()
-            {
-                EventSourceTrace(null);
-                byte b = 1;
-                Interop.CheckIo(Interop.Sys.Write(_requestWakeupPipeFd, &b, 1));
-            }
-
-            /// <summary>Clears data from the wakeup pipe.</summary>
-            /// <remarks>
-            /// This must only be called when we know there's data to be read.
-            /// The MultiAgent could easily deadlock if it's called when there's no data in the pipe.
-            /// </remarks>
-            private unsafe void ReadFromWakeupPipeWhenKnownToContainData()
-            {
-                // It's possible but unlikely that there will be tons of extra data in the pipe,
-                // more than we end up reading out here (it's unlikely because we only write a byte to the pipe when
-                // transitioning from 0 to 1 incoming request).  In that unlikely event, the worst
-                // case will be that the next one or more waits will wake up immediately, with each one
-                // subsequently clearing out more of the pipe.
-                const int ClearBufferSize = 64; // sufficiently large to clear the pipe in any normal case
-                byte* clearBuf = stackalloc byte[ClearBufferSize];
-                Interop.CheckIo(Interop.Sys.Read(_wakeupRequestedPipeFd, clearBuf, ClearBufferSize));
-            }
-
-            /// <summary>Requests that libcurl unpause the connection associated with this request.</summary>
-            internal void RequestUnpause(EasyRequest easy)
-            {
-                EventSourceTrace(null, easy: easy);
-                QueueIfRunning(new IncomingRequest { Easy = easy, Type = IncomingRequestType.Unpause });
-            }
-
-            /// <summary>Requests that the request associated with the easy operation be canceled.</summary>
-            internal void RequestCancel(EasyRequest easy)
-            {
-                EventSourceTrace(null, easy: easy);
-                QueueIfRunning(new IncomingRequest { Easy = easy, Type = IncomingRequestType.Cancel });
-            }
-
-            /// <summary>Creates and configures a new multi handle.</summary>
-            private Interop.Http.SafeCurlMultiHandle CreateAndConfigureMultiHandle()
-            {
-                // Create the new handle
-                Interop.Http.SafeCurlMultiHandle multiHandle = Interop.Http.MultiCreate();
-                if (multiHandle.IsInvalid)
-                {
-                    throw CreateHttpRequestException(new CurlException((int)CURLcode.CURLE_FAILED_INIT, isMulti: false));
-                }
-
-                // In support of HTTP/2, enable HTTP/2 connections to be multiplexed if possible.
-                // We must only do this if the version of libcurl being used supports HTTP/2 multiplexing.
-                // Due to a change in a libcurl signature, if we try to make this call on an older libcurl,
-                // we'll end up accidentally and unconditionally enabling HTTP 1.1 pipelining.
-                if (s_supportsHttp2Multiplexing)
-                {
-                    ThrowIfCURLMError(Interop.Http.MultiSetOptionLong(multiHandle,
-                        Interop.Http.CURLMoption.CURLMOPT_PIPELINING,
-                        (long)Interop.Http.CurlPipe.CURLPIPE_MULTIPLEX));
-                    EventSourceTrace("Set multiplexing on multi handle");
-                }
-
-                // Configure max connections per host if it was changed from the default.  In shared mode,
-                // this will be pulled from the handler that first created the agent; the setting from subsequent
-                // handlers that use this will be ignored.
-                if (_creatingHandler != null)
-                {
-                    int maxConnections = _creatingHandler.MaxConnectionsPerServer;
-                    if (maxConnections < int.MaxValue) // int.MaxValue considered infinite, mapping to libcurl default of 0
-                    {
-                        CURLMcode code = Interop.Http.MultiSetOptionLong(multiHandle, Interop.Http.CURLMoption.CURLMOPT_MAX_HOST_CONNECTIONS, maxConnections);
-                        switch (code)
-                        {
-                            case CURLMcode.CURLM_OK:
-                                EventSourceTrace("Set max host connections to {0}", maxConnections);
-                                break;
-                            default:
-                                // Treat failures as non-fatal in release; worst case is we employ more connections than desired.
-                                EventSourceTrace("Setting CURLMOPT_MAX_HOST_CONNECTIONS failed: {0}. Ignoring option.", code);
-                                break;
-                        }
-                    }
-                }
-
-                return multiHandle;
-            }
-
-            /// <summary>Thread work item entrypoint for a multiagent worker.</summary>
-            private void WorkerBody()
-            {
-                Debug.Assert(!Monitor.IsEntered(_incomingRequests), $"No locks should be held while invoking {nameof(WorkerBody)}");
-                Debug.Assert(_runningWorker != null && _runningWorker.Id == Task.CurrentId, "This is the worker, so it must be running");
-
-                EventSourceTrace("MultiAgent worker running");
-                try
-                {
-                    try
-                    {
-                        // Do the actual processing
-                        WorkerBodyLoop();
-                    }
-                    finally
-                    {
-                        EventSourceTrace("MultiAgent worker shutting down");
-
-                        // The multi handle's reference count was increased prior to launching
-                        // this processing task.  Release that reference; any Dispose operations
-                        // that occurred during the worker's processing will now be allowed to
-                        // proceed to clean up the multi handle.
-                        _multiHandle.DangerousRelease();
-
-                        lock (_incomingRequests)
-                        {
-                            // Close our wakeup pipe (ignore close errors).
-                            // This is done while holding the lock to prevent
-                            // subsequent Queue calls to see an improperly configured
-                            // set of descriptors.
-                            _wakeupRequestedPipeFd.Dispose();
-                            _wakeupRequestedPipeFd = null;
-                            _requestWakeupPipeFd.Dispose();
-                            _requestWakeupPipeFd = null;
-
-                            // In the time between we stopped processing and taking the lock,
-                            // more requests could have been added.  If they were,
-                            // kick off another processing loop.
-                            _runningWorker = null;
-                            if (_incomingRequests.Count > 0 && !_disposed)
-                            {
-                                EnsureWorkerIsRunning();
-                            }
-                        }
-                    }
-                }
-                catch (Exception exc)
-                {
-                    // Something went very wrong.  In general this should not happen.  The only time it might reasonably
-                    // happen is if CurlHandler is disposed of while it's actively processing, in which case we could
-                    // get an ObjectDisposedException.
-                    EventSourceTrace("Unexpected worker failure: {0}", exc);
-                    Debug.Assert(exc is ObjectDisposedException, $"Unexpected exception from processing loop: {exc}");
-
-                    // At this point if there any queued requests but there's no worker,
-                    // those queued requests are potentially going to sit there waiting forever,
-                    // resulting in a hang. Instead, fail those requests.
-                    lock (_incomingRequests)
-                    {
-                        if (_runningWorker == null)
-                        {
-                            while (_incomingRequests.Count > 0)
-                            {
-                                _incomingRequests.Dequeue().Easy.CleanupAndFailRequest(exc);
-                            }
-                        }
-                    }
-                }
-            }
-
-            /// <summary>Main processing loop employed by the multiagent worker body.</summary>
-            private void WorkerBodyLoop()
-            {
-                Debug.Assert(_wakeupRequestedPipeFd != null, "Should have a non-null pipe for wake ups");
-                Debug.Assert(!_wakeupRequestedPipeFd.IsInvalid, "Should have a valid pipe for wake ups");
-                Debug.Assert(!_wakeupRequestedPipeFd.IsClosed, "Should have an open pipe for wake ups");
-
-                Debug.Assert(_multiHandle != null, "Should have a non-null multi handle");
-                Debug.Assert(!_multiHandle.IsInvalid, "Should have a valid multi handle");
-                Debug.Assert(!_multiHandle.IsClosed, "Should have an open multi handle");
-
-                // Clear our active operations table.  This should already be clear, either because
-                // all previous operations completed without unexpected exception, or in the case of an
-                // unexpected exception we should have cleaned up gracefully anyway.  But just in case...
-                Debug.Assert(_activeOperations.Count == 0, "We shouldn't have any active operations when starting processing.");
-                _activeOperations.Clear();
-
-                Exception eventLoopError = null;
-                try
-                {
-                    // Continue processing as long as there are any active operations
-                    while (true)
-                    {
-                        // First handle any requests in the incoming requests queue.
-                        // (This method is factored out mostly to keep this loop concise, but also partly
-                        // to avoid keeping any references to EasyRequests rooted by the stack and thus
-                        // preventing them from being GC'd and the response stream finalized.  That's mainly
-                        // a concern for debug builds, where the JIT may extend a local's lifetime.  The same
-                        // logic applies to some of the other helpers used later in this loop.)
-                        HandleIncomingRequests();
-
-                        // If we have no active operations, there's no work to do right now.
-                        if (_activeOperations.Count == 0)
-                        {
-                            // Setting up a MultiAgent processing loop involves creating a new MultiAgent, creating a task
-                            // and a thread to process it, creating a new pipe, etc., which has non-trivial cost associated
-                            // with it.  Thus, to avoid repeatedly spinning up and down these workers, we can keep this worker
-                            // alive for a little while longer in case another request comes in within some reasonably small
-                            // amount of time.  This helps with the case where a sequence of requests is made serially rather
-                            // than in parallel, avoiding the likely case of spinning up a new multiagent for each.
-                            Interop.Sys.PollEvents triggered;
-                            Interop.Error pollRv = Interop.Sys.Poll(_wakeupRequestedPipeFd, Interop.Sys.PollEvents.POLLIN, KeepAliveMilliseconds, out triggered);
-                            if (pollRv == Interop.Error.SUCCESS && (triggered & Interop.Sys.PollEvents.POLLIN) != 0)
-                            {
-                                // Another request came in while we were waiting. Clear the pipe and loop around to continue processing.
-                                ReadFromWakeupPipeWhenKnownToContainData();
-                                continue;
-                            }
-
-                            // We're done.  Exit the multiagent.
-                            return;
-                        }
-
-                        // We have one or more active operations. Run any work that needs to be run.
-                        PerformCurlWork();
-
-                        // Complete and remove any requests that have finished being processed.
-                        Interop.Http.CURLMSG message;
-                        IntPtr easyHandle;
-                        CURLcode result;
-                        while (Interop.Http.MultiInfoRead(_multiHandle, out message, out easyHandle, out result))
-                        {
-                            HandleCurlMessage(message, easyHandle, result);
-                        }
-
-                        // If there are any active operations, wait for more things to do.
-                        if (_activeOperations.Count > 0)
-                        {
-                            WaitForWork();
-                        }
-                    }
-                }
-                catch (Exception exc)
-                {
-                    eventLoopError = exc;
-                    throw;
-                }
-                finally
-                {
-                    // There may still be active operations, if  an unexpected exception occurred.
-                    // Make sure to clean up any remaining operations, failing them and releasing their resources.
-                    if (_activeOperations.Count > 0)
-                    {
-                        CleanUpRemainingActiveOperations(eventLoopError);
-                    }
-                }
-            }
-
-            /// <summary>
-            /// Drains the incoming requests queue, dequeuing each request and handling it according to its type.
-            /// </summary>
-            private void HandleIncomingRequests()
-            {
-                Debug.Assert(!Monitor.IsEntered(_incomingRequests), "Incoming requests lock should only be held while accessing the queue");
-                EventSourceTrace(null);
-
-                while (true)
-                {
-                    // Get the next request
-                    IncomingRequest request;
-                    lock (_incomingRequests)
-                    {
-                        if (_incomingRequests.Count == 0)
-                        {
-                            return;
-                        }
-
-                        request = _incomingRequests.Dequeue();
-                    }
-
-                    // Process the request
-                    EasyRequest easy = request.Easy;
-                    EventSourceTrace("Type: {0}", request.Type, easy: easy);
-                    switch (request.Type)
-                    {
-                        case IncomingRequestType.New:
-                            ActivateNewRequest(easy);
-                            break;
-
-                        case IncomingRequestType.Cancel:
-                            Debug.Assert(easy._associatedMultiAgent == this, "Should only cancel associated easy requests");
-                            FindFailAndCleanupActiveRequest(easy, new OperationCanceledException(easy._cancellationToken));
-                            break;
-
-                        case IncomingRequestType.Unpause:
-                            Debug.Assert(easy._associatedMultiAgent == this, "Should only unpause associated easy requests");
-                            if (!easy._easyHandle.IsClosed)
-                            {
-                                IntPtr gcHandlePtr;
-                                ActiveRequest ar;
-                                Debug.Assert(FindActiveRequest(easy, out gcHandlePtr, out ar), "Couldn't find active request for unpause");
-
-                                try
-                                {
-                                    ThrowIfCURLEError(Interop.Http.EasyUnpause(easy._easyHandle));
-                                }
-                                catch (Exception exc)
-                                {
-                                    FindFailAndCleanupActiveRequest(easy, exc);
-                                }
-                            }
-                            break;
-
-                        case IncomingRequestType.Shutdown:
-                            // When we get a shutdown request, we want to stop all operations that haven't had
-                            // their response message published.  Other operations may continue.
-                            Debug.Assert(easy == null, "Expected null easy for a Shutdown request");
-                            CleanUpRemainingActiveOperations(
-                                new OperationCanceledException(SR.net_http_unix_handler_disposed),
-                                onlyIfResponseMessageNotPublished: true);
-                            break;
-
-                        default:
-                            Debug.Fail("Invalid request type: " + request.Type);
-                            break;
-                    }
-                }
-            }
-
-            /// <summary>Tell libcurl to perform any available processing on the easy handles associated with this agent's multi handle.</summary>
-            private void PerformCurlWork()
-            {
-                CURLMcode performResult;
-                EventSourceTrace("Ask libcurl to perform any available work...");
-                while ((performResult = Interop.Http.MultiPerform(_multiHandle)) == CURLMcode.CURLM_CALL_MULTI_PERFORM) ;
-                EventSourceTrace("...done performing work: {0}", performResult);
-                ThrowIfCURLMError(performResult);
-            }
-
-            /// <summary>
-            /// Tell libcurl to block waiting for work to be ready to handle.  It'll return when there's work to be
-            /// performed, when a timeout has occurred, or when new requests have entered our incoming requests queue.
-            /// </summary>
-            private void WaitForWork()
-            {
-                // Ask libcurl to wait for more things to do.  We pass in our wakeup-requested pipe handle so that libcurl
-                // will wait on that file descriptor as well and wake up if an incoming request arrived into our queue.
-                bool isWakeupRequestedPipeActive;
-                bool isTimeout;
-                ThrowIfCURLMError(Interop.Http.MultiWait(_multiHandle, _wakeupRequestedPipeFd, out isWakeupRequestedPipeActive, out isTimeout));
-
-                if (isWakeupRequestedPipeActive)
-                {
-                    // We woke up (at least in part) because a wake-up was requested.
-                    // Read the data out of the pipe to clear it.
-                    Debug.Assert(!isTimeout, $"Should not have timed out when {nameof(isWakeupRequestedPipeActive)} is true");
-                    EventSourceTrace("Wait wake-up");
-                    ReadFromWakeupPipeWhenKnownToContainData();
-                }
-
-                if (isTimeout)
-                {
-                    EventSourceTrace("Wait timeout");
-                }
-
-                // PERF NOTE: curl_multi_wait uses poll (assuming it's available), which is O(N) in terms of the number of fds
-                // being waited on. If this ends up being a scalability bottleneck, we can look into using the curl_multi_socket_*
-                // APIs, which would let us switch to using epoll by being notified when sockets file descriptors are added or
-                // removed and configuring the epoll context with EPOLL_CTL_ADD/DEL, which at the expense of a lot of additional
-                // complexity would let us turn the O(N) operation into an O(1) operation.  The additional complexity would come
-                // not only in the form of additional callbacks and managing the socket collection, but also in the form of timer
-                // management, which is necessary when using the curl_multi_socket_* APIs and which we avoid by using just
-                // curl_multi_wait/perform.
-            }
-
-            /// <summary>Handle a libcurl message received as part of processing work.  This should signal a completed operation.</summary>
-            private void HandleCurlMessage(Interop.Http.CURLMSG message, IntPtr easyHandle, CURLcode result)
-            {
-                if (message != Interop.Http.CURLMSG.CURLMSG_DONE)
-                {
-                    Debug.Fail($"CURLMSG_DONE is supposed to be the only message type, but got {message}");
-                    EventSourceTrace("Unexpected CURLMSG: {0}", message);
-                    return;
-                }
-
-                // Get the GCHandle pointer from the easy handle's state
-                IntPtr gcHandlePtr;
-                CURLcode getInfoResult = Interop.Http.EasyGetInfoPointer(easyHandle, CURLINFO.CURLINFO_PRIVATE, out gcHandlePtr);
-                Debug.Assert(getInfoResult == CURLcode.CURLE_OK, $"Failed to get info on a completing easy handle: {getInfoResult}");
-                if (getInfoResult == CURLcode.CURLE_OK)
-                {
-                    // Use the GCHandle to look up the associated ActiveRequest
-                    ActiveRequest completedOperation;
-                    bool gotActiveOp = _activeOperations.TryGetValue(gcHandlePtr, out completedOperation);
-                    Debug.Assert(gotActiveOp, "Expected to find GCHandle ptr in active operations table");
-
-                    // Deactivate the easy handle and finish all processing related to the request
-                    DeactivateActiveRequest(completedOperation, gcHandlePtr);
-                    FinishRequest(completedOperation.EasyWrapper, result);
-                }
-            }
-
-            /// <summary>When shutting down the multi agent worker, ensure any active operations are forcibly completed.</summary>
-            /// <param name="error">The error to use to complete any remaining operations.</param>
-            /// <param name="onlyIfResponseMessageNotPublished">
-            /// true if the only active operations that should be canceled and cleaned up are those which have not
-            /// yet had their response message published. false if all active operations should be canceled regardless
-            /// of where they are in processing.
-            /// </param>
-            private void CleanUpRemainingActiveOperations(Exception error, bool onlyIfResponseMessageNotPublished = false)
-            {
-                EventSourceTrace("Shutting down {0} active operations.", _activeOperations.Count);
-                try
-                {
-                    // Copy the operations to a tmp array so that we don't try to modify the dictionary while enumerating it
-                    var activeOps = new KeyValuePair<IntPtr, ActiveRequest>[_activeOperations.Count];
-                    ((IDictionary<IntPtr, ActiveRequest>)_activeOperations).CopyTo(activeOps, 0);
-
-                    // Fail all active ops.
-                    Exception lastError = null;
-                    foreach (KeyValuePair<IntPtr, ActiveRequest> pair in activeOps)
-                    {
-                        try
-                        {
-                            IntPtr failingOperationGcHandle = pair.Key;
-                            ActiveRequest failingActiveRequest = pair.Value;
-                            EasyRequest easy = failingActiveRequest.EasyWrapper.Target; // may be null if the EasyRequest was already collected
-                            if (!onlyIfResponseMessageNotPublished || (easy != null && !easy.Task.IsCompleted))
-                            {
-                                // Deactivate the request, removing it from the multi handle and allowing it to be cleaned up
-                                DeactivateActiveRequest(failingActiveRequest, failingOperationGcHandle);
-
-                                // Complete the operation's task and clean up any of its resources, if it still exists.
-                                easy?.CleanupAndFailRequest(CreateHttpRequestException(error));
-                            }
-                        }
-                        catch (Exception e)
-                        {
-                            // We don't want a spurious failure while cleaning up one request to prevent us from trying
-                            // to clean up the rest of them.
-                            lastError = e;
-                        }
-                    }
-
-                    // Now propagate any failure that may have occurred while cleaning up
-                    if (lastError != null)
-                    {
-                        ExceptionDispatchInfo.Throw(lastError);
-                    }
-                }
-                finally
-                {
-                    if (!onlyIfResponseMessageNotPublished)
-                    {
-                        // Ensure the table is now cleared.
-                        _activeOperations.Clear();
-                    }
-                }
-            }
-
-            /// <summary>
-            /// Activates the request represented by the EasyRequest.  This includes creating the libcurl easy handle,
-            /// configuring it, and associating it with the multi handle so that it may be processed.
-            /// </summary>
-            private void ActivateNewRequest(EasyRequest easy)
-            {
-                Debug.Assert(easy != null, "We should never get a null request");
-                Debug.Assert(easy._associatedMultiAgent == this, "Request should be associated with this agent");
-
-                // If cancellation has been requested, complete the request proactively
-                if (easy._cancellationToken.IsCancellationRequested)
-                {
-                    easy.CleanupAndFailRequest(new OperationCanceledException(easy._cancellationToken));
-                    return;
-                }
-
-                // We need to create a GCHandle that we can pass to libcurl to let it keep associated managed
-                // state alive and help us to determine which state corresponds to the particular request.  However,
-                // having a GCHandle that keeps an EasyRequest alive will prevent finalization of anything to do with
-                // that EasyRequest, which means we could end up in a situation where code creates and then drops a
-                // request, but then libcurl ends up keeping the state alive (until the reuest/response eventually times
-                // out, assuming the timeout wasn't set to infinite).  To address this, we create a GCHandle to a wrapper
-                // object.  At first, that wrapper object wraps a strong reference to the EasyRequest, since until a
-                // response comes back, the caller doesn't actually have a reference to anything related to the request.
-                // Then once a response comes back and the caller is responsible for keeping the request/response alive,
-                // we replace the wrapped state with a weak reference to the EasyRequest.  That way, if the user then
-                // drops the response, we can allow it to be finalized and not keep it alive indefinitely by the
-                // native reference.  Finalization of the response stream will cause all of the relevant state to be
-                // closed, including closing out the native easy session and then free'ing this GCHandle.
-                easy._selfStrongToWeakReference = new StrongToWeakReference<EasyRequest>(easy); // store wrapper onto the easy so that it can transition it to weak and then lose the ref
-                GCHandle gcHandle = GCHandle.Alloc(easy._selfStrongToWeakReference);
-                IntPtr gcHandlePtr = GCHandle.ToIntPtr(gcHandle);
-
-                // Configure the easy request and add it to the multi handle.
-                bool addedRef = false;
-                try
-                {
-                    easy.InitializeCurl();
-
-                    easy.SetCurlOption(Interop.Http.CURLoption.CURLOPT_PRIVATE, gcHandlePtr);
-                    easy.SetCurlCallbacks(gcHandlePtr, s_receiveHeadersCallback, s_sendCallback, s_seekCallback, s_receiveBodyCallback, s_debugCallback);
-
-                    // Make sure that as long as the easy handle is referenced by the multi handle that
-                    // it doesn't get finalized.  Doing so can lead to serious problems like seg faults,
-                    // for example if the multi handle is trying to access the easy handle on one thread
-                    // while it's being finalized on another.
-                    easy._easyHandle.DangerousAddRef(ref addedRef);
-
-                    // Finally, register the easy handle with the multi handle
-                    ThrowIfCURLMError(Interop.Http.MultiAddHandle(_multiHandle, easy._easyHandle));
-                }
-                catch (Exception exc)
-                {
-                    if (addedRef)
-                    {
-                        easy._easyHandle.DangerousRelease();
-                    }
-                    gcHandle.Free();
-                    easy.CleanupAndFailRequest(exc);
-                    return;
-                }
-
-                // And if cancellation can be requested, hook up a cancellation callback.
-                // This callback will put the easy request back into the queue, which will
-                // ensure that a wake-up request has been issued.
-                var cancellationReg = default(CancellationTokenRegistration);
-                if (easy._cancellationToken.CanBeCanceled)
-                {
-                    // To avoid keeping the EasyRequest rooted in the associated CancellationTokenSource,
-                    // the cancellation registration is given the wrapper rather than the object directly.
-                    cancellationReg = easy._cancellationToken.Register(s =>
-                    {
-                        var wrapper = (StrongToWeakReference<EasyRequest>)s;
-                        EasyRequest e = wrapper.Target; // may be null if already collected
-                        e?._associatedMultiAgent.RequestCancel(e);
-                    }, easy._selfStrongToWeakReference);
-                }
-
-                // Finally, add it to our map.
-                _activeOperations.Add(gcHandlePtr, new ActiveRequest
-                {
-                    EasyWrapper = easy._selfStrongToWeakReference,
-                    EasyHandle = easy._easyHandle,
-                    CancellationRegistration = cancellationReg,
-                });
-            }
-
-            /// <summary>Extract the EasyRequest from the GCHandle pointer to it.</summary>
-            internal static bool TryGetEasyRequestFromGCHandle(IntPtr gcHandlePtr, out EasyRequest easy)
-            {
-                // Get the EasyRequest from the context
-                try
-                {
-                    GCHandle handle = GCHandle.FromIntPtr(gcHandlePtr);
-                    easy = (handle.Target as StrongToWeakReference<EasyRequest>)?.Target;
-                    return easy != null;
-                }
-                catch (Exception e) when (e is InvalidCastException || e is InvalidOperationException)
-                {
-                    Debug.Fail($"Error accessing GCHandle: {e}");
-                }
-
-                easy = null;
-                return false;
-            }
-
-            /// <summary>
-            /// Corresponding to ActivateNewRequest, removes the active request from the multi handle, frees the GCHandle,
-            /// removes the request from our tracking table, and ensures cancellation has been unregistered.
-            /// </summary>
-            private void DeactivateActiveRequest(ActiveRequest activeRequest, IntPtr gcHandlePtr)
-            {
-                try
-                {
-                    // Remove the operation from the multi handle so we can shut down the multi handle cleanly
-                    CURLMcode removeResult = Interop.Http.MultiRemoveHandle(_multiHandle, activeRequest.EasyHandle);
-                    Debug.Assert(removeResult == CURLMcode.CURLM_OK, "Failed to remove easy handle"); // ignore cleanup errors in release
-
-#if !SYSNETHTTP_NO_OPENSSL
-                    Interop.Crypto.ErrClearError(); // Ensure that no SSL errors were left on the queue by libcurl.
-#endif
-
-                    // Release the associated GCHandle so that it's not kept alive forever
-                    if (gcHandlePtr != IntPtr.Zero)
-                    {
-                        try
-                        {
-                            GCHandle.FromIntPtr(gcHandlePtr).Free();
-                            bool removed = _activeOperations.Remove(gcHandlePtr);
-                            Debug.Assert(removed, "Expected GCHandle to still be referenced by active operations table");
-                        }
-                        catch (InvalidOperationException)
-                        {
-                            Debug.Fail("Couldn't get/free the GCHandle for an active operation while shutting down due to failure");
-                        }
-                    }
-
-                    // Undo cancellation registration
-                    activeRequest.CancellationRegistration.Dispose();
-                }
-                finally
-                {
-                    // We previously AddRef'd the easy handle to ensure that it wasn't finalized
-                    // while it was still registered with the multi handle.  Now that it's been removed,
-                    // we need to remove the reference.
-                    activeRequest.EasyHandle.DangerousRelease();
-                }
-            }
-
-            /// <summary>
-            /// Looks up an ActiveRequest in the active operations table by EasyRequest.  This is a linear operation
-            /// and should not be used on hot paths.
-            /// </summary>
-            private bool FindActiveRequest(EasyRequest easy, out IntPtr gcHandlePtr, out ActiveRequest activeRequest)
-            {
-                // We maintain an IntPtr=>ActiveRequest mapping, which makes it cheap to look-up by GCHandle ptr but
-                // expensive to look up by EasyRequest.  If we find this becoming a bottleneck, we can add a reverse
-                // map that stores the other direction as well.  It should only be used on slow paths, such as when
-                // completing an operation due to failure.
-                foreach (KeyValuePair<IntPtr, ActiveRequest> pair in _activeOperations)
-                {
-                    if (pair.Value.EasyWrapper.Target == easy)
-                    {
-                        gcHandlePtr = pair.Key;
-                        activeRequest = pair.Value;
-                        return true;
-                    }
-                }
-
-                gcHandlePtr = IntPtr.Zero;
-                activeRequest = default(ActiveRequest);
-                return false;
-            }
-
-            /// <summary>
-            /// Finds in the active operations table the operation for the specified easy request,
-            /// and then assuming it's found, deactivates and fails it with the specified exception.
-            /// </summary>
-            private void FindFailAndCleanupActiveRequest(EasyRequest easy, Exception error)
-            {
-                EventSourceTrace("Error: {0}", error, easy: easy);
-
-                IntPtr gcHandlePtr;
-                ActiveRequest activeRequest;
-                if (FindActiveRequest(easy, out gcHandlePtr, out activeRequest))
-                {
-                    DeactivateActiveRequest(activeRequest, gcHandlePtr);
-                    easy.CleanupAndFailRequest(error);
-                }
-                else
-                {
-                    Debug.Assert(easy.Task.IsCompleted, "We should only not be able to find the request if it failed or we started to send back the response.");
-                }
-            }
-
-            /// <summary>Finishes the processing of a completed easy operation.</summary>
-            private void FinishRequest(StrongToWeakReference<EasyRequest> easyWrapper, CURLcode messageResult)
-            {
-                EasyRequest completedOperation = easyWrapper.Target;
-                EventSourceTrace("Curl result: {0}", messageResult, easy: completedOperation);
-
-                if (completedOperation == null)
-                {
-                    // Already collected; nothing more to do.
-                    return;
-                }
-
-                if (completedOperation._responseMessage.StatusCode != HttpStatusCode.Unauthorized)
-                {
-                    // If preauthentication is enabled, then we want to transfer credentials to the handler's credential cache.
-                    // That entails asking the easy operation which auth types are supported, and then giving that info to the
-                    // handler, which along with the request URI and its server credentials will populate the cache appropriately.
-                    if (completedOperation._handler.PreAuthenticate)
-                    {
-                        long authAvailable;
-                        if (Interop.Http.EasyGetInfoLong(completedOperation._easyHandle, CURLINFO.CURLINFO_HTTPAUTH_AVAIL, out authAvailable) == CURLcode.CURLE_OK)
-                        {
-                            completedOperation._handler.TransferCredentialsToCache(
-                                completedOperation._requestMessage.RequestUri, (Interop.Http.CURLAUTH)authAvailable);
-                        }
-                        // Ignore errors: no need to fail for the sake of putting the credentials into the cache
-                    }
-                }
-
-                // Complete or fail the request
-                try
-                {
-                    // At this point, we've completed processing the entire request, either due to error
-                    // or due to completing the entire response.
-                    completedOperation.Cleanup();
-
-                    // libcurl will return CURLE_UNSUPPORTED_PROTOCOL if the url it tried to go to had an unsupported protocol.
-                    // This could be the original url provided or one provided in a Location header for a redirect.  Since
-                    // we vet the original url passed in, such an error here must be for a redirect, in which case we want to
-                    // ignore it and treat such failures as successes, to match the Windows behavior.
-                    if (messageResult != CURLcode.CURLE_UNSUPPORTED_PROTOCOL)
-                    {
-                        // libcurl will return CURLE_RECV_ERROR (56) if proxy authentication failed when connecting to a https server,
-                        // whereas it returns CURLE_OK for a http server proxy authentication failure. We ignore this curl behavior error,
-                        // and let the user rely on response message status code to match the Windows behavior.
-                        if (messageResult != CURLcode.CURLE_RECV_ERROR ||
-                                completedOperation._responseMessage.StatusCode != HttpStatusCode.ProxyAuthenticationRequired)
-                        {
-                            ThrowIfCURLEError(messageResult);
-                        }
-                    }
-
-                    // Make sure the response message is published, in case it wasn't already, and since we're done processing
-                    // everything to do with this request, make sure the response stream is marked complete as well.
-                    completedOperation.EnsureResponseMessagePublished();
-                    completedOperation._responseMessage.ResponseStream.SignalComplete();
-                }
-                catch (Exception exc)
-                {
-                    completedOperation.FailRequest(exc);
-                }
-            }
-
-            /// <summary>Callback invoked by libcurl when debug information is available.</summary>
-            private static void CurlDebugFunction(IntPtr curl, Interop.Http.CurlInfoType type, IntPtr data, ulong size, IntPtr context)
-            {
-                EasyRequest easy;
-                TryGetEasyRequestFromGCHandle(context, out easy);
-                // If we're unable to get an associated request, we simply trace without it.
-
-                try
-                {
-                    switch (type)
-                    {
-                        case Interop.Http.CurlInfoType.CURLINFO_TEXT:
-                        case Interop.Http.CurlInfoType.CURLINFO_HEADER_IN:
-                        case Interop.Http.CurlInfoType.CURLINFO_HEADER_OUT:
-                            string text = Marshal.PtrToStringAnsi(data, (int)size).Trim();
-                            if (text.Length > 0)
-                            {
-                                CurlHandler.EventSourceTrace("{0}: {1}", type, text, 0, easy: easy);
-                            }
-                            break;
-
-                        default:
-                            CurlHandler.EventSourceTrace("{0}: {1} bytes", type, size, 0, easy: easy);
-                            break;
-                    }
-                }
-                catch (Exception exc)
-                {
-                    CurlHandler.EventSourceTrace("Error: {0}", exc, easy: easy);
-                }
-            }
-
-            /// <summary>Callback invoked by libcurl for each response header received.</summary>
-            private static ulong CurlReceiveHeadersCallback(IntPtr buffer, ulong size, ulong nitems, IntPtr context)
-            {
-                // The callback is invoked once per header; multi-line headers get merged into a single line.
-
-                size *= nitems;
-                Debug.Assert(size <= Interop.Http.CURL_MAX_HTTP_HEADER, $"Expected header size <= {Interop.Http.CURL_MAX_HTTP_HEADER}, got {size}");
-
-                EasyRequest easy;
-                if (TryGetEasyRequestFromGCHandle(context, out easy))
-                {
-                    CurlHandler.EventSourceTrace("Size: {0}", size, easy: easy);
-                    try
-                    {
-                        if (size == 0)
-                        {
-                            return 0;
-                        }
-
-                        // Make sure we've not yet published the response. This could happen with trailer headers,
-                        // in which case we just ignore them (we don't want to add them to the response headers at
-                        // this point, as it'd contribute to a race condition, both in terms of headers appearing
-                        // "randomly" and in terms of accessing a non-thread-safe data structure from this thread
-                        // while the consumer might be accessing / mutating it elsewhere.)
-                        if (easy.Task.IsCompleted)
-                        {
-                            CurlHandler.EventSourceTrace("Response already published. Ignoring headers.", easy: easy);
-                            return size;
-                        }
-
-                        CurlResponseMessage response = easy._responseMessage;
-                        CurlResponseHeaderReader reader = new CurlResponseHeaderReader(buffer, size);
-
-                        // Validate that we haven't received too much header data.
-                        // MaxResponseHeadersLength property is in units in K (1024) bytes.
-                        ulong headerBytesReceived = response._headerBytesReceived + size;
-                        if (headerBytesReceived > (ulong)(easy._handler.MaxResponseHeadersLength * 1024))
-                        {
-                            throw new HttpRequestException(
-                                SR.Format(SR.net_http_response_headers_exceeded_length, easy._handler.MaxResponseHeadersLength));
-                        }
-                        response._headerBytesReceived = (uint)headerBytesReceived;
-
-                        // Parse the header
-                        if (reader.ReadStatusLine(response))
-                        {
-                            CurlHandler.EventSourceTrace("Received status line", easy: easy);
-
-                            // Clear the headers when the status line is received. This may happen multiple times if there are multiple response headers (like in redirection).
-                            response.Headers.Clear();
-                            response.Content.Headers.Clear();
-                            response._headerBytesReceived = (uint)size;
-
-                            // Update the request message with the Uri
-                            easy.StoreLastEffectiveUri();
-                        }
-                        else
-                        {
-                            string headerName;
-                            string headerValue;
-
-                            if (reader.ReadHeader(out headerName, out headerValue))
-                            {
-                                if (!response.Headers.TryAddWithoutValidation(headerName, headerValue))
-                                {
-                                    response.Content.Headers.TryAddWithoutValidation(headerName, headerValue);
-                                }
-                                else if ((int)response.StatusCode >= 300 && (int)response.StatusCode < 400 &&
-                                    easy._handler.AllowAutoRedirect &&
-                                    string.Equals(headerName, HttpKnownHeaderNames.Location, StringComparison.OrdinalIgnoreCase))
-                                {
-                                    // A "Location" header field can mean different things for different status codes.  For 3xx status codes,
-                                    // it implies a redirect.  As such, if we got a 3xx status code and we support automatically redirecting,
-                                    // reconfigure the easy handle under the assumption that libcurl will redirect.  If it does redirect, we'll
-                                    // be prepared; if it doesn't (e.g. it doesn't treat some particular 3xx as a redirect, if we've reached
-                                    // our redirect limit, etc.), this will have been unnecessary work in reconfiguring the easy handle, but
-                                    // nothing incorrect, as we'll tear down the handle once the request finishes, anyway, and all of the configuration
-                                    // we're doing is about initiating a new request.
-                                    if ((int)response.StatusCode >= 301 && (int)response.StatusCode <= 303)
-                                    {
-                                        // ISSUE: 25163
-                                        // Ideally we want to avoid modifying the users request message.
-                                        easy._requestMessage.Headers.TransferEncodingChunked = false;
-                                    }
-                                    easy.SetPossibleRedirectForLocationHeader(headerValue);
-                                }
-                                else if (string.Equals(headerName, HttpKnownHeaderNames.SetCookie, StringComparison.OrdinalIgnoreCase))
-                                {
-                                    easy._handler.AddResponseCookies(easy, headerValue);
-                                }
-                            }
-                        }
-
-                        return size;
-                    }
-                    catch (Exception ex)
-                    {
-                        easy.FailRequest(ex); // cleanup will be handled by main processing loop
-                    }
-                }
-
-                // Returning a value other than size fails the callback and forces
-                // request completion with an error
-                CurlHandler.EventSourceTrace("Aborting request", easy: easy);
-                return size - 1;
-            }
-
-            /// <summary>Callback invoked by libcurl for body data received.</summary>
-            private static ulong CurlReceiveBodyCallback(
-                IntPtr buffer, ulong size, ulong nitems, IntPtr context)
-            {
-                size *= nitems;
-
-                EasyRequest easy;
-                if (TryGetEasyRequestFromGCHandle(context, out easy))
-                {
-                    CurlHandler.EventSourceTrace("Size: {0}", size, easy: easy);
-                    try
-                    {
-                        if (!(easy.Task.IsCanceled || easy.Task.IsFaulted))
-                        {
-                            // Complete the task if it hasn't already been.  This will make the
-                            // stream available to consumers.  A previous write callback
-                            // may have already completed the task to publish the response.
-                            easy.EnsureResponseMessagePublished();
-
-                            // Try to transfer the data to a reader.  This will return either the
-                            // amount of data transferred (equal to the amount requested
-                            // to be transferred), or it will return a pause request.
-                            return easy._responseMessage.ResponseStream.TransferDataToResponseStream(buffer, (long)size);
-                        }
-                    }
-                    catch (Exception ex)
-                    {
-                        easy.FailRequest(ex); // cleanup will be handled by main processing loop
-                    }
-                }
-
-                // Returning a value other than size fails the callback and forces
-                // request completion with an error.
-                CurlHandler.EventSourceTrace("Aborting request", easy: easy);
-                return (size > 0) ? size - 1 : 1;
-            }
-
-            /// <summary>Callback invoked by libcurl to read request data.</summary>
-            private static ulong CurlSendCallback(IntPtr buffer, ulong size, ulong nitems, IntPtr context)
-            {
-                int length = checked((int)(size * nitems));
-
-                if (TryGetEasyRequestFromGCHandle(context, out EasyRequest easy))
-                {
-                    CurlHandler.EventSourceTrace("Size: {0}", length, easy: easy);
-
-                    if (length == 0)
-                    {
-                        return 0;
-                    }
-
-                    Debug.Assert(easy._requestMessage.Content != null, "We should only be in the send callback if we have request content");
-                    Debug.Assert(easy._associatedMultiAgent != null, "The request should be associated with a multi agent.");
-
-                    try
-                    {
-                        // Transfer data from the request's content stream to libcurl
-                        return TransferDataFromRequestStream(buffer, length, easy);
-                    }
-                    catch (Exception ex)
-                    {
-                        easy.FailRequest(ex); // cleanup will be handled by main processing loop
-                    }
-                }
-
-                // Something went wrong.
-                CurlHandler.EventSourceTrace("Aborting request", easy: easy);
-                return Interop.Http.CURL_READFUNC_ABORT;
-            }
-
-            /// <summary>
-            /// Transfers up to <paramref name="length"/> data from the <paramref name="easy"/>'s
-            /// request content (non-memory) stream to the buffer.
-            /// </summary>
-            /// <returns>The number of bytes transferred.</returns>
-            private static ulong TransferDataFromRequestStream(IntPtr buffer, int length, EasyRequest easy)
-            {
-                CurlHandler.EventSourceTrace("Length: {0}", length, easy: easy);
-
-                MultiAgent multi = easy._associatedMultiAgent;
-
-                // First check to see whether there's any data available from a previous asynchronous read request.
-                // If there is, the transfer state's Task field will be non-null, with its Result representing
-                // the number of bytes read.  The Buffer will then contain all of that read data.  If the Count
-                // is 0, then this is the first time we're checking that Task, and so we populate the Count
-                // from that read result.  After that, we can transfer as much data remains between Offset and
-                // Count.  Multiple callbacks may pull from that one read.
-
-                EasyRequest.SendTransferState sts = easy._sendTransferState;
-                if (sts != null)
-                {
-                    // Is there a previous read that may still have data to be consumed?
-                    if (sts.Task != null)
-                    {
-                        if (!sts.Task.IsCompleted)
-                        {
-                            // We have a previous read that's not yet completed.  This should be quite rare, but it can
-                            // happen when we're unpaused prematurely, potentially due to the request still finishing
-                            // being sent as the server starts to send a response.  Since we still have the outstanding
-                            // read, we simply re-pause.  When the task completes (which could have happened immediately
-                            // after the check). the continuation we previously created will fire and queue an unpause.
-                            // Since all of this processing is single-threaded on the current thread, that unpause request
-                            // is guaranteed to happen after this re-pause.
-                            multi.EventSourceTrace("Re-pausing reading after a spurious un-pause", easy: easy);
-                            return Interop.Http.CURL_READFUNC_PAUSE;
-                        }
-
-                        // Determine how many bytes were read on the last asynchronous read.
-                        // If nothing was read, then we're done and can simply return 0 to indicate
-                        // the end of the stream.
-                        int bytesRead = sts.Task.GetAwaiter().GetResult(); // will throw if read failed
-                        Debug.Assert(bytesRead >= 0 && bytesRead <= sts.Buffer.Length, $"ReadAsync returned an invalid result length: {bytesRead}");
-                        if (bytesRead == 0)
-                        {
-                            sts.SetTaskOffsetCount(null, 0, 0);
-                            return 0;
-                        }
-
-                        // If Count is still 0, then this is the first time after the task completed
-                        // that we're examining the data: transfer the bytesRead to the Count.
-                        if (sts.Count == 0)
-                        {
-                            multi.EventSourceTrace("ReadAsync completed with bytes: {0}", bytesRead, easy: easy);
-                            sts.Count = bytesRead;
-                        }
-
-                        // Now Offset and Count are both accurate.  Determine how much data we can copy to libcurl...
-                        int availableData = sts.Count - sts.Offset;
-                        Debug.Assert(availableData > 0, "There must be some data still available.");
-
-                        // ... and copy as much of that as libcurl will allow.
-                        int bytesToCopy = Math.Min(availableData, length);
-                        Marshal.Copy(sts.Buffer, sts.Offset, buffer, bytesToCopy);
-                        multi.EventSourceTrace("Copied {0} bytes from request stream", bytesToCopy, easy: easy);
-
-                        // Update the offset.  If we've gone through all of the data, reset the state
-                        // so that the next time we're called back we'll do a new read.
-                        sts.Offset += bytesToCopy;
-                        Debug.Assert(sts.Offset <= sts.Count, "Offset should never exceed count");
-                        if (sts.Offset == sts.Count)
-                        {
-                            sts.SetTaskOffsetCount(null, 0, 0);
-                        }
-
-                        // Return the amount of data copied
-                        Debug.Assert(bytesToCopy > 0, "We should never return 0 bytes here.");
-                        return (ulong)bytesToCopy;
-                    }
-
-                    // sts was non-null but sts.Task was null, meaning there was no previous task/data
-                    // from which to satisfy any of this request.
-                }
-                else // sts == null
-                {
-                    // Allocate a transfer state object to use for the remainder of this request.
-                    Debug.Assert(easy._requestMessage.Content != null, "Content shouldn't be null, since we already got a content request stream");
-                    long bufferSize = easy._requestMessage.Content.Headers.ContentLength.GetValueOrDefault();
-                    if (bufferSize <= 0 || bufferSize > MaxRequestBufferSize)
-                    {
-                        bufferSize = MaxRequestBufferSize;
-                    }
-                    easy._sendTransferState = sts = new EasyRequest.SendTransferState((int)bufferSize);
-                }
-
-                Debug.Assert(sts != null, "By this point we should have a transfer object");
-                Debug.Assert(sts.Task == null, "There shouldn't be a task now.");
-                Debug.Assert(sts.Count == 0, "Count should be zero.");
-                Debug.Assert(sts.Offset == 0, "Offset should be zero.");
-
-                // If we get here, there was no previously read data available to copy.
-
-                // Make sure we actually have a stream to read from.  This will be null if either
-                // this is the first time we're reading it, or if the stream was reset as part
-                // of curl trying to rewind.  Then do the read.
-                ValueTask<int> asyncRead;
-                if (easy._requestContentStream == null)
-                {
-                    multi.EventSourceTrace("Calling ReadAsStreamAsync to get new request stream", easy: easy);
-                    Task<Stream> readAsStreamTask = easy._requestMessage.Content.ReadAsStreamAsync();
-                    asyncRead = readAsStreamTask.IsCompleted ?
-                        StoreRetrievedContentStreamAndReadAsync(readAsStreamTask, easy, sts, length) :
-                        new ValueTask<int>(easy._requestMessage.Content.ReadAsStreamAsync().ContinueWith((t, s) =>
-                        {
-                            var stateAndRequest = (Tuple<int, EasyRequest.SendTransferState, EasyRequest>)s;
-                            return StoreRetrievedContentStreamAndReadAsync(t,
-                                stateAndRequest.Item3, stateAndRequest.Item2, stateAndRequest.Item1).AsTask();
-                        }, Tuple.Create(length, sts, easy), CancellationToken.None,
-                        TaskContinuationOptions.ExecuteSynchronously | TaskContinuationOptions.DenyChildAttach, TaskScheduler.Default).Unwrap());
-                }
-                else
-                {
-                    multi.EventSourceTrace("Starting async read", easy: easy);
-                    asyncRead = easy._requestContentStream.ReadAsync(
-                       new Memory<byte>(sts.Buffer, 0, Math.Min(sts.Buffer.Length, length)), easy._cancellationToken);
-                }
-
-                // Even though it's "Async", it's possible this read could complete synchronously or extremely quickly.
-                // Check to see if it did, in which case we can also satisfy the libcurl request synchronously in this callback.
-                if (asyncRead.IsCompleted)
-                {
-                    multi.EventSourceTrace("Async read completed immediately", easy: easy);
-
-                    // Get the amount of data read.
-                    int bytesRead = asyncRead.GetAwaiter().GetResult(); // will throw if read failed
-                    if (bytesRead == 0)
-                    {
-                        multi.EventSourceTrace("Read 0 bytes", easy: easy);
-                        return 0;
-                    }
-
-                    // Copy as much as we can.
-                    int bytesToCopy = Math.Min(bytesRead, length);
-                    Debug.Assert(bytesToCopy > 0 && bytesToCopy <= sts.Buffer.Length, $"ReadAsync quickly returned an invalid result length: {bytesToCopy}");
-                    Marshal.Copy(sts.Buffer, 0, buffer, bytesToCopy);
-                    multi.EventSourceTrace("Read {0} bytes", bytesToCopy, easy: easy);
-
-                    // If we read more than we were able to copy, stash it away for the next read.
-                    if (bytesToCopy < bytesRead)
-                    {
-                        multi.EventSourceTrace("Storing {0} bytes for later", bytesRead - bytesToCopy, easy: easy);
-                        sts.SetTaskOffsetCount(asyncRead.AsTask(), bytesToCopy, bytesRead);
-                    }
-
-                    // Return the number of bytes read.
-                    return (ulong)bytesToCopy;
-                }
-
-                // Otherwise, the read completed asynchronously.  Store the task, and hook up a continuation
-                // such that the connection will be unpaused once the task completes.
-                sts.SetTaskOffsetCount(asyncRead.AsTask(), 0, 0);
-                sts.Task.ContinueWith((t, s) =>
-                {
-                    EasyRequest easyRef = (EasyRequest)s;
-                    easyRef._associatedMultiAgent.RequestUnpause(easyRef);
-                }, easy, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);
-
-                // Then pause the connection.
-                multi.EventSourceTrace("Pausing transfer from request stream", easy: easy);
-                return Interop.Http.CURL_READFUNC_PAUSE;
-            }
-
-            /// <summary>
-            /// Given a completed task used to retrieve the content stream asynchronously, extracts the stream,
-            /// stores it into <see cref="EasyRequest._requestContentStream"/>, and does an initial read on it.
-            /// </summary>
-            private static ValueTask<int> StoreRetrievedContentStreamAndReadAsync(
-                Task<Stream> readAsStreamTask, EasyRequest easy, EasyRequest.SendTransferState sts, int length)
-            {
-                Debug.Assert(readAsStreamTask.IsCompleted, $"Expected {nameof(readAsStreamTask)} to be completed, got {readAsStreamTask.Status}");
-                try
-                {
-                    MultiAgent multi = easy._associatedMultiAgent;
-                    multi.EventSourceTrace("Async operation completed: {0}", readAsStreamTask.Status, easy: easy);
-
-                    // Get and store the resulting stream
-                    easy._requestContentStream = readAsStreamTask.GetAwaiter().GetResult();
-                    multi.EventSourceTrace("Got stream: {0}", easy._requestContentStream.GetType(), easy: easy);
-
-                    // If the stream is seekable, store its original position.  We'll use this any time we need to seek
-                    // back to the "beginning", as it's possible the stream isn't at position 0.
-                    if (easy._requestContentStream.CanSeek)
-                    {
-                        long startingPos = easy._requestContentStream.Position;
-                        easy._requestContentStreamStartingPosition = startingPos;
-                        CurlHandler.EventSourceTrace("Stream starting position: {0}", startingPos, easy: easy);
-                    }
-
-                    // Now that we have a stream, do the desired read
-                    multi.EventSourceTrace("Starting async read", easy: easy);
-                    return easy._requestContentStream.ReadAsync(new Memory<byte>(sts.Buffer, 0, Math.Min(sts.Buffer.Length, length)), easy._cancellationToken);
-                }
-                catch (OperationCanceledException oce)
-                {
-                    return new ValueTask<int>(oce.CancellationToken.IsCancellationRequested ?
-                        Task.FromCanceled<int>(oce.CancellationToken) :
-                        Task.FromCanceled<int>(new CancellationToken(true)));
-                }
-                catch (Exception exc)
-                {
-                    return new ValueTask<int>(Task.FromException<int>(exc));
-                }
-            }
-
-            /// <summary>Callback invoked by libcurl to seek to a position within the request stream.</summary>
-            private static Interop.Http.CurlSeekResult CurlSeekCallback(IntPtr context, long offset, int origin)
-            {
-                EasyRequest easy;
-                if (TryGetEasyRequestFromGCHandle(context, out easy))
-                {
-                    CurlHandler.EventSourceTrace("Offset: {0}, Origin: {1}", offset, origin, 0, easy: easy);
-                    try
-                    {
-                        // If we don't have a stream yet, we can't seek.
-                        if (easy._requestContentStream == null)
-                        {
-                            CurlHandler.EventSourceTrace("No request stream exists yet. Can't seek", easy: easy);
-                            return Interop.Http.CurlSeekResult.CURL_SEEKFUNC_CANTSEEK;
-                        }
-
-                        // If the stream is seekable, which is a very common case, everyone is happy.
-                        // Simply seek on the stream.
-                        if (easy._requestContentStream.CanSeek)
-                        {
-                            CurlHandler.EventSourceTrace("Seeking on the existing stream", easy: easy);
-                            SeekOrigin seek = (SeekOrigin)origin;
-                            if (seek == SeekOrigin.Begin)
-                            {
-                                Debug.Assert(easy._requestContentStreamStartingPosition.HasValue);
-                                easy._requestContentStream.Position = easy._requestContentStreamStartingPosition.GetValueOrDefault();
-                            }
-                            else
-                            {
-                                easy._requestContentStream.Seek(offset, seek);
-                            }
-                            return Interop.Http.CurlSeekResult.CURL_SEEKFUNC_OK;
-                        }
-
-                        // The stream isn't seekable.  Now we start getting into shakier ground.
-                        // Most of the time the seek callback is used, it's because libcurl is rewinding
-                        // to the beginning of the stream due to a redirect, an auth challenge, etc. (other
-                        // cases where it might try to seek elsewhere would be, e.g., with a Range header).
-                        // In such cases, we can't seek, but we can simply re-read the stream from the content.
-                        // In most cases this will "just work." There are corner cases, however, where it'll
-                        // fail but we won't yet know it failed, e.g. if a StreamContent is used, ReadAsStreamAsync
-                        // will give us back a wrapper stream over the same original underlying stream and without
-                        // having changed its position (it's not seekable).  At that point we'll think
-                        // we have a new stream, but when reading starts happening, it'll be at the existing
-                        // position, and we'll only end up sending part of the data (or none in the common case
-                        // where we'd already read ot the end).  As a workaround for that, we can at least special case
-                        // the StreamContent type, for which we know this will be an issue.  It won't help with other
-                        // corner -case contents like this, but for such contents, we would still end up failing the
-                        // request, just sooner.
-                        if (offset == 0 && origin == (int)SeekOrigin.Begin &&
-                            !(easy._requestMessage.Content is StreamContent)) // avoid known problematic case
-                        {
-                            CurlHandler.EventSourceTrace("Removing the existing request stream, to be replaced on subsequent read", easy: easy);
-                            easy._requestContentStream = null;
-                        }
-
-                        // Can't seek.  Let libcurl know: it may still be able to recover.
-                        CurlHandler.EventSourceTrace("Can't seek", easy: easy);
-                        return Interop.Http.CurlSeekResult.CURL_SEEKFUNC_CANTSEEK;
-                    }
-                    catch (Exception ex)
-                    {
-                        easy.FailRequest(ex); // cleanup will be handled by main processing loop
-                    }
-                }
-
-                // Something went wrong
-                CurlHandler.EventSourceTrace("Seek failed", easy: easy);
-                return Interop.Http.CurlSeekResult.CURL_SEEKFUNC_FAIL;
-            }
-
-            private void EventSourceTrace<TArg0>(string formatMessage, TArg0 arg0, EasyRequest easy = null, [CallerMemberName] string memberName = null)
-            {
-                CurlHandler.EventSourceTrace(formatMessage, arg0, this, easy, memberName);
-            }
-
-            private void EventSourceTrace(string message, EasyRequest easy = null, [CallerMemberName] string memberName = null)
-            {
-                CurlHandler.EventSourceTrace(message, this, easy, memberName);
-            }
-
-            /// <summary>Represents an active request currently being processed by the agent.</summary>
-            private struct ActiveRequest
-            {
-                public StrongToWeakReference<EasyRequest> EasyWrapper;
-                public Interop.Http.SafeCurlHandle EasyHandle;
-                public CancellationTokenRegistration CancellationRegistration;
-            }
-
-            /// <summary>Represents an incoming request to be processed by the agent.</summary>
-            internal struct IncomingRequest
-            {
-                public IncomingRequestType Type;
-                public EasyRequest Easy;
-            }
-
-            /// <summary>The type of an incoming request to be processed by the agent.</summary>
-            internal enum IncomingRequestType : byte
-            {
-                /// <summary>A new request that's never been submitted to an agent.</summary>
-                New,
-                /// <summary>A request to cancel a request previously submitted to the agent.</summary>
-                Cancel,
-                /// <summary>A request to unpause the connection associated with a request previously submitted to the agent.</summary>
-                Unpause,
-                /// <summary>A request to shutdown the agent and all active operations.  No easy request is associated with this type.</summary>
-                Shutdown
-            }
-        }
-
-    }
-}
diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/CurlHandler/CurlHandler.SslProvider.Linux.cs b/src/libraries/System.Net.Http/src/System/Net/Http/CurlHandler/CurlHandler.SslProvider.Linux.cs
deleted file mode 100644 (file)
index 9131817..0000000
+++ /dev/null
@@ -1,449 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Diagnostics;
-using System.IO;
-using System.Net.Security;
-using System.Runtime.InteropServices;
-using System.Security.Authentication;
-using System.Security.Cryptography;
-using System.Security.Cryptography.X509Certificates;
-using System.Threading;
-using System.Threading.Tasks;
-using Microsoft.Win32.SafeHandles;
-
-using CURLcode = Interop.Http.CURLcode;
-using CURLINFO = Interop.Http.CURLINFO;
-
-namespace System.Net.Http
-{
-    internal partial class CurlHandler : HttpMessageHandler
-    {
-        private static class SslProvider
-        {
-            private static readonly Interop.Http.SslCtxCallback s_sslCtxCallback = SslCtxCallback;
-            private static readonly Interop.Ssl.AppVerifyCallback s_sslVerifyCallback = VerifyCertChain;
-            private static readonly Oid s_serverAuthOid = new Oid("1.3.6.1.5.5.7.3.1");
-            private static string _sslCaPath;
-            private static string _sslCaInfo;
-
-            internal static void SetSslOptions(EasyRequest easy, ClientCertificateOption clientCertOption)
-            {
-                EventSourceTrace("ClientCertificateOption: {0}", clientCertOption, easy:easy);
-                Debug.Assert(clientCertOption == ClientCertificateOption.Automatic || clientCertOption == ClientCertificateOption.Manual);
-
-                // Create a client certificate provider if client certs may be used.
-                X509Certificate2Collection clientCertificates = easy._handler._clientCertificates;
-                ClientCertificateProvider certProvider =
-                    clientCertOption == ClientCertificateOption.Automatic ? new ClientCertificateProvider(null) : // automatic
-                    clientCertificates?.Count > 0 ? new ClientCertificateProvider(clientCertificates) : // manual with certs
-                    null; // manual without certs
-                IntPtr userPointer = IntPtr.Zero;
-                if (certProvider != null)
-                {
-                    EventSourceTrace("Created certificate provider", easy:easy);
-
-                    // The client cert provider needs to be passed through to the callback, and thus
-                    // we create a GCHandle to keep it rooted.  This handle needs to be cleaned up
-                    // when the request has completed, and a simple and pay-for-play way to do that
-                    // is by cleaning it up in a continuation off of the request.
-                    userPointer = GCHandle.ToIntPtr(certProvider._gcHandle);
-                    easy.Task.ContinueWith((_, state) => ((IDisposable)state).Dispose(), certProvider,
-                        CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);
-                }
-
-                // Configure the options.  Our best support is when targeting OpenSSL/1.0.  For other backends,
-                // we fall back to a minimal amount of support, and may throw a PNSE based on the options requested.
-                if (Interop.Http.HasMatchingOpenSslVersion)
-                {
-                    // Register the callback with libcurl.  We need to register even if there's no user-provided
-                    // server callback and even if there are no client certificates, because we support verifying
-                    // server certificates against more than those known to OpenSSL.
-                    SetSslOptionsForSupportedBackend(easy, certProvider, userPointer);
-                }
-                else
-                {
-                    // Newer versions of OpenSSL, and other non-OpenSSL backends, do not currently support callbacks.
-                    // That means we'll throw a PNSE if a callback is required.
-                    SetSslOptionsForUnsupportedBackend(easy, certProvider);
-                }
-            }
-
-            private static void SetSslOptionsForSupportedBackend(EasyRequest easy, ClientCertificateProvider certProvider, IntPtr userPointer)
-            {
-                CURLcode answer = easy.SetSslCtxCallback(s_sslCtxCallback, userPointer);
-                EventSourceTrace("Callback registration result: {0}", answer, easy: easy);
-                switch (answer)
-                {
-                    case CURLcode.CURLE_OK:
-                        // We successfully registered.  If we'll be invoking a user-provided callback to verify the server
-                        // certificate as part of that, disable libcurl's verification of the host name; we need to get
-                        // the callback from libcurl even if the host name doesn't match, so we take on the responsibility
-                        // of doing the host name match in the callback prior to invoking the user's delegate.
-                        if (easy._handler.ServerCertificateCustomValidationCallback != null)
-                        {
-                            easy.SetCurlOption(Interop.Http.CURLoption.CURLOPT_SSL_VERIFYHOST, 0);
-                            // But don't change the CURLOPT_SSL_VERIFYPEER setting, as setting it to 0 will
-                            // cause SSL and libcurl to ignore the result of the server callback.
-                        }
-
-                        SetSslOptionsForCertificateStore(easy);
-
-                        // The allowed SSL protocols will be set in the configuration callback.
-                        break;
-
-                    case CURLcode.CURLE_UNKNOWN_OPTION: // Curl 7.38 and prior
-                    case CURLcode.CURLE_NOT_BUILT_IN:   // Curl 7.39 and later
-                        SetSslOptionsForUnsupportedBackend(easy, certProvider);
-                        break;
-
-                    default:
-                        ThrowIfCURLEError(answer);
-                        break;
-                }
-            }
-
-            private static void GetSslCaLocations(out string path, out string info)
-            {
-                // We only provide curl option values when SSL_CERT_FILE or SSL_CERT_DIR is set.
-                // When that is the case, we set the options so curl ends up using the same certificates as the
-                // X509 machine store.
-                path = _sslCaPath;
-                info = _sslCaInfo;
-
-                if (path == null || info == null)
-                {
-                    bool hasEnvironmentVariables = Environment.GetEnvironmentVariable("SSL_CERT_FILE") != null ||
-                                                   Environment.GetEnvironmentVariable("SSL_CERT_DIR") != null;
-
-                    if (hasEnvironmentVariables)
-                    {
-                        path = Interop.Crypto.GetX509RootStorePath();
-                        if (!Directory.Exists(path))
-                        {
-                            // X509 store ignores non-existing.
-                            path = string.Empty;
-                        }
-
-                        info = Interop.Crypto.GetX509RootStoreFile();
-                        if (!File.Exists(info))
-                        {
-                            // X509 store ignores non-existing.
-                            info = string.Empty;
-                        }
-                    }
-                    else
-                    {
-                        path = string.Empty;
-                        info = string.Empty;
-                    }
-                    _sslCaPath = path;
-                    _sslCaInfo = info;
-                }
-            }
-
-            private static void SetSslOptionsForCertificateStore(EasyRequest easy)
-            {
-                // Support specifying certificate directory/bundle via environment variables: SSL_CERT_DIR, SSL_CERT_FILE.
-                GetSslCaLocations(out string sslCaPath, out string sslCaInfo);
-
-                if (sslCaPath != string.Empty)
-                {
-                    easy.SetCurlOption(Interop.Http.CURLoption.CURLOPT_CAPATH, sslCaPath);
-
-                    // https proxy support requires libcurl 7.52.0+
-                    easy.TrySetCurlOption(Interop.Http.CURLoption.CURLOPT_PROXY_CAPATH, sslCaPath);
-                }
-
-                if (sslCaInfo != string.Empty)
-                {
-                    easy.SetCurlOption(Interop.Http.CURLoption.CURLOPT_CAINFO, sslCaInfo);
-
-                    // https proxy support requires libcurl 7.52.0+
-                    easy.TrySetCurlOption(Interop.Http.CURLoption.CURLOPT_PROXY_CAINFO, sslCaInfo);
-                }
-            }
-
-            private static void SetSslOptionsForUnsupportedBackend(EasyRequest easy, ClientCertificateProvider certProvider)
-            {
-                if (certProvider != null)
-                {
-                    throw new PlatformNotSupportedException(SR.Format(SR.net_http_libcurl_clientcerts_notsupported_sslbackend, CurlVersionDescription, CurlSslVersionDescription, Interop.Http.RequiredOpenSslDescription));
-                }
-
-                if (easy._handler.CheckCertificateRevocationList)
-                {
-                    throw new PlatformNotSupportedException(SR.Format(SR.net_http_libcurl_revocation_notsupported_sslbackend, CurlVersionDescription, CurlSslVersionDescription, Interop.Http.RequiredOpenSslDescription));
-                }
-
-                if (easy._handler.ServerCertificateCustomValidationCallback != null)
-                {
-                    if (easy.ServerCertificateValidationCallbackAcceptsAll)
-                    {
-                        EventSourceTrace("Warning: Disabling peer and host verification per {0}", nameof(HttpClientHandler.DangerousAcceptAnyServerCertificateValidator), easy: easy);
-                        easy.SetCurlOption(Interop.Http.CURLoption.CURLOPT_SSL_VERIFYPEER, 0);
-                        easy.SetCurlOption(Interop.Http.CURLoption.CURLOPT_SSL_VERIFYHOST, 0);
-                    }
-                    else
-                    {
-                        throw new PlatformNotSupportedException(SR.Format(SR.net_http_libcurl_callback_notsupported_sslbackend, CurlVersionDescription, CurlSslVersionDescription, Interop.Http.RequiredOpenSslDescription));
-                    }
-                }
-                else
-                {
-                    SetSslOptionsForCertificateStore(easy);
-                }
-
-                // In case of defaults configure the allowed SSL protocols.
-                SetSslVersion(easy);
-            }
-
-            private static void SetSslVersion(EasyRequest easy, IntPtr sslCtx = default(IntPtr))
-            {
-                // Get the requested protocols.
-                SslProtocols protocols = easy._handler.SslProtocols;
-                if (protocols == SslProtocols.None)
-                {
-                    // Let libcurl use its defaults if None is set.
-                    return;
-                }
-
-                // libcurl supports options for either enabling all of the TLS1.* protocols or enabling
-                // just one protocol; it doesn't currently support enabling two of the three, e.g. you can't
-                // pick TLS1.1 and TLS1.2 but not TLS1.0, but you can select just TLS1.2.
-                Interop.Http.CurlSslVersion curlSslVersion;
-                switch (protocols)
-                {
-#pragma warning disable 0618 // SSL2/3 are deprecated
-                    case SslProtocols.Ssl2:
-                        curlSslVersion = Interop.Http.CurlSslVersion.CURL_SSLVERSION_SSLv2;
-                        break;
-                    case SslProtocols.Ssl3:
-                        curlSslVersion = Interop.Http.CurlSslVersion.CURL_SSLVERSION_SSLv3;
-                        break;
-#pragma warning restore 0618
-
-                    case SslProtocols.Tls:
-                        curlSslVersion = Interop.Http.CurlSslVersion.CURL_SSLVERSION_TLSv1_0;
-                        break;
-                    case SslProtocols.Tls11:
-                        curlSslVersion = Interop.Http.CurlSslVersion.CURL_SSLVERSION_TLSv1_1;
-                        break;
-                    case SslProtocols.Tls12:
-                        curlSslVersion = Interop.Http.CurlSslVersion.CURL_SSLVERSION_TLSv1_2;
-                        break;
-                    case SslProtocols.Tls13:
-                        curlSslVersion = Interop.Http.CurlSslVersion.CURL_SSLVERSION_TLSv1_3;
-                        break;
-
-                    case SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12:
-                    case SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12 | SslProtocols.Tls13:
-                        curlSslVersion = Interop.Http.CurlSslVersion.CURL_SSLVERSION_TLSv1;
-                        break;
-
-                    default:
-                        throw new NotSupportedException(SR.net_securityprotocolnotsupported);
-                }
-
-                try
-                {
-                    easy.SetCurlOption(Interop.Http.CURLoption.CURLOPT_SSLVERSION, (long)curlSslVersion);
-                }
-                catch (CurlException e) when (e.HResult == (int)CURLcode.CURLE_UNKNOWN_OPTION)
-                {
-                    throw new NotSupportedException(SR.net_securityprotocolnotsupported, e);
-                }
-            }
-
-            private static CURLcode SslCtxCallback(IntPtr curl, IntPtr sslCtx, IntPtr userPointer)
-            {
-                EasyRequest easy;
-                if (!TryGetEasyRequest(curl, out easy))
-                {
-                    return CURLcode.CURLE_ABORTED_BY_CALLBACK;
-                }
-                EventSourceTrace(null, easy: easy);
-
-                // Configure the SSL protocols allowed.
-                SslProtocols protocols = easy._handler.SslProtocols;
-                if (protocols == SslProtocols.None)
-                {
-                    // If None is selected, let OpenSSL use its defaults, but with SSL2/3 explicitly disabled.
-                    // Since the shim/OpenSSL work on a disabling system, where any protocols for which bits aren't
-                    // set are disabled, we set all of the bits other than those we want disabled.
-#pragma warning disable 0618 // the enum values are obsolete
-                    protocols = ~(SslProtocols.Ssl2 | SslProtocols.Ssl3);
-#pragma warning restore 0618
-                }
-                Interop.Ssl.SetProtocolOptions(sslCtx, protocols);
-
-                // Configure the SSL server certificate verification callback.
-                Interop.Ssl.SslCtxSetCertVerifyCallback(sslCtx, s_sslVerifyCallback, curl);
-
-                // If a client certificate provider was provided, also configure the client certificate callback.
-                if (userPointer != IntPtr.Zero)
-                {
-                    try
-                    {
-                        // Provider is passed in via a GCHandle.  Get the provider, which contains
-                        // the client certificate callback delegate.
-                        GCHandle handle = GCHandle.FromIntPtr(userPointer);
-                        ClientCertificateProvider provider = (ClientCertificateProvider)handle.Target;
-                        if (provider == null)
-                        {
-                            Debug.Fail($"Expected non-null provider in {nameof(SslCtxCallback)}");
-                            return CURLcode.CURLE_ABORTED_BY_CALLBACK;
-                        }
-
-                        // Register the callback.
-                        Interop.Ssl.SslCtxSetClientCertCallback(sslCtx, provider._callback);
-                        EventSourceTrace("Registered client certificate callback.", easy: easy);
-                    }
-                    catch (Exception e)
-                    {
-                        Debug.Fail($"Exception in {nameof(SslCtxCallback)}", e.ToString());
-                        return CURLcode.CURLE_ABORTED_BY_CALLBACK;
-                    }
-                }
-
-                return CURLcode.CURLE_OK;
-            }
-
-            private static bool TryGetEasyRequest(IntPtr curlPtr, out EasyRequest easy)
-            {
-                Debug.Assert(curlPtr != IntPtr.Zero, "curlPtr is not null");
-
-                IntPtr gcHandlePtr;
-                CURLcode getInfoResult = Interop.Http.EasyGetInfoPointer(curlPtr, CURLINFO.CURLINFO_PRIVATE, out gcHandlePtr);
-                if (getInfoResult == CURLcode.CURLE_OK)
-                {
-                    return MultiAgent.TryGetEasyRequestFromGCHandle(gcHandlePtr, out easy);
-                }
-
-                Debug.Fail($"Failed to get info on a completing easy handle: {getInfoResult}");
-                easy = null;
-                return false;
-            }
-
-            private static int VerifyCertChain(IntPtr storeCtxPtr, IntPtr curlPtr)
-            {
-                const int SuccessResult = 1, FailureResult = 0;
-
-                EasyRequest easy;
-                if (!TryGetEasyRequest(curlPtr, out easy))
-                {
-                    EventSourceTrace("Could not find associated easy request: {0}", curlPtr);
-                    return FailureResult;
-                }
-
-                var storeCtx = new SafeX509StoreCtxHandle(storeCtxPtr, ownsHandle: false);
-                try
-                {
-                    return VerifyCertChain(storeCtx, easy) ? SuccessResult : FailureResult;
-                }
-                catch (Exception exc)
-                {
-                    EventSourceTrace("Unexpected exception: {0}", exc, easy: easy);
-                    easy.FailRequest(CreateHttpRequestException(new CurlException((int)CURLcode.CURLE_ABORTED_BY_CALLBACK, exc)));
-                    return FailureResult;
-                }
-                finally
-                {
-                    storeCtx.Dispose();
-                }
-            }
-
-            private static bool VerifyCertChain(SafeX509StoreCtxHandle storeCtx, EasyRequest easy)
-            {
-                IntPtr leafCertPtr = Interop.Crypto.X509StoreCtxGetTargetCert(storeCtx);
-                if (leafCertPtr == IntPtr.Zero)
-                {
-                    EventSourceTrace("Invalid certificate pointer", easy: easy);
-                    return false;
-                }
-
-                X509Certificate2[] otherCerts = null;
-                int otherCertsCount = 0;
-                var leafCert = new X509Certificate2(leafCertPtr);
-                try
-                {
-                    // We need to respect the user's server validation callback if there is one.  If there isn't one,
-                    // we can start by first trying to use OpenSSL's verification, though only if CRL checking is disabled,
-                    // as OpenSSL doesn't do that.
-                    if (easy._handler.ServerCertificateCustomValidationCallback == null &&
-                        !easy._handler.CheckCertificateRevocationList)
-                    {
-                        // Start by using the default verification provided directly by OpenSSL.
-                        // If it succeeds in verifying the cert chain, we're done. Employing this instead of
-                        // our custom implementation will need to be revisited if we ever decide to introduce a
-                        // "disallowed" store that enables users to "untrust" certs the system trusts.
-                        if (Interop.Crypto.X509VerifyCert(storeCtx))
-                        {
-                            return true;
-                        }
-                    }
-
-                    // Either OpenSSL verification failed, or there was a server validation callback
-                    // or certificate revocation checking was enabled. Either way, fall back to manual
-                    // and more expensive verification that includes checking the user's certs (not
-                    // just the system store ones as OpenSSL does).
-                    using (var chain = new X509Chain())
-                    {
-                        chain.ChainPolicy.RevocationMode = easy._handler.CheckCertificateRevocationList ? X509RevocationMode.Online : X509RevocationMode.NoCheck;
-                        chain.ChainPolicy.RevocationFlag = X509RevocationFlag.ExcludeRoot;
-
-                        using (SafeSharedX509StackHandle extraStack = Interop.Crypto.X509StoreCtxGetSharedUntrusted(storeCtx))
-                        {
-                            if (extraStack.IsInvalid)
-                            {
-                                otherCerts = Array.Empty<X509Certificate2>();
-                            }
-                            else
-                            {
-                                int extraSize = Interop.Crypto.GetX509StackFieldCount(extraStack);
-                                otherCerts = new X509Certificate2[extraSize];
-
-                                for (int i = 0; i < extraSize; i++)
-                                {
-                                    IntPtr certPtr = Interop.Crypto.GetX509StackField(extraStack, i);
-                                    if (certPtr != IntPtr.Zero)
-                                    {
-                                        X509Certificate2 cert = new X509Certificate2(certPtr);
-                                        otherCerts[otherCertsCount++] = cert;
-                                        chain.ChainPolicy.ExtraStore.Add(cert);
-                                    }
-                                }
-                            }
-                        }
-
-                        var serverCallback = easy._handler._serverCertificateValidationCallback;
-                        if (serverCallback == null)
-                        {
-                            SslPolicyErrors errors = CertificateValidation.BuildChainAndVerifyProperties(chain, leafCert,
-                                checkCertName: false, hostName: null); // libcurl already verifies the host name
-                            return errors == SslPolicyErrors.None;
-                        }
-                        else
-                        {
-                            // Authenticate the remote party: (e.g. when operating in client mode, authenticate the server).
-                            chain.ChainPolicy.ApplicationPolicy.Add(s_serverAuthOid);
-
-                            SslPolicyErrors errors = CertificateValidation.BuildChainAndVerifyProperties(chain, leafCert,
-                                checkCertName: true, hostName: easy._requestMessage.RequestUri.Host); // we disabled automatic host verification, so we do it here
-                            return serverCallback(easy._requestMessage, leafCert, chain, errors);
-                        }
-                    }
-                }
-                finally
-                {
-                    for (int i = 0; i < otherCertsCount; i++)
-                    {
-                        otherCerts[i].Dispose();
-                    }
-                    leafCert.Dispose();
-                }
-            }
-        }
-    }
-}
diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/CurlHandler/CurlHandler.SslProvider.OSX.cs b/src/libraries/System.Net.Http/src/System/Net/Http/CurlHandler/CurlHandler.SslProvider.OSX.cs
deleted file mode 100644 (file)
index 1725d4e..0000000
+++ /dev/null
@@ -1,152 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Diagnostics;
-using System.Security.Authentication;
-using System.Security.Cryptography.X509Certificates;
-
-using CURLcode = Interop.Http.CURLcode;
-
-namespace System.Net.Http
-{
-    internal partial class CurlHandler : HttpMessageHandler
-    {
-        private static class SslProvider
-        {
-            internal static void SetSslOptions(EasyRequest easy, ClientCertificateOption clientCertOption)
-            {
-                Debug.Assert(
-                    clientCertOption == ClientCertificateOption.Automatic ||
-                    clientCertOption == ClientCertificateOption.Manual);
-
-                // Create a client certificate provider if client certs may be used.
-                X509Certificate2Collection clientCertificates = easy._handler._clientCertificates;
-
-                if (clientCertOption != ClientCertificateOption.Manual || clientCertificates?.Count > 0)
-                {
-                    // libcurl does not have an option of accepting a SecIdentityRef via an input option,
-                    // only via writing it to a file and letting it load the PFX.
-                    // This would require that a) we write said file, and b) that it contaminate the default
-                    // keychain (because their PFX loader loads to the default keychain).
-                    throw new PlatformNotSupportedException(SR.net_http_libcurl_clientcerts_notsupported_os);
-                }
-
-                // Revocation checking is always on for darwinssl (SecureTransport).
-                // If any other backend is used and revocation is requested, we can't guarantee
-                // that assertion.
-                if (easy._handler.CheckCertificateRevocationList &&
-                    !CurlSslVersionDescription.Equals(Interop.Http.SecureTransportDescription))
-                {
-                    throw new PlatformNotSupportedException(
-                        SR.Format(
-                            SR.net_http_libcurl_revocation_notsupported_sslbackend,
-                            CurlVersionDescription,
-                            CurlSslVersionDescription,
-                            Interop.Http.SecureTransportDescription));
-                }
-
-                if (easy._handler.ServerCertificateCustomValidationCallback != null)
-                {
-                    // libcurl (as of 7.49.1) does not have any callback which can be registered which fires
-                    // between the time that a TLS/SSL handshake has offered up the server certificate and the
-                    // time that the HTTP request headers are written.  Were there any callback, the option
-                    // CURLINFO_TLS_SSL_PTR could be queried (and the backend identifier validated to be
-                    // CURLSSLBACKEND_DARWINSSL). Then the SecTrustRef could be extracted to build the chain,
-                    // a la SslStream.
-                    //
-                    // Without the callback the matrix looks like:
-                    // * If default-trusted and callback-would-trust: No difference (except side effects, like logging).
-                    // * If default-trusted and callback-would-block: Data would have been sent in violation of user trust.
-                    // * If not-default-trusted and callback-would-not-trust: No difference (except side effects).
-                    // * If not-default-trusted and callback-would-trust: No data sent, which doesn't match user desires.
-                    //
-                    // Of the two "different" cases, sending when we shouldn't is worse, so that's the direction we
-                    // have to cater to. So we'll use default trust, and throw on any custom callback.
-                    //
-                    // The situation where system trust fails can be remedied by including the certificate into the
-                    // user's keychain and setting the SSL policy trust for it to "Always Trust".
-                    // Similarly, the "block this" could be attained by setting the SSL policy for a cert in the
-                    // keychain to "Never Trust".
-                    //
-                    // However, one case we can support is when we know all certificates will pass validation.
-                    // We can detect a key case of that: whether DangerousAcceptAnyServerCertificateValidator was used.
-                    if (easy.ServerCertificateValidationCallbackAcceptsAll)
-                    {
-                        EventSourceTrace("Warning: Disabling peer verification per {0}", nameof(HttpClientHandler.DangerousAcceptAnyServerCertificateValidator), easy: easy);
-                        easy.SetCurlOption(Interop.Http.CURLoption.CURLOPT_SSL_VERIFYPEER, 0); // don't verify the peer
-
-                        // Don't set CURLOPT_SSL_VERIFHOST to 0; doing so disables SNI with SecureTransport backend.
-                        if (!CurlSslVersionDescription.Equals(Interop.Http.SecureTransportDescription))
-                        {
-                            easy.SetCurlOption(Interop.Http.CURLoption.CURLOPT_SSL_VERIFYHOST, 0); // don't verify the hostname
-                        }
-                    }
-                    else
-                    {
-                        throw new PlatformNotSupportedException(SR.net_http_libcurl_callback_notsupported_os);
-                    }
-                }
-
-                SetSslVersion(easy);
-            }
-
-            private static void SetSslVersion(EasyRequest easy)
-            {
-                // Get the requested protocols.
-                SslProtocols protocols = easy._handler.SslProtocols;
-                if (protocols == SslProtocols.None)
-                {
-                    // Let libcurl use its defaults if None is set.
-                    return;
-                }
-
-                // libcurl supports options for either enabling all of the TLS1.* protocols or enabling
-                // just one protocol; it doesn't currently support enabling two of the three, e.g. you can't
-                // pick TLS1.1 and TLS1.2 but not TLS1.0, but you can select just TLS1.2.
-                Interop.Http.CurlSslVersion curlSslVersion;
-                switch (protocols)
-                {
-#pragma warning disable 0618 // SSL2/3 are deprecated
-                    case SslProtocols.Ssl2:
-                        curlSslVersion = Interop.Http.CurlSslVersion.CURL_SSLVERSION_SSLv2;
-                        break;
-                    case SslProtocols.Ssl3:
-                        curlSslVersion = Interop.Http.CurlSslVersion.CURL_SSLVERSION_SSLv3;
-                        break;
-#pragma warning restore 0618
-
-                    case SslProtocols.Tls:
-                        curlSslVersion = Interop.Http.CurlSslVersion.CURL_SSLVERSION_TLSv1_0;
-                        break;
-                    case SslProtocols.Tls11:
-                        curlSslVersion = Interop.Http.CurlSslVersion.CURL_SSLVERSION_TLSv1_1;
-                        break;
-                    case SslProtocols.Tls12:
-                        curlSslVersion = Interop.Http.CurlSslVersion.CURL_SSLVERSION_TLSv1_2;
-                        break;
-                    case SslProtocols.Tls13:
-                        curlSslVersion = Interop.Http.CurlSslVersion.CURL_SSLVERSION_TLSv1_3;
-                        break;
-
-                    case SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12:
-                    case SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12 | SslProtocols.Tls13:
-                        curlSslVersion = Interop.Http.CurlSslVersion.CURL_SSLVERSION_TLSv1;
-                        break;
-
-                    default:
-                        throw new NotSupportedException(SR.net_securityprotocolnotsupported);
-                }
-
-                try
-                {
-                    easy.SetCurlOption(Interop.Http.CURLoption.CURLOPT_SSLVERSION, (long)curlSslVersion);
-                }
-                catch (CurlException e) when (e.HResult == (int)CURLcode.CURLE_UNKNOWN_OPTION)
-                {
-                    throw new NotSupportedException(SR.net_securityprotocolnotsupported, e);
-                }
-            }
-        }
-    }
-}
diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/CurlHandler/CurlHandler.cs b/src/libraries/System.Net.Http/src/System/Net/Http/CurlHandler/CurlHandler.cs
deleted file mode 100644 (file)
index 0979454..0000000
+++ /dev/null
@@ -1,786 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.IO;
-using System.Net.Security;
-using System.Runtime.CompilerServices;
-using System.Security.Authentication;
-using System.Security.Cryptography.X509Certificates;
-using System.Threading;
-using System.Threading.Tasks;
-
-using CURLAUTH = Interop.Http.CURLAUTH;
-using CURLcode = Interop.Http.CURLcode;
-using CURLMcode = Interop.Http.CURLMcode;
-using CURLoption = Interop.Http.CURLoption;
-
-namespace System.Net.Http
-{
-    // Object model:
-    // -------------
-    // CurlHandler provides an HttpMessageHandler implementation that wraps libcurl.  The core processing for CurlHandler
-    // is handled via a CurlHandler.MultiAgent instance, where currently a CurlHandler instance stores and uses a single
-    // MultiAgent for the lifetime of the handler (with the MultiAgent lazily initialized on first use, so that it can
-    // be initialized with all of the configured options on the handler).  The MultiAgent is named as such because it wraps
-    // a libcurl multi handle that's responsible for handling all requests on the instance.  When a request arrives, it's
-    // queued to the MultiAgent, which ensures that a thread is running to continually loop and process all work associated
-    // with the multi handle until no more work is required; at that point, the thread is retired until more work arrives,
-    // at which point another thread will be spun up.  Any number of requests will have their handling multiplexed onto
-    // this one event loop thread.  Each request is represented by a CurlHandler.EasyRequest, so named because it wraps
-    // a libcurl easy handle, libcurl's representation of a request.  The EasyRequest stores all state associated with
-    // the request, including the CurlHandler.CurlResponseMessage and CurlHandler.CurlResponseStream that are handed
-    // back to the caller to provide access to the HTTP response information.
-    //
-    // Lifetime:
-    // ---------
-    // The MultiAgent is initialized on first use and is kept referenced by the CurlHandler for the remainder of the
-    // handler's lifetime.  Both are disposable, and disposing of the CurlHandler will dispose of the MultiAgent.
-    // However, libcurl is not thread safe in that two threads can't be using the same multi or easy handles concurrently,
-    // so any interaction with the multi handle must happen on the MultiAgent's thread.  For this reason, the
-    // SafeHandle storing the underlying multi handle has its ref count incremented when the MultiAgent worker is running
-    // and decremented when it stops running, enabling any disposal requests to be delayed until the worker has quiesced.
-    // To enable that to happen quickly when a dispose operation occurs, an "incoming request" (how all other threads
-    // communicate with the MultiAgent worker) is queued to the worker to request a shutdown; upon receiving that request,
-    // the worker will exit and allow the multi handle to be disposed of.
-    //
-    // An EasyRequest itself doesn't govern its own lifetime.  Since an easy handle is added to a multi handle for
-    // the multi handle to process, the easy handle must not be destroyed until after it's been removed from the multi handle.
-    // As such, once the SafeHandle for an easy handle is created, although its stored in the EasyRequest instance,
-    // it's also stored into a dictionary on the MultiAgent and has its ref count incremented to prevent it from being
-    // disposed of while it's in use by the multi handle.
-    //
-    // When a request is made to the CurlHandler, callbacks are registered with libcurl, including state that will
-    // be passed back into managed code and used to identify the associated EasyRequest.  This means that the native
-    // code needs to be able both to keep the EasyRequest alive and to refer to it using an IntPtr.  For this, we
-    // use a GCHandle to the EasyRequest.  However, the native code needs to be able to refer to the EasyRequest for the
-    // lifetime of the request, but we also need to avoid keeping the EasyRequest (and all state it references) alive artificially.
-    // For the beginning phase of the request, the native code may be the only thing referencing the managed objects, since
-    // when a caller invokes "Task<HttpResponseMessage> SendAsync(...)", there's nothing handed back to the caller that represents
-    // the request until at least the HTTP response headers are received and the returned Task is completed with the response
-    // message object.  However, after that point, if the caller drops the HttpResponseMessage, we also want to cancel and
-    // dispose of the associated state, which means something needs to be finalizable and not kept rooted while at the same
-    // time still allowing the native code to continue using its GCHandle and lookup the associated state as long as it's alive.
-    // Yet then when an async read is made on the response message, we want to postpone such finalization and ensure that the async
-    // read can be appropriately completed with control and reference ownership given back to the reader. As such, we do two things:
-    // we make the response stream finalizable, and we make the GCHandle be to a wrapper object for the EasyRequest rather than to
-    // the EasyRequest itself.  That wrapper object maintains a weak reference to the EasyRequest as well as sometimes maintaining
-    // a strong reference.  When the request starts out, the GCHandle is created to the wrapper, which has a strong reference to
-    // the EasyRequest (which also back references to the wrapper so that the wrapper can be accessed via it).  The GCHandle is
-    // thus keeping the EasyRequest and all of the state it references alive, e.g. the CurlResponseStream, which itself has a reference
-    // back to the EasyRequest.  Once the request progresses to the point of receiving HTTP response headers and the HttpResponseMessage
-    // is handed back to the caller, the wrapper object drops its strong reference and maintains only a weak reference.  At this
-    // point, if the caller were to drop its HttpResponseMessage object, that would also drop the only strong reference to the
-    // CurlResponseStream; the CurlResponseStream would be available for collection and finalization, and its finalization would
-    // request cancellation of the easy request to the multi agent.  The multi agent would then in response remove the easy handle
-    // from the multi handle and decrement the ref count on the SafeHandle for the easy handle, allowing it to be finalized and
-    // the underlying easy handle released.  If instead of dropping the HttpResponseMessage the caller makes a read request on the
-    // response stream, the wrapper object is transitioned back to having a strong reference, so that even if the caller then drops
-    // the HttpResponseMessage, the read Task returned from the read operation will still be completed eventually, at which point
-    // the wrapper will transition back to being a weak reference.
-    //
-    // Even with that, of course, Dispose is still the recommended way of cleaning things up.  Disposing the CurlResponseMessage
-    // will Dispose the CurlResponseStream, which will Dispose of the SafeHandle for the easy handle and request that the MultiAgent
-    // cancel the operation.  Once canceled and removed, the SafeHandle will have its ref count decremented and the previous disposal
-    // will proceed to release the underlying handle.
-
-    internal partial class CurlHandler : HttpMessageHandler
-    {
-        #region Constants
-
-        private const string UriSchemeHttp = "http";
-        private const string UriSchemeHttps = "https";
-        private const string EncodingNameGzip = "gzip";
-        private const string EncodingNameDeflate = "deflate";
-
-        private const int MaxRequestBufferSize = 16384; // Default used by libcurl
-        private const string NoTransferEncoding = HttpKnownHeaderNames.TransferEncoding + ":";
-        private const string NoContentType = HttpKnownHeaderNames.ContentType + ":";
-        private const string NoExpect = HttpKnownHeaderNames.Expect + ":";
-
-        #endregion
-
-        #region Fields
-
-        private static readonly KeyValuePair<string, CURLAUTH>[] s_orderedAuthTypes = new KeyValuePair<string, CURLAUTH>[] {
-            new KeyValuePair<string, CURLAUTH>("Negotiate", CURLAUTH.Negotiate),
-            new KeyValuePair<string, CURLAUTH>("NTLM", CURLAUTH.NTLM),
-            new KeyValuePair<string, CURLAUTH>("Digest", CURLAUTH.Digest),
-            new KeyValuePair<string, CURLAUTH>("Basic", CURLAUTH.Basic),
-        };
-
-        private static readonly bool s_supportsAutomaticDecompression;
-        private static readonly bool s_supportsSSL;
-        private static readonly bool s_supportsHttp2Multiplexing;
-        private static string s_curlVersionDescription;
-        private static string s_curlSslVersionDescription;
-
-        private static readonly MultiAgent s_singletonSharedAgent;
-        private readonly MultiAgent _agent;
-        private volatile bool _anyOperationStarted;
-        private volatile bool _disposed;
-
-        private IWebProxy _proxy = null;
-        private ICredentials _serverCredentials = null;
-        private bool _useProxy = HttpHandlerDefaults.DefaultUseProxy;
-        private ICredentials _defaultProxyCredentials = null;
-        private DecompressionMethods _automaticDecompression = HttpHandlerDefaults.DefaultAutomaticDecompression;
-        private bool _preAuthenticate = HttpHandlerDefaults.DefaultPreAuthenticate;
-        private CredentialCache _credentialCache = null; // protected by LockObject
-        private bool _useDefaultCredentials = HttpHandlerDefaults.DefaultUseDefaultCredentials;
-        private CookieContainer _cookieContainer = new CookieContainer();
-        private bool _useCookies = HttpHandlerDefaults.DefaultUseCookies;
-        private bool _automaticRedirection = HttpHandlerDefaults.DefaultAutomaticRedirection;
-        private int _maxAutomaticRedirections = HttpHandlerDefaults.DefaultMaxAutomaticRedirections;
-        private int _maxConnectionsPerServer = HttpHandlerDefaults.DefaultMaxConnectionsPerServer;
-        private int _maxResponseHeadersLength = HttpHandlerDefaults.DefaultMaxResponseHeadersLength;
-        private ClientCertificateOption _clientCertificateOption = HttpHandlerDefaults.DefaultClientCertificateOption;
-        private X509Certificate2Collection _clientCertificates;
-        private Func<HttpRequestMessage, X509Certificate2, X509Chain, SslPolicyErrors, bool> _serverCertificateValidationCallback;
-        private bool _checkCertificateRevocationList = HttpHandlerDefaults.DefaultCheckCertificateRevocationList;
-        private SslProtocols _sslProtocols = SslProtocols.None; // use default
-        private IDictionary<string, object> _properties; // Only create dictionary when required.
-
-        private object LockObject { get { return _agent; } }
-
-        #endregion
-
-#pragma warning disable CA1810 // explicit static cctor
-        static CurlHandler()
-        {
-            // curl_global_init call handled by Interop.LibCurl's cctor
-
-            Interop.Http.CurlFeatures features = Interop.Http.GetSupportedFeatures();
-            s_supportsSSL = (features & Interop.Http.CurlFeatures.CURL_VERSION_SSL) != 0;
-            s_supportsAutomaticDecompression = (features & Interop.Http.CurlFeatures.CURL_VERSION_LIBZ) != 0;
-            s_supportsHttp2Multiplexing = (features & Interop.Http.CurlFeatures.CURL_VERSION_HTTP2) != 0 && Interop.Http.GetSupportsHttp2Multiplexing() && !UseSingletonMultiAgent;
-
-            if (NetEventSource.IsEnabled)
-            {
-                EventSourceTrace($"libcurl: {CurlVersionDescription} {CurlSslVersionDescription} {features}");
-            }
-
-            // By default every CurlHandler gets its own MultiAgent.  But for some backends,
-            // we need to restrict the number of threads involved in processing libcurl work,
-            // so we create a single MultiAgent that's used by all handlers.
-            if (UseSingletonMultiAgent)
-            {
-                s_singletonSharedAgent = new MultiAgent(null);
-            }
-        }
-#pragma warning restore CA1810
-
-        public CurlHandler()
-        {
-            // If the shared MultiAgent was initialized, use it.
-            // Otherwise, create a new MultiAgent for this handler.
-            _agent = s_singletonSharedAgent ?? new MultiAgent(this);
-        }
-
-        #region Properties
-
-        private static string CurlVersionDescription => s_curlVersionDescription ?? (s_curlVersionDescription = Interop.Http.GetVersionDescription() ?? string.Empty);
-        private static string CurlSslVersionDescription => s_curlSslVersionDescription ?? (s_curlSslVersionDescription = Interop.Http.GetSslVersionDescription() ?? string.Empty);
-
-        private static bool UseSingletonMultiAgent
-        {
-            get
-            {
-                // Some backends other than OpenSSL need locks initialized in order to use them in a
-                // multithreaded context, which would happen with multiple HttpClients and thus multiple
-                // MultiAgents. Since we don't currently have the ability to do so initialization, instead we
-                // restrict all HttpClients to use the same MultiAgent instance in this case.  We know LibreSSL
-                // is in this camp, so we currently special-case it.
-                string curlSslVersion = Interop.Http.GetSslVersionDescription();
-                return
-                    !string.IsNullOrEmpty(curlSslVersion) &&
-                    curlSslVersion.StartsWith(Interop.Http.LibreSslDescription, StringComparison.OrdinalIgnoreCase);
-            }
-        }
-
-        internal bool AllowAutoRedirect
-        {
-            get { return _automaticRedirection; }
-            set
-            {
-                CheckDisposedOrStarted();
-                _automaticRedirection = value;
-            }
-        }
-
-        internal bool UseProxy
-        {
-            get { return _useProxy; }
-            set
-            {
-                CheckDisposedOrStarted();
-                _useProxy = value;
-            }
-        }
-
-        internal IWebProxy Proxy
-        {
-            get { return _proxy; }
-            set
-            {
-                CheckDisposedOrStarted();
-                _proxy = value;
-            }
-        }
-
-        internal ICredentials DefaultProxyCredentials
-        {
-            get { return _defaultProxyCredentials; }
-            set
-            {
-                CheckDisposedOrStarted();
-                _defaultProxyCredentials = value;
-            }
-        }
-
-        internal ICredentials Credentials
-        {
-            get { return _serverCredentials; }
-            set { _serverCredentials = value; }
-        }
-
-        internal ClientCertificateOption ClientCertificateOptions
-        {
-            get { return _clientCertificateOption; }
-            set
-            {
-                if (value != ClientCertificateOption.Manual &&
-                    value != ClientCertificateOption.Automatic)
-                {
-                    throw new ArgumentOutOfRangeException(nameof(value));
-                }
-
-                CheckDisposedOrStarted();
-                _clientCertificateOption = value;
-            }
-        }
-
-        internal X509Certificate2Collection ClientCertificates
-        {
-            get
-            {
-                if (_clientCertificateOption != ClientCertificateOption.Manual)
-                {
-                    throw new InvalidOperationException(SR.Format(SR.net_http_invalid_enable_first, nameof(ClientCertificateOptions), nameof(ClientCertificateOption.Manual)));
-                }
-
-                return _clientCertificates ?? (_clientCertificates = new X509Certificate2Collection());
-            }
-        }
-
-        internal Func<HttpRequestMessage, X509Certificate2, X509Chain, SslPolicyErrors, bool> ServerCertificateCustomValidationCallback
-        {
-            get { return _serverCertificateValidationCallback; }
-            set
-            {
-                CheckDisposedOrStarted();
-                _serverCertificateValidationCallback = value;
-            }
-        }
-
-        internal bool CheckCertificateRevocationList
-        {
-            get { return _checkCertificateRevocationList; }
-            set
-            {
-                CheckDisposedOrStarted();
-                _checkCertificateRevocationList = value;
-            }
-        }
-
-        internal SslProtocols SslProtocols
-        {
-            get { return _sslProtocols; }
-            set
-            {
-                CheckDisposedOrStarted();
-                _sslProtocols = value;
-            }
-        }
-
-        internal bool SupportsAutomaticDecompression => s_supportsAutomaticDecompression;
-
-        internal DecompressionMethods AutomaticDecompression
-        {
-            get { return _automaticDecompression; }
-            set
-            {
-                CheckDisposedOrStarted();
-                _automaticDecompression = value;
-            }
-        }
-
-        internal bool PreAuthenticate
-        {
-            get { return _preAuthenticate; }
-            set
-            {
-                CheckDisposedOrStarted();
-                _preAuthenticate = value;
-                if (value && _credentialCache == null)
-                {
-                    _credentialCache = new CredentialCache();
-                }
-            }
-        }
-
-        internal bool UseCookies
-        {
-            get { return _useCookies; }
-            set
-            {
-                CheckDisposedOrStarted();
-                _useCookies = value;
-            }
-        }
-
-        internal CookieContainer CookieContainer
-        {
-            get { return _cookieContainer; }
-            set
-            {
-                CheckDisposedOrStarted();
-                _cookieContainer = value;
-            }
-        }
-
-        internal int MaxAutomaticRedirections
-        {
-            get { return _maxAutomaticRedirections; }
-            set
-            {
-                if (value <= 0)
-                {
-                    throw new ArgumentOutOfRangeException(nameof(value), value, SR.Format(SR.net_http_value_must_be_greater_than, 0));
-                }
-
-                CheckDisposedOrStarted();
-                _maxAutomaticRedirections = value;
-            }
-        }
-
-        internal int MaxConnectionsPerServer
-        {
-            get { return _maxConnectionsPerServer; }
-            set
-            {
-                if (value < 1)
-                {
-                    throw new ArgumentOutOfRangeException(nameof(value), value, SR.Format(SR.net_http_value_must_be_greater_than, 0));
-                }
-
-                CheckDisposedOrStarted();
-                _maxConnectionsPerServer = value;
-            }
-        }
-
-        internal int MaxResponseHeadersLength
-        {
-            get { return _maxResponseHeadersLength; }
-            set
-            {
-                if (value <= 0)
-                {
-                    throw new ArgumentOutOfRangeException(nameof(value), value, SR.Format(SR.net_http_value_must_be_greater_than, 0));
-                }
-
-                CheckDisposedOrStarted();
-                _maxResponseHeadersLength = value;
-            }
-        }
-
-        internal bool UseDefaultCredentials
-        {
-            get { return _useDefaultCredentials; }
-            set
-            {
-                CheckDisposedOrStarted();
-                _useDefaultCredentials = value;
-            }
-        }
-
-        public IDictionary<string, object> Properties
-        {
-            get
-            {
-                if (_properties == null)
-                {
-                    _properties = new Dictionary<string, object>();
-                }
-
-                return _properties;
-            }
-        }
-        #endregion
-
-        protected override void Dispose(bool disposing)
-        {
-            _disposed = true;
-            if (disposing && _agent != s_singletonSharedAgent)
-            {
-                _agent.Dispose();
-            }
-            base.Dispose(disposing);
-        }
-
-        protected internal override Task<HttpResponseMessage> SendAsync(
-            HttpRequestMessage request, CancellationToken cancellationToken)
-        {
-            if (request == null)
-            {
-                throw new ArgumentNullException(nameof(request), SR.net_http_handler_norequest);
-            }
-
-            if (request.RequestUri.Scheme == UriSchemeHttps)
-            {
-                if (!s_supportsSSL)
-                {
-                    throw new PlatformNotSupportedException(SR.Format(SR.net_http_unix_https_support_unavailable_libcurl, CurlVersionDescription));
-                }
-            }
-            else
-            {
-                Debug.Assert(request.RequestUri.Scheme == UriSchemeHttp, "HttpClient expected to validate scheme as http or https.");
-            }
-
-            if (request.Headers.TransferEncodingChunked.GetValueOrDefault() && (request.Content == null))
-            {
-                return Task.FromException<HttpResponseMessage>(
-                    new HttpRequestException(SR.net_http_client_execution_error,
-                        new InvalidOperationException(SR.net_http_chunked_not_allowed_with_empty_content)));
-            }
-
-            if (_useCookies && _cookieContainer == null)
-            {
-                throw new InvalidOperationException(SR.net_http_invalid_cookiecontainer);
-            }
-
-            CheckDisposed();
-            SetOperationStarted();
-
-            // Do an initial cancellation check to avoid initiating the async operation if
-            // cancellation has already been requested.  After this, we'll rely on CancellationToken.Register
-            // to notify us of cancellation requests and shut down the operation if possible.
-            if (cancellationToken.IsCancellationRequested)
-            {
-                return Task.FromCanceled<HttpResponseMessage>(cancellationToken);
-            }
-
-            // Create the easy request.  This associates the easy request with this handler and configures
-            // it based on the settings configured for the handler.
-            var easy = new EasyRequest(this, _agent, request, cancellationToken);
-            try
-            {
-                EventSourceTrace("{0}", request, easy: easy);
-                _agent.Queue(new MultiAgent.IncomingRequest { Easy = easy, Type = MultiAgent.IncomingRequestType.New });
-            }
-            catch (Exception exc)
-            {
-                easy.CleanupAndFailRequest(exc);
-            }
-
-            return easy.Task;
-        }
-
-        #region Private methods
-
-        private void SetOperationStarted()
-        {
-            if (!_anyOperationStarted)
-            {
-                _anyOperationStarted = true;
-            }
-        }
-
-        private KeyValuePair<NetworkCredential, CURLAUTH> GetCredentials(Uri requestUri)
-        {
-            // If preauthentication is enabled, we may have populated our internal credential cache,
-            // so first check there to see if we have any credentials for this uri.
-            if (_preAuthenticate)
-            {
-                KeyValuePair<NetworkCredential, CURLAUTH> ncAndScheme;
-                lock (LockObject)
-                {
-                    Debug.Assert(_credentialCache != null, "Expected non-null credential cache");
-                    ncAndScheme = GetCredentials(requestUri, _credentialCache, s_orderedAuthTypes);
-                }
-                if (ncAndScheme.Key != null)
-                {
-                    return ncAndScheme;
-                }
-            }
-
-            // We either weren't preauthenticating or we didn't have any cached credentials
-            // available, so check the credentials on the handler.
-            return GetCredentials(requestUri, _serverCredentials, s_orderedAuthTypes);
-        }
-
-        private void TransferCredentialsToCache(Uri serverUri, CURLAUTH serverAuthAvail)
-        {
-            if (_serverCredentials == null)
-            {
-                // No credentials, nothing to put into the cache.
-                return;
-            }
-
-            lock (LockObject)
-            {
-                // For each auth type we allow, check whether it's one supported by the server.
-                KeyValuePair<string, CURLAUTH>[] validAuthTypes = s_orderedAuthTypes;
-                for (int i = 0; i < validAuthTypes.Length; i++)
-                {
-                    // Is it supported by the server?
-                    if ((serverAuthAvail & validAuthTypes[i].Value) != 0)
-                    {
-                        // And do we have a credential for it?
-                        NetworkCredential nc = _serverCredentials.GetCredential(serverUri, validAuthTypes[i].Key);
-                        if (nc != null)
-                        {
-                            // We have a credential for it, so add it, and we're done.
-                            Debug.Assert(_credentialCache != null, "Expected non-null credential cache");
-                            try
-                            {
-                                _credentialCache.Add(serverUri, validAuthTypes[i].Key, nc);
-                            }
-                            catch (ArgumentException)
-                            {
-                                // Ignore the case of key already present
-                            }
-                            break;
-                        }
-                    }
-                }
-            }
-        }
-
-        private void AddResponseCookies(EasyRequest state, string cookieHeader)
-        {
-            if (!_useCookies)
-            {
-                return;
-            }
-
-            try
-            {
-                _cookieContainer.SetCookies(state._requestMessage.RequestUri, cookieHeader);
-                state.SetCookieOption(state._requestMessage.RequestUri);
-            }
-            catch (CookieException e)
-            {
-                EventSourceTrace(
-                    "Malformed cookie parsing failed: {0}, server: {1}, cookie: {2}",
-                    e.Message, state._requestMessage.RequestUri, cookieHeader,
-                    easy: state);
-            }
-        }
-
-        private static KeyValuePair<NetworkCredential, CURLAUTH> GetCredentials(Uri requestUri, ICredentials credentials, KeyValuePair<string, CURLAUTH>[] validAuthTypes)
-        {
-            NetworkCredential nc = null;
-            CURLAUTH curlAuthScheme = CURLAUTH.None;
-
-            if (credentials != null)
-            {
-                // For each auth type we consider valid, try to get a credential for it.
-                // Union together the auth types for which we could get credentials, but validate
-                // that the found credentials are all the same, as libcurl doesn't support differentiating
-                // by auth type.
-                for (int i = 0; i < validAuthTypes.Length; i++)
-                {
-                    NetworkCredential networkCredential = credentials.GetCredential(requestUri, validAuthTypes[i].Key);
-                    if (networkCredential != null)
-                    {
-                        curlAuthScheme |= validAuthTypes[i].Value;
-                        if (nc == null)
-                        {
-                            nc = networkCredential;
-                        }
-                        else if (!AreEqualNetworkCredentials(nc, networkCredential))
-                        {
-                            throw new PlatformNotSupportedException(SR.Format(SR.net_http_unix_invalid_credential, CurlVersionDescription));
-                        }
-                    }
-                }
-            }
-
-            EventSourceTrace("Authentication scheme: {0}", curlAuthScheme);
-            return new KeyValuePair<NetworkCredential, CURLAUTH>(nc, curlAuthScheme); ;
-        }
-
-        private void CheckDisposed()
-        {
-            if (_disposed)
-            {
-                throw new ObjectDisposedException(GetType().FullName);
-            }
-        }
-
-        private void CheckDisposedOrStarted()
-        {
-            CheckDisposed();
-            if (_anyOperationStarted)
-            {
-                throw new InvalidOperationException(SR.net_http_operation_started);
-            }
-        }
-
-        private static void ThrowIfCURLEError(CURLcode error)
-        {
-            if (error != CURLcode.CURLE_OK) // success
-            {
-                string msg = CurlException.GetCurlErrorString((int)error, isMulti: false);
-                EventSourceTrace(msg);
-                switch (error)
-                {
-                    case CURLcode.CURLE_OPERATION_TIMEDOUT:
-                        throw new OperationCanceledException(msg);
-
-                    case CURLcode.CURLE_OUT_OF_MEMORY:
-                        throw new OutOfMemoryException(msg);
-
-                    case CURLcode.CURLE_SEND_FAIL_REWIND:
-                        throw new InvalidOperationException(msg);
-
-                    default:
-                        throw new CurlException((int)error, msg);
-                }
-            }
-        }
-
-        private static void ThrowIfCURLMError(CURLMcode error)
-        {
-            if (error != CURLMcode.CURLM_OK && // success
-                error != CURLMcode.CURLM_CALL_MULTI_PERFORM) // success + a hint to try curl_multi_perform again
-            {
-                string msg = CurlException.GetCurlErrorString((int)error, isMulti: true);
-                EventSourceTrace(msg);
-                switch (error)
-                {
-                    case CURLMcode.CURLM_ADDED_ALREADY:
-                    case CURLMcode.CURLM_BAD_EASY_HANDLE:
-                    case CURLMcode.CURLM_BAD_HANDLE:
-                    case CURLMcode.CURLM_BAD_SOCKET:
-                        throw new ArgumentException(msg);
-                    case CURLMcode.CURLM_UNKNOWN_OPTION:
-                        throw new ArgumentOutOfRangeException(msg);
-                    case CURLMcode.CURLM_OUT_OF_MEMORY:
-                        throw new OutOfMemoryException(msg);
-                    case CURLMcode.CURLM_INTERNAL_ERROR:
-                    default:
-                        throw new CurlException((int)error, msg);
-                }
-            }
-        }
-
-        private static bool AreEqualNetworkCredentials(NetworkCredential credential1, NetworkCredential credential2)
-        {
-            Debug.Assert(credential1 != null && credential2 != null, "arguments are non-null in network equality check");
-            return credential1.UserName == credential2.UserName &&
-                credential1.Domain == credential2.Domain &&
-                string.Equals(credential1.Password, credential2.Password, StringComparison.Ordinal);
-        }
-
-        // PERF NOTE:
-        // These generic overloads of EventSourceTrace (and similar wrapper methods in some of the other CurlHandler
-        // nested types) exist to allow call sites to call EventSourceTrace without boxing and without checking
-        // NetEventSource.IsEnabled.  Do not remove these without fixing the call sites accordingly.
-
-        private static void EventSourceTrace<TArg0>(
-            string formatMessage, TArg0 arg0,
-            MultiAgent agent = null, EasyRequest easy = null, [CallerMemberName] string memberName = null)
-        {
-            if (NetEventSource.IsEnabled)
-            {
-                EventSourceTraceCore(string.Format(formatMessage, arg0), agent, easy, memberName);
-            }
-        }
-
-        private static void EventSourceTrace<TArg0, TArg1, TArg2>
-            (string formatMessage, TArg0 arg0, TArg1 arg1, TArg2 arg2,
-            MultiAgent agent = null, EasyRequest easy = null, [CallerMemberName] string memberName = null)
-        {
-            if (NetEventSource.IsEnabled)
-            {
-                EventSourceTraceCore(string.Format(formatMessage, arg0, arg1, arg2), agent, easy, memberName);
-            }
-        }
-
-        private static void EventSourceTrace(
-            string message,
-            MultiAgent agent = null, EasyRequest easy = null, [CallerMemberName] string memberName = null)
-        {
-            if (NetEventSource.IsEnabled)
-            {
-                EventSourceTraceCore(message, agent, easy, memberName);
-            }
-        }
-
-        private static void EventSourceTraceCore(string message, MultiAgent agent, EasyRequest easy, string memberName)
-        {
-            // If we weren't handed a multi agent, see if we can get one from the EasyRequest
-            if (agent == null && easy != null)
-            {
-                agent = easy._associatedMultiAgent;
-            }
-
-            NetEventSource.Log.HandlerMessage(
-                agent?.GetHashCode() ?? 0,
-                (agent?.RunningWorkerId).GetValueOrDefault(),
-                easy?.Task.Id ?? 0,
-                memberName,
-                message);
-        }
-
-        private static HttpRequestException CreateHttpRequestException(Exception inner)
-        {
-            return new HttpRequestException(SR.net_http_client_execution_error, inner);
-        }
-
-        private static IOException MapToReadWriteIOException(Exception error, bool isRead)
-        {
-            return new IOException(
-                isRead ? SR.net_http_io_read : SR.net_http_io_write,
-                error is HttpRequestException && error.InnerException != null ? error.InnerException : error);
-        }
-
-        private static void SetChunkedModeForSend(HttpRequestMessage request)
-        {
-            bool chunkedMode = request.Headers.TransferEncodingChunked.GetValueOrDefault();
-            HttpContent requestContent = request.Content;
-            Debug.Assert(requestContent != null, "request is null");
-
-            // Deal with conflict between 'Content-Length' vs. 'Transfer-Encoding: chunked' semantics.
-            // libcurl adds a Transfer-Encoding header by default and the request fails if both are set.
-            // ISSUE: 25163
-            // Ideally we want to avoid modifying the users request message.
-            if (requestContent.Headers.ContentLength.HasValue)
-            {
-                if (chunkedMode)
-                {
-                    // Same behaviour as WinHttpHandler
-                    requestContent.Headers.ContentLength = null;
-                }
-                else
-                {
-                    // Prevent libcurl from adding Transfer-Encoding header
-                    request.Headers.TransferEncodingChunked = false;
-                }
-            }
-            else if (!chunkedMode)
-            {
-                // Make sure Transfer-Encoding: chunked header is set,
-                // as we have content to send but no known length for it.
-                request.Headers.TransferEncodingChunked = true;
-            }
-        }
-
-        #endregion
-    }
-}
diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/CurlHandler/CurlResponseHeaderReader.cs b/src/libraries/System.Net.Http/src/System/Net/Http/CurlHandler/CurlResponseHeaderReader.cs
deleted file mode 100644 (file)
index 6aa23ea..0000000
+++ /dev/null
@@ -1,301 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Diagnostics;
-using System.Runtime.InteropServices;
-
-namespace System.Net.Http
-{
-    internal readonly struct CurlResponseHeaderReader
-    {
-        private const string HttpPrefix = "HTTP/";
-
-        private readonly HeaderBufferSpan _span;
-
-        public CurlResponseHeaderReader(IntPtr buffer, ulong size)
-        {
-            Debug.Assert(buffer != IntPtr.Zero);
-            Debug.Assert(size <= int.MaxValue);
-
-            _span = new HeaderBufferSpan(buffer, (int)size).Trim();
-        }
-
-        public bool ReadStatusLine(HttpResponseMessage response)
-        {
-            if (!_span.StartsWithHttpPrefix())
-            {
-                return false;
-            }
-
-            int index = HttpPrefix.Length;
-            int majorVersion = _span.ReadInt(ref index);
-            CheckResponseMsgFormat(majorVersion != 0);
-            CheckResponseMsgFormat(index < _span.Length);
-
-            int minorVersion;
-            if (_span[index] == '.')
-            {
-                index++;
-
-                CheckResponseMsgFormat(index < _span.Length && _span[index] >= '0' && _span[index] <= '9');
-                minorVersion = _span.ReadInt(ref index);
-            }
-            else
-            {
-                minorVersion = 0;
-            }
-
-            CheckResponseMsgFormat(_span.SkipSpace(ref index));
-
-            // Parse status code.
-            int statusCode = _span.ReadInt(ref index);
-            CheckResponseMsgFormat(statusCode >= 100 && statusCode < 1000);
-
-            bool foundSpace = _span.SkipSpace(ref index);
-            CheckResponseMsgFormat(index <= _span.Length);
-            CheckResponseMsgFormat(foundSpace || index == _span.Length);
-
-            // Set the response HttpVersion.
-            response.Version =
-                (majorVersion == 1 && minorVersion == 1) ? HttpVersion.Version11 :
-                (majorVersion == 1 && minorVersion == 0) ? HttpVersion.Version10 :
-                (majorVersion == 2 && minorVersion == 0) ? HttpVersion.Version20 :
-                HttpVersion.Unknown;
-
-            response.StatusCode = (HttpStatusCode)statusCode;
-
-            // Try to use a known reason phrase instead of allocating a new string.
-            HeaderBufferSpan reasonPhraseSpan = _span.Slice(index);
-            string knownReasonPhrase = HttpStatusDescription.Get(response.StatusCode);
-            response.ReasonPhrase = reasonPhraseSpan.EqualsOrdinal(knownReasonPhrase) ?
-                knownReasonPhrase :
-                reasonPhraseSpan.ToString();
-
-            return true;
-        }
-
-        public bool ReadHeader(out string headerName, out string headerValue)
-        {
-            int index = 0;
-            while (index < _span.Length && ValidHeaderNameChar(_span[index]))
-            {
-                index++;
-            }
-
-            if (index > 0)
-            {
-                // For compatability, skip past any whitespace before the colon, even though
-                // the RFC suggests there shouldn't be any.
-                int headerNameLength = index;
-                while (index < _span.Length && IsWhiteSpaceLatin1(_span[index]))
-                {
-                    index++;
-                }
-
-                CheckResponseMsgFormat(index < _span.Length);
-                CheckResponseMsgFormat(_span[index] == ':');
-                HeaderBufferSpan headerNameSpan = _span.Slice(0, headerNameLength);
-                if (!HttpKnownHeaderNames.TryGetHeaderName(headerNameSpan.Buffer, headerNameSpan.Length, out headerName))
-                {
-                    headerName = headerNameSpan.ToString();
-                }
-                CheckResponseMsgFormat(headerName.Length > 0);
-
-                index++;
-                headerValue = _span.Slice(index).Trim().ToString();
-                return true;
-            }
-
-            headerName = null;
-            headerValue = null;
-            return false;
-        }
-
-        private static void CheckResponseMsgFormat(bool condition)
-        {
-            if (!condition)
-            {
-                throw new HttpRequestException(SR.net_http_invalid_response);
-            }
-        }
-
-        private static bool ValidHeaderNameChar(byte c)
-        {
-            const string invalidChars = "()<>@,;:\\\"/[]?={}";
-            return c > ' ' && !invalidChars.Contains((char)c);
-        }
-
-        internal static bool IsWhiteSpaceLatin1(byte c)
-        {
-            // SPACE
-            // U+0009 = <control> HORIZONTAL TAB
-            // U+000a = <control> LINE FEED
-            // U+000b = <control> VERTICAL TAB
-            // U+000c = <control> FORM FEED
-            // U+000d = <control> CARRIAGE RETURN
-            // U+0085 = <control> NEXT LINE
-            // U+00a0 = NO-BREAK SPACE
-            return c == ' ' || (c >= '\x0009' && c <= '\x000d') || c == '\x00a0' || c == '\x0085';
-        }
-
-        private readonly unsafe struct HeaderBufferSpan
-        {
-            private readonly byte* _pointer;
-            public readonly int Length;
-
-            public static readonly HeaderBufferSpan Empty = default(HeaderBufferSpan);
-
-            public HeaderBufferSpan(IntPtr pointer, int length)
-                : this((byte*)pointer, length)
-            {
-            }
-
-            public HeaderBufferSpan(byte* pointer, int length)
-            {
-                Debug.Assert(pointer != null);
-                Debug.Assert(length >= 0);
-
-                _pointer = pointer;
-                Length = length;
-            }
-
-            public IntPtr Buffer => new IntPtr(_pointer);
-
-            public byte this[int index]
-            {
-                get
-                {
-                    Debug.Assert(index >= 0 && index < Length);
-                    return _pointer[index];
-                }
-            }
-
-            public HeaderBufferSpan Trim()
-            {
-                if (Length == 0)
-                {
-                    return Empty;
-                }
-
-                int index = 0;
-                while (index < Length && IsWhiteSpaceLatin1(_pointer[index]))
-                {
-                    index++;
-                }
-
-                int end = Length - 1;
-                while (end >= index && IsWhiteSpaceLatin1(_pointer[end]))
-                {
-                    end--;
-                }
-
-                byte* pointer = _pointer + index;
-                int length = end - index + 1;
-
-                return new HeaderBufferSpan(pointer, length);
-            }
-
-            public bool StartsWithHttpPrefix()
-            {
-                if (Length < HttpPrefix.Length)
-                {
-                    return false;
-                }
-
-                return
-                    (_pointer[0] == 'H' || _pointer[0] == 'h') &&
-                    (_pointer[1] == 'T' || _pointer[1] == 't') &&
-                    (_pointer[2] == 'T' || _pointer[2] == 't') &&
-                    (_pointer[3] == 'P' || _pointer[3] == 'p') &&
-                    (_pointer[4] == '/');
-            }
-
-            public int ReadInt(ref int index)
-            {
-                int value = 0;
-                for (; index < Length; index++)
-                {
-                    byte c = _pointer[index];
-                    if (c < '0' || c > '9')
-                    {
-                        break;
-                    }
-
-                    value = (value * 10) + (c - '0');
-                }
-
-                return value;
-            }
-
-            public bool SkipSpace(ref int index)
-            {
-                bool foundSpace = false;
-                for (; index < Length; index++)
-                {
-                    if (_pointer[index] == ' ' || _pointer[index] == '\t')
-                    {
-                        foundSpace = true;
-                    }
-                    else
-                    {
-                        break;
-                    }
-                }
-                return foundSpace;
-            }
-
-            public bool EqualsOrdinal(string value)
-            {
-                if (value == null)
-                {
-                    return false;
-                }
-
-                if (Length != value.Length)
-                {
-                    return false;
-                }
-
-                for (int i = 0; i < Length; i++)
-                {
-                    if (_pointer[i] != value[i])
-                    {
-                        return false;
-                    }
-                }
-
-                return true;
-            }
-
-            public HeaderBufferSpan Slice(int startIndex)
-            {
-                return Slice(startIndex, Length - startIndex);
-            }
-
-            public HeaderBufferSpan Slice(int startIndex, int length)
-            {
-                Debug.Assert(startIndex >= 0);
-                Debug.Assert(length >= 0);
-                Debug.Assert(startIndex <= Length - length);
-
-                if (length == 0)
-                {
-                    return Empty;
-                }
-
-                if (startIndex == 0 && length == Length)
-                {
-                    return this;
-                }
-
-                return new HeaderBufferSpan(_pointer + startIndex, length);
-            }
-
-            public override string ToString()
-            {
-                return Length == 0 ? string.Empty : HttpRuleParser.DefaultHttpEncoding.GetString(_pointer, Length);
-            }
-        }
-    }
-}
index d2881e9..3124db1 100644 (file)
@@ -13,39 +13,27 @@ namespace System.Net.Http
 {
     public partial class HttpClientHandler : HttpMessageHandler
     {
-        // Only one of these two handlers will be initialized.
-        private readonly CurlHandler _curlHandler;
         private readonly SocketsHttpHandler _socketsHttpHandler;
         private readonly DiagnosticsHandler _diagnosticsHandler;
         private ClientCertificateOption _clientCertificateOptions;
 
-        public HttpClientHandler() : this(UseSocketsHttpHandler) { }
-
-        private HttpClientHandler(bool useSocketsHttpHandler) // used by parameterless ctor and as hook for testing
+        public HttpClientHandler()
         {
-            if (useSocketsHttpHandler)
-            {
-                _socketsHttpHandler = new SocketsHttpHandler();
-                _diagnosticsHandler = new DiagnosticsHandler(_socketsHttpHandler);
-                ClientCertificateOptions = ClientCertificateOption.Manual;
-            }
-            else
-            {
-                _curlHandler = new CurlHandler();
-                _diagnosticsHandler = new DiagnosticsHandler(_curlHandler);
-            }
+            _socketsHttpHandler = new SocketsHttpHandler();
+            _diagnosticsHandler = new DiagnosticsHandler(_socketsHttpHandler);
+            ClientCertificateOptions = ClientCertificateOption.Manual;
         }
 
         protected override void Dispose(bool disposing)
         {
             if (disposing)
             {
-                ((HttpMessageHandler)_curlHandler ?? _socketsHttpHandler).Dispose();
+                _socketsHttpHandler.Dispose();
             }
             base.Dispose(disposing);
         }
 
-        public virtual bool SupportsAutomaticDecompression => _curlHandler == null || _curlHandler.SupportsAutomaticDecompression;
+        public virtual bool SupportsAutomaticDecompression => true;
 
         public virtual bool SupportsProxy => true;
 
@@ -53,23 +41,13 @@ namespace System.Net.Http
 
         public bool UseCookies
         {
-            get => _curlHandler != null ? _curlHandler.UseCookies : _socketsHttpHandler.UseCookies;
-            set
-            {
-                if (_curlHandler != null)
-                {
-                    _curlHandler.UseCookies = value;
-                }
-                else
-                {
-                    _socketsHttpHandler.UseCookies = value;
-                }
-            }
+            get => _socketsHttpHandler.UseCookies;
+            set => _socketsHttpHandler.UseCookies = value;
         }
 
         public CookieContainer CookieContainer
         {
-            get => _curlHandler != null ? _curlHandler.CookieContainer : _socketsHttpHandler.CookieContainer;
+            get => _socketsHttpHandler.CookieContainer;
             set
             {
                 if (value == null)
@@ -77,55 +55,31 @@ namespace System.Net.Http
                     throw new ArgumentNullException(nameof(value));
                 }
 
-                if (_curlHandler != null)
-                {
-                    _curlHandler.CookieContainer = value;
-                }
-                else
-                {
-                    _socketsHttpHandler.CookieContainer = value;
-                }
+                _socketsHttpHandler.CookieContainer = value;
             }
         }
 
         public ClientCertificateOption ClientCertificateOptions
         {
-            get
-            {
-                if (_curlHandler != null)
-                {
-                    return _curlHandler.ClientCertificateOptions;
-                }
-                else
-                {
-                    return _clientCertificateOptions;
-                }
-            }
+            get => _clientCertificateOptions;
             set
             {
-                if (_curlHandler != null)
+                switch (value)
                 {
-                    _curlHandler.ClientCertificateOptions = value;
-                }
-                else
-                {
-                    switch (value)
-                    {
-                        case ClientCertificateOption.Manual:
-                            ThrowForModifiedManagedSslOptionsIfStarted();
-                            _clientCertificateOptions = value;
-                            _socketsHttpHandler.SslOptions.LocalCertificateSelectionCallback = (sender, targetHost, localCertificates, remoteCertificate, acceptableIssuers) => CertificateHelper.GetEligibleClientCertificate(ClientCertificates);
-                            break;
+                    case ClientCertificateOption.Manual:
+                        ThrowForModifiedManagedSslOptionsIfStarted();
+                        _clientCertificateOptions = value;
+                        _socketsHttpHandler.SslOptions.LocalCertificateSelectionCallback = (sender, targetHost, localCertificates, remoteCertificate, acceptableIssuers) => CertificateHelper.GetEligibleClientCertificate(ClientCertificates);
+                        break;
 
-                        case ClientCertificateOption.Automatic:
-                            ThrowForModifiedManagedSslOptionsIfStarted();
-                            _clientCertificateOptions = value;
-                            _socketsHttpHandler.SslOptions.LocalCertificateSelectionCallback = (sender, targetHost, localCertificates, remoteCertificate, acceptableIssuers) => CertificateHelper.GetEligibleClientCertificate();
-                            break;
+                    case ClientCertificateOption.Automatic:
+                        ThrowForModifiedManagedSslOptionsIfStarted();
+                        _clientCertificateOptions = value;
+                        _socketsHttpHandler.SslOptions.LocalCertificateSelectionCallback = (sender, targetHost, localCertificates, remoteCertificate, acceptableIssuers) => CertificateHelper.GetEligibleClientCertificate();
+                        break;
 
-                        default:
-                            throw new ArgumentOutOfRangeException(nameof(value));
-                    }
+                    default:
+                        throw new ArgumentOutOfRangeException(nameof(value));
                 }
             }
         }
@@ -134,184 +88,94 @@ namespace System.Net.Http
         {
             get
             {
-                if (_curlHandler != null)
+                if (ClientCertificateOptions != ClientCertificateOption.Manual)
                 {
-                    return _curlHandler.ClientCertificates;
+                    throw new InvalidOperationException(SR.Format(SR.net_http_invalid_enable_first, nameof(ClientCertificateOptions), nameof(ClientCertificateOption.Manual)));
                 }
-                else
-                {
-                    if (ClientCertificateOptions != ClientCertificateOption.Manual)
-                    {
-                        throw new InvalidOperationException(SR.Format(SR.net_http_invalid_enable_first, nameof(ClientCertificateOptions), nameof(ClientCertificateOption.Manual)));
-                    }
 
-                    return _socketsHttpHandler.SslOptions.ClientCertificates ??
-                        (_socketsHttpHandler.SslOptions.ClientCertificates = new X509CertificateCollection());
-                }
+                return _socketsHttpHandler.SslOptions.ClientCertificates ??
+                    (_socketsHttpHandler.SslOptions.ClientCertificates = new X509CertificateCollection());
             }
         }
 
         public Func<HttpRequestMessage, X509Certificate2, X509Chain, SslPolicyErrors, bool> ServerCertificateCustomValidationCallback
         {
-            get
-            {
-                return _curlHandler != null ?
-                    _curlHandler.ServerCertificateCustomValidationCallback :
-                    (_socketsHttpHandler.SslOptions.RemoteCertificateValidationCallback?.Target as ConnectHelper.CertificateCallbackMapper)?.FromHttpClientHandler;
-            }
+            get => (_socketsHttpHandler.SslOptions.RemoteCertificateValidationCallback?.Target as ConnectHelper.CertificateCallbackMapper)?.FromHttpClientHandler;
             set
             {
-                if (_curlHandler != null)
-                {
-                    _curlHandler.ServerCertificateCustomValidationCallback = value;
-                }
-                else
-                {
-                    ThrowForModifiedManagedSslOptionsIfStarted();
-                    _socketsHttpHandler.SslOptions.RemoteCertificateValidationCallback = value != null ?
-                        new ConnectHelper.CertificateCallbackMapper(value).ForSocketsHttpHandler :
-                        null;
-                }
+                ThrowForModifiedManagedSslOptionsIfStarted();
+                _socketsHttpHandler.SslOptions.RemoteCertificateValidationCallback = value != null ?
+                    new ConnectHelper.CertificateCallbackMapper(value).ForSocketsHttpHandler :
+                    null;
             }
         }
 
         public bool CheckCertificateRevocationList
         {
-            get => _curlHandler != null ? _curlHandler.CheckCertificateRevocationList : _socketsHttpHandler.SslOptions.CertificateRevocationCheckMode == X509RevocationMode.Online;
+            get => _socketsHttpHandler.SslOptions.CertificateRevocationCheckMode == X509RevocationMode.Online;
             set
             {
-                if (_curlHandler != null)
-                {
-                    _curlHandler.CheckCertificateRevocationList = value;
-                }
-                else
-                {
-                    ThrowForModifiedManagedSslOptionsIfStarted();
-                    _socketsHttpHandler.SslOptions.CertificateRevocationCheckMode = value ? X509RevocationMode.Online : X509RevocationMode.NoCheck;
-                }
+                ThrowForModifiedManagedSslOptionsIfStarted();
+                _socketsHttpHandler.SslOptions.CertificateRevocationCheckMode = value ? X509RevocationMode.Online : X509RevocationMode.NoCheck;
             }
         }
 
         public SslProtocols SslProtocols
         {
-            get => _curlHandler != null ? _curlHandler.SslProtocols : _socketsHttpHandler.SslOptions.EnabledSslProtocols;
+            get => _socketsHttpHandler.SslOptions.EnabledSslProtocols;
             set
             {
-                if (_curlHandler != null)
-                {
-                    _curlHandler.SslProtocols = value;
-                }
-                else
-                {
-                    ThrowForModifiedManagedSslOptionsIfStarted();
-                    _socketsHttpHandler.SslOptions.EnabledSslProtocols = value;
-                }
+                ThrowForModifiedManagedSslOptionsIfStarted();
+                _socketsHttpHandler.SslOptions.EnabledSslProtocols = value;
             }
         }
 
         public DecompressionMethods AutomaticDecompression
         {
-            get => _curlHandler != null ? _curlHandler.AutomaticDecompression : _socketsHttpHandler.AutomaticDecompression;
-            set
-            {
-                if (_curlHandler != null)
-                {
-                    _curlHandler.AutomaticDecompression = value;
-                }
-                else
-                {
-                    _socketsHttpHandler.AutomaticDecompression = value;
-                }
-            }
+            get => _socketsHttpHandler.AutomaticDecompression;
+            set => _socketsHttpHandler.AutomaticDecompression = value;
         }
 
         public bool UseProxy
         {
-            get => _curlHandler != null ? _curlHandler.UseProxy : _socketsHttpHandler.UseProxy;
-            set
-            {
-                if (_curlHandler != null)
-                {
-                    _curlHandler.UseProxy = value;
-                }
-                else
-                {
-                    _socketsHttpHandler.UseProxy = value;
-                }
-            }
+            get => _socketsHttpHandler.UseProxy;
+            set => _socketsHttpHandler.UseProxy = value;
         }
 
         public IWebProxy Proxy
         {
-            get => _curlHandler != null ? _curlHandler.Proxy : _socketsHttpHandler.Proxy;
-            set
-            {
-                if (_curlHandler != null)
-                {
-                    _curlHandler.Proxy = value;
-                }
-                else
-                {
-                    _socketsHttpHandler.Proxy = value;
-                }
-            }
+            get => _socketsHttpHandler.Proxy;
+            set => _socketsHttpHandler.Proxy = value;
         }
 
         public ICredentials DefaultProxyCredentials
         {
-            get => _curlHandler != null ? _curlHandler.DefaultProxyCredentials : _socketsHttpHandler.DefaultProxyCredentials;
-            set
-            {
-                if (_curlHandler != null)
-                {
-                    _curlHandler.DefaultProxyCredentials = value;
-                }
-                else
-                {
-                    _socketsHttpHandler.DefaultProxyCredentials = value;
-                }
-            }
+            get => _socketsHttpHandler.DefaultProxyCredentials;
+            set => _socketsHttpHandler.DefaultProxyCredentials = value;
         }
 
         public bool PreAuthenticate
         {
-            get => _curlHandler != null ? _curlHandler.PreAuthenticate : _socketsHttpHandler.PreAuthenticate;
-            set
-            {
-                if (_curlHandler != null)
-                {
-                    _curlHandler.PreAuthenticate = value;
-                }
-                else
-                {
-                    _socketsHttpHandler.PreAuthenticate = value;
-                }
-            }
+            get => _socketsHttpHandler.PreAuthenticate;
+            set => _socketsHttpHandler.PreAuthenticate = value;
         }
 
         public bool UseDefaultCredentials
         {
-            // Either read variable from curlHandler or compare .Credentials as socketsHttpHandler does not have separate prop.
-            get => _curlHandler != null ? _curlHandler.UseDefaultCredentials : _socketsHttpHandler.Credentials == CredentialCache.DefaultCredentials;
+            // Compare .Credentials as socketsHttpHandler does not have separate prop.
+            get => _socketsHttpHandler.Credentials == CredentialCache.DefaultCredentials;
             set
             {
-                if (_curlHandler != null)
+                if (value)
                 {
-                    _curlHandler.UseDefaultCredentials = value;
+                    _socketsHttpHandler.Credentials = CredentialCache.DefaultCredentials;
                 }
                 else
                 {
-                    if (value)
+                    if (_socketsHttpHandler.Credentials == CredentialCache.DefaultCredentials)
                     {
-                        _socketsHttpHandler.Credentials = CredentialCache.DefaultCredentials;
-                    }
-                    else
-                    {
-                        if (_socketsHttpHandler.Credentials == CredentialCache.DefaultCredentials)
-                        {
-                            // Only clear out the Credentials property if it was a DefaultCredentials.
-                            _socketsHttpHandler.Credentials = null;
-                        }
+                        // Only clear out the Credentials property if it was a DefaultCredentials.
+                        _socketsHttpHandler.Credentials = null;
                     }
                 }
             }
@@ -319,91 +183,38 @@ namespace System.Net.Http
 
         public ICredentials Credentials
         {
-            get => _curlHandler != null ? _curlHandler.Credentials : _socketsHttpHandler.Credentials;
-            set
-            {
-                if (_curlHandler != null)
-                {
-                    _curlHandler.Credentials = value;
-                }
-                else
-                {
-                    _socketsHttpHandler.Credentials = value;
-                }
-            }
+            get => _socketsHttpHandler.Credentials;
+            set => _socketsHttpHandler.Credentials = value;
         }
 
         public bool AllowAutoRedirect
         {
-            get => _curlHandler != null ? _curlHandler.AllowAutoRedirect : _socketsHttpHandler.AllowAutoRedirect;
-            set
-            {
-                if (_curlHandler != null)
-                {
-                    _curlHandler.AllowAutoRedirect = value;
-                }
-                else
-                {
-                    _socketsHttpHandler.AllowAutoRedirect = value;
-                }
-            }
+            get => _socketsHttpHandler.AllowAutoRedirect;
+            set => _socketsHttpHandler.AllowAutoRedirect = value;
         }
 
         public int MaxAutomaticRedirections
         {
-            get => _curlHandler != null ? _curlHandler.MaxAutomaticRedirections : _socketsHttpHandler.MaxAutomaticRedirections;
-            set
-            {
-                if (_curlHandler != null)
-                {
-                    _curlHandler.MaxAutomaticRedirections = value;
-                }
-                else
-                {
-                    _socketsHttpHandler.MaxAutomaticRedirections = value;
-                }
-            }
+            get => _socketsHttpHandler.MaxAutomaticRedirections;
+            set => _socketsHttpHandler.MaxAutomaticRedirections = value;
         }
 
         public int MaxConnectionsPerServer
         {
-            get => _curlHandler != null ? _curlHandler.MaxConnectionsPerServer : _socketsHttpHandler.MaxConnectionsPerServer;
-            set
-            {
-                if (_curlHandler != null)
-                {
-                    _curlHandler.MaxConnectionsPerServer = value;
-                }
-                else
-                {
-                    _socketsHttpHandler.MaxConnectionsPerServer = value;
-                }
-            }
+            get => _socketsHttpHandler.MaxConnectionsPerServer;
+            set => _socketsHttpHandler.MaxConnectionsPerServer = value;
         }
 
         public int MaxResponseHeadersLength
         {
-            get => _curlHandler != null ? _curlHandler.MaxResponseHeadersLength : _socketsHttpHandler.MaxResponseHeadersLength;
-            set
-            {
-                if (_curlHandler != null)
-                {
-                    _curlHandler.MaxResponseHeadersLength = value;
-                }
-                else
-                {
-                    _socketsHttpHandler.MaxResponseHeadersLength = value;
-                }
-            }
+            get => _socketsHttpHandler.MaxResponseHeadersLength;
+            set => _socketsHttpHandler.MaxResponseHeadersLength = value;
         }
 
-        public IDictionary<string, object> Properties => _curlHandler != null ?
-            _curlHandler.Properties :
-            _socketsHttpHandler.Properties;
+        public IDictionary<string, object> Properties => _socketsHttpHandler.Properties;
 
         protected internal override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) =>
             DiagnosticsHandler.IsEnabled() ? _diagnosticsHandler.SendAsync(request, cancellationToken) :
-            _curlHandler != null ? _curlHandler.SendAsync(request, cancellationToken) :
             _socketsHttpHandler.SendAsync(request, cancellationToken);
     }
 }
index 1be42c0..d88483c 100644 (file)
@@ -28,7 +28,7 @@ namespace System.Net.Http
                 string envVar = Environment.GetEnvironmentVariable(SocketsHttpHandlerEnvironmentVariableSettingName);
                 if (envVar != null && (envVar.Equals("false", StringComparison.OrdinalIgnoreCase) || envVar.Equals("0")))
                 {
-                    // Use WinHttpHandler on Windows and CurlHandler on Unix.
+                    // Use WinHttpHandler on Windows.
                     return false;
                 }
 
index 367a1ef..31e1c97 100644 (file)
@@ -18,20 +18,8 @@ namespace System.Net.Http.Functional.Tests
 
     public abstract class HttpClientEKUTest : HttpClientHandlerTestBase
     {
-        // Curl + OSX SecureTransport doesn't support the custom certificate callback.
-        private static bool BackendSupportsCustomCertificateHandling =>
-#if TargetsWindows
-            true;
-#else
-            TestHelper.NativeHandlerSupportsSslConfiguration();
-#endif
-
         private static bool CanTestCertificates =>
-            Capability.IsTrustedRootCertificateInstalled() &&
-            (BackendSupportsCustomCertificateHandling || Capability.AreHostsFileNamesInstalled());
-
-        private static bool CanTestClientCertificates =>
-            CanTestCertificates && BackendSupportsCustomCertificateHandling;
+            Capability.IsTrustedRootCertificateInstalled() && Capability.AreHostsFileNamesInstalled();
 
         public const int TestTimeoutMilliseconds = 15 * 1000;
 
@@ -91,7 +79,7 @@ namespace System.Net.Http.Functional.Tests
             }
         }
 
-        [ConditionalFact(nameof(CanTestClientCertificates))]
+        [ConditionalFact(nameof(CanTestCertificates))]
         public async Task HttpClient_NoEKUClientAuth_Ok()
         {
             var options = new HttpsTestServer.Options();
@@ -115,7 +103,7 @@ namespace System.Net.Http.Functional.Tests
             }
         }
 
-        [ConditionalFact(nameof(CanTestClientCertificates))]
+        [ConditionalFact(nameof(CanTestCertificates))]
         public async Task HttpClient_ServerEKUClientAuth_Fails()
         {
             var options = new HttpsTestServer.Options();
index 7f81963..308331b 100644 (file)
@@ -63,40 +63,6 @@ namespace System.Net.Http.Functional.Tests
             }
         }
 
-        [OuterLoop("Uses external server")]
-        [Fact]
-        public async Task Automatic_SSLBackendNotSupported_ThrowsPlatformNotSupportedException()
-        {
-            if (BackendSupportsCustomCertificateHandling) // can't use [Conditional*] right now as it's evaluated at the wrong time for SocketsHttpHandler
-            {
-                return;
-            }
-
-            using (HttpClientHandler handler = CreateHttpClientHandler())
-            using (HttpClient client = CreateHttpClient(handler))
-            {
-                handler.ClientCertificateOptions = ClientCertificateOption.Automatic;
-                await Assert.ThrowsAsync<PlatformNotSupportedException>(() => client.GetAsync(Configuration.Http.SecureRemoteEchoServer));
-            }
-        }
-
-        [OuterLoop("Uses external server")]
-        [Fact]
-        public async Task Manual_SSLBackendNotSupported_ThrowsPlatformNotSupportedException()
-        {
-            if (BackendSupportsCustomCertificateHandling) // can't use [Conditional*] right now as it's evaluated at the wrong time for SocketsHttpHandler
-            {
-                return;
-            }
-
-            HttpClientHandler handler = CreateHttpClientHandler();
-            handler.ClientCertificates.Add(Configuration.Certificates.GetClientCertificate());
-            using (HttpClient client = CreateHttpClient(handler))
-            {
-                await Assert.ThrowsAsync<PlatformNotSupportedException>(() => client.GetAsync(Configuration.Http.SecureRemoteEchoServer));
-            }
-        }
-
         private HttpClient CreateHttpClientWithCert(X509Certificate2 cert)
         {
             HttpClientHandler handler = CreateHttpClientHandler();
@@ -114,12 +80,6 @@ namespace System.Net.Http.Functional.Tests
         [InlineData(3, false)]
         public async Task Manual_CertificateOnlySentWhenValid_Success(int certIndex, bool serverExpectsClientCertificate)
         {
-            if (!BackendSupportsCustomCertificateHandling || IsCurlHandler) // can't use [Conditional*] right now as it's evaluated at the wrong time for SocketsHttpHandler
-            {
-                _output.WriteLine($"Skipping {nameof(Manual_CertificateOnlySentWhenValid_Success)}()");
-                return;
-            }
-
             var options = new LoopbackServer.Options { UseSsl = true };
 
             X509Certificate2 GetClientCertificate(int certIndex) => certIndex switch
@@ -170,12 +130,6 @@ namespace System.Net.Http.Functional.Tests
             int numberOfRequests,
             bool reuseClient) // validate behavior with and without connection pooling, which impacts client cert usage
         {
-            if (!BackendSupportsCustomCertificateHandling) // can't use [Conditional*] right now as it's evaluated at the wrong time for SocketsHttpHandler
-            {
-                _output.WriteLine($"Skipping {nameof(Manual_CertificateSentMatchesCertificateReceived_Success)}()");
-                return;
-            }
-
             var options = new LoopbackServer.Options { UseSsl = true };
 
             async Task MakeAndValidateRequest(HttpClient client, LoopbackServer server, Uri url, X509Certificate2 cert)
@@ -231,12 +185,6 @@ namespace System.Net.Http.Functional.Tests
         [InlineData(ClientCertificateOption.Automatic)]
         public async Task AutomaticOrManual_DoesntFailRegardlessOfWhetherClientCertsAreAvailable(ClientCertificateOption mode)
         {
-            if (!BackendSupportsCustomCertificateHandling) // can't use [Conditional*] right now as it's evaluated at the wrong time for SocketsHttpHandler
-            {
-                _output.WriteLine($"Skipping {nameof(AutomaticOrManual_DoesntFailRegardlessOfWhetherClientCertsAreAvailable)}()");
-                return;
-            }
-
             using (HttpClientHandler handler = CreateHttpClientHandler())
             using (HttpClient client = CreateHttpClient(handler))
             {
@@ -256,23 +204,5 @@ namespace System.Net.Http.Functional.Tests
                 }, new LoopbackServer.Options { UseSsl = true });
             }
         }
-
-        private bool BackendSupportsCustomCertificateHandling
-        {
-            get
-            {
-#if TargetsWindows
-                return true;
-#else
-                if (UseSocketsHttpHandler)
-                {
-                    // Socket Handler is independent of platform curl.
-                    return true;
-                }
-
-                return TestHelper.NativeHandlerSupportsSslConfiguration();
-#endif
-            }
-        }
     }
 }
diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.ServerCertificates.Unix.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.ServerCertificates.Unix.cs
deleted file mode 100644 (file)
index 8bf3034..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.IO;
-using System.Net.Security;
-using System.Net.Test.Common;
-using System.Runtime.InteropServices;
-using System.Security.Authentication.ExtendedProtection;
-using System.Security.Cryptography.X509Certificates;
-using System.Threading.Tasks;
-using Microsoft.DotNet.RemoteExecutor;
-using Xunit;
-
-namespace System.Net.Http.Functional.Tests
-{
-    public abstract partial class HttpClientHandler_ServerCertificates_Test
-    {
-        private static bool ShouldSuppressRevocationException
-        {
-            get
-            {
-                if (!RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
-                {
-                    return false;
-                }
-
-                // If a run on a clean macOS ever fails we need to consider that "false"
-                // for CheckCertificateRevocationList is actually "use a system default" now,
-                // and may require changing how this option is exposed. Considering the variety of
-                // systems this should probably be complex like
-                // enum RevocationCheckingOption {
-                //     // Use it if able
-                //     BestPlatformSecurity = 0,
-                //     // Don't use it, if that's an option.
-                //     BestPlatformPerformance,
-                //     // Required
-                //     MustCheck,
-                //     // Prohibited
-                //     MustNotCheck,
-                // }
-
-                if (Interop.Http.GetSslVersionDescription() == "SecureTransport")
-                {
-                    return true;
-                }
-                return false;
-            }
-        }
-
-        internal bool BackendSupportsCustomCertificateHandling
-        {
-            get
-            {
-                if (UseSocketsHttpHandler)
-                {
-                    return true;
-                }
-
-                return TestHelper.NativeHandlerSupportsSslConfiguration();
-            }
-        }
-
-        [Fact]
-        [PlatformSpecific(~TestPlatforms.OSX)] // Not implemented
-        public void HttpClientUsesSslCertEnvironmentVariables()
-        {
-            // We set SSL_CERT_DIR and SSL_CERT_FILE to empty locations.
-            // The HttpClient should fail to validate the server certificate.
-
-            var psi = new ProcessStartInfo();
-            string sslCertDir = GetTestFilePath();
-            Directory.CreateDirectory(sslCertDir);
-            psi.Environment.Add("SSL_CERT_DIR", sslCertDir);
-
-            string sslCertFile = GetTestFilePath();
-            File.WriteAllText(sslCertFile, "");
-            psi.Environment.Add("SSL_CERT_FILE", sslCertFile);
-
-            RemoteExecutor.Invoke(async (useSocketsHttpHandlerString, useHttp2String) =>
-            {
-                const string Url = "https://www.microsoft.com";
-
-                using (HttpClient client = CreateHttpClient(useSocketsHttpHandlerString, useHttp2String))
-                {
-                    await Assert.ThrowsAsync<HttpRequestException>(() => client.GetAsync(Url));
-                }
-            }, UseSocketsHttpHandler.ToString(), UseHttp2.ToString(), new RemoteInvokeOptions { StartInfo = psi }).Dispose();
-        }
-    }
-}
diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.ServerCertificates.Windows.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.ServerCertificates.Windows.cs
deleted file mode 100644 (file)
index e590398..0000000
+++ /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.
-// See the LICENSE file in the project root for more information.
-
-namespace System.Net.Http.Functional.Tests
-{
-    public abstract partial class HttpClientHandler_ServerCertificates_Test
-    {
-        private static bool ShouldSuppressRevocationException => false;
-
-        internal bool BackendSupportsCustomCertificateHandling => true;
-    }
-}
index 357d986..58ada76 100644 (file)
@@ -3,6 +3,8 @@
 // See the LICENSE file in the project root for more information.
 
 using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
 using System.Linq;
 using System.Net.Security;
 using System.Net.Test.Common;
@@ -21,8 +23,6 @@ namespace System.Net.Http.Functional.Tests
     public abstract partial class HttpClientHandler_ServerCertificates_Test : HttpClientHandlerTestBase
     {
         private static bool ClientSupportsDHECipherSuites => (!PlatformDetection.IsWindows || PlatformDetection.IsWindows10Version1607OrGreater);
-        private bool BackendSupportsCustomCertificateHandlingAndClientSupportsDHECipherSuites =>
-            (BackendSupportsCustomCertificateHandling && ClientSupportsDHECipherSuites);
 
         public HttpClientHandler_ServerCertificates_Test(ITestOutputHelper output) : base(output) { }
 
@@ -78,11 +78,6 @@ namespace System.Net.Http.Functional.Tests
         [Fact]
         public async Task UseCallback_HaveCredsAndUseAuthenticatedCustomProxyAndPostToSecureServer_Success()
         {
-            if (!BackendSupportsCustomCertificateHandling)
-            {
-                return;
-            }
-
             if (IsWinHttpHandler && PlatformDetection.IsWindows7)
             {
                 // Issue #27612
@@ -125,11 +120,6 @@ namespace System.Net.Http.Functional.Tests
         [Fact]
         public async Task UseCallback_HaveNoCredsAndUseAuthenticatedCustomProxyAndPostToSecureServer_ProxyAuthenticationRequiredStatusCode()
         {
-            if (!BackendSupportsCustomCertificateHandling)
-            {
-                return;
-            }
-
             var options = new LoopbackProxyServer.Options
                 { AuthenticationSchemes = AuthenticationSchemes.Basic,
                   ConnectionCloseAfter407 = true
@@ -153,12 +143,6 @@ namespace System.Net.Http.Functional.Tests
         [Fact]
         public async Task UseCallback_NotSecureConnection_CallbackNotCalled()
         {
-            if (!BackendSupportsCustomCertificateHandling)
-            {
-                Console.WriteLine($"Skipping {nameof(UseCallback_NotSecureConnection_CallbackNotCalled)}()");
-                return;
-            }
-
             HttpClientHandler handler = CreateHttpClientHandler();
             using (HttpClient client = CreateHttpClient(handler))
             {
@@ -203,12 +187,6 @@ namespace System.Net.Http.Functional.Tests
         [MemberData(nameof(UseCallback_ValidCertificate_ExpectedValuesDuringCallback_Urls))]
         public async Task UseCallback_ValidCertificate_ExpectedValuesDuringCallback(Configuration.Http.RemoteServer remoteServer, Uri url, bool checkRevocation)
         {
-            if (!BackendSupportsCustomCertificateHandling)
-            {
-                Console.WriteLine($"Skipping {nameof(UseCallback_ValidCertificate_ExpectedValuesDuringCallback)}({url}, {checkRevocation})");
-                return;
-            }
-
             HttpClientHandler handler = CreateHttpClientHandler();
             using (HttpClient client = CreateHttpClientForRemoteServer(remoteServer, handler))
             {
@@ -251,12 +229,6 @@ namespace System.Net.Http.Functional.Tests
         [Fact]
         public async Task UseCallback_CallbackReturnsFailure_ThrowsException()
         {
-            if (!BackendSupportsCustomCertificateHandling)
-            {
-                Console.WriteLine($"Skipping {nameof(UseCallback_CallbackReturnsFailure_ThrowsException)}()");
-                return;
-            }
-
             HttpClientHandler handler = CreateHttpClientHandler();
             using (HttpClient client = CreateHttpClient(handler))
             {
@@ -269,12 +241,6 @@ namespace System.Net.Http.Functional.Tests
         [Fact]
         public async Task UseCallback_CallbackThrowsException_ExceptionPropagatesAsBaseException()
         {
-            if (!BackendSupportsCustomCertificateHandling)
-            {
-                Console.WriteLine($"Skipping {nameof(UseCallback_CallbackThrowsException_ExceptionPropagatesAsBaseException)}()");
-                return;
-            }
-
             HttpClientHandler handler = CreateHttpClientHandler();
             using (HttpClient client = CreateHttpClient(handler))
             {
@@ -321,7 +287,7 @@ namespace System.Net.Http.Functional.Tests
             }
             catch (HttpRequestException)
             {
-                if (UseSocketsHttpHandler || !ShouldSuppressRevocationException)
+                if (UseSocketsHttpHandler)
                     throw;
             }
         }
@@ -330,12 +296,6 @@ namespace System.Net.Http.Functional.Tests
         [Fact]
         public async Task NoCallback_RevokedCertificate_RevocationChecking_Fails()
         {
-            if (!BackendSupportsCustomCertificateHandling)
-            {
-                Console.WriteLine($"Skipping {nameof(NoCallback_RevokedCertificate_RevocationChecking_Fails)}()");
-                return;
-            }
-
             HttpClientHandler handler = CreateHttpClientHandler();
             handler.CheckCertificateRevocationList = true;
             using (HttpClient client = CreateHttpClient(handler))
@@ -353,12 +313,6 @@ namespace System.Net.Http.Functional.Tests
 
         private async Task UseCallback_BadCertificate_ExpectedPolicyErrors_Helper(string url, string useSocketsHttpHandlerString, string useHttp2String, SslPolicyErrors expectedErrors)
         {
-            if (!BackendSupportsCustomCertificateHandling)
-            {
-                Console.WriteLine($"Skipping {nameof(UseCallback_BadCertificate_ExpectedPolicyErrors)}({url}, {expectedErrors})");
-                return;
-            }
-
             HttpClientHandler handler = CreateHttpClientHandler(useSocketsHttpHandlerString, useHttp2String);
             using (HttpClient client = CreateHttpClient(handler, useHttp2String))
             {
@@ -390,7 +344,7 @@ namespace System.Net.Http.Functional.Tests
         {
             const int SEC_E_BUFFER_TOO_SMALL = unchecked((int)0x80090321);
 
-            if (!BackendSupportsCustomCertificateHandlingAndClientSupportsDHECipherSuites)
+            if (!ClientSupportsDHECipherSuites)
             {
                 return;
             }
@@ -409,42 +363,6 @@ namespace System.Net.Http.Functional.Tests
         }
 
         [OuterLoop("Uses external server")]
-        [Fact]
-        public async Task SSLBackendNotSupported_Callback_ThrowsPlatformNotSupportedException()
-        {
-            if (BackendSupportsCustomCertificateHandling)
-            {
-                return;
-            }
-
-            HttpClientHandler handler = CreateHttpClientHandler();
-            handler.ServerCertificateCustomValidationCallback = delegate { return true; }; // Do not use TestHelper.AllowAllCertificates / HttpClientHandler.DangerousAcceptAnyServerCertificateValidator
-            using (HttpClient client = CreateHttpClient(handler))
-            {
-                await Assert.ThrowsAsync<PlatformNotSupportedException>(() => client.GetAsync(Configuration.Http.SecureRemoteEchoServer));
-            }
-        }
-
-        [OuterLoop("Uses external server")]
-        [Fact]
-        // For macOS the "custom handling" means that revocation can't be *disabled*. So this test does not apply.
-        [PlatformSpecific(~TestPlatforms.OSX)]
-        public async Task SSLBackendNotSupported_Revocation_ThrowsPlatformNotSupportedException()
-        {
-            if (BackendSupportsCustomCertificateHandling)
-            {
-                return;
-            }
-
-            HttpClientHandler handler = CreateHttpClientHandler();
-            handler.CheckCertificateRevocationList = true;
-            using (HttpClient client = CreateHttpClient(handler))
-            {
-                await Assert.ThrowsAsync<PlatformNotSupportedException>(() => client.GetAsync(Configuration.Http.SecureRemoteEchoServer));
-            }
-        }
-
-        [OuterLoop("Uses external server")]
         [PlatformSpecific(TestPlatforms.Windows)] // CopyToAsync(Stream, TransportContext) isn't used on unix
         [Fact]
         public async Task PostAsync_Post_ChannelBinding_ConfiguredCorrectly()
@@ -461,37 +379,54 @@ namespace System.Net.Http.Functional.Tests
                 Assert.NotNull(channelBinding);
 
                 // Validate the ChannelBinding's validity.
-                if (BackendSupportsCustomCertificateHandling)
+                Assert.False(channelBinding.IsInvalid, "Expected valid binding");
+                Assert.NotEqual(IntPtr.Zero, channelBinding.DangerousGetHandle());
+
+                // Validate the ChannelBinding's description.
+                string channelBindingDescription = channelBinding.ToString();
+                Assert.NotNull(channelBindingDescription);
+                Assert.NotEmpty(channelBindingDescription);
+                Assert.True((channelBindingDescription.Length + 1) % 3 == 0, $"Unexpected length {channelBindingDescription.Length}");
+                for (int i = 0; i < channelBindingDescription.Length; i++)
                 {
-                    Assert.False(channelBinding.IsInvalid, "Expected valid binding");
-                    Assert.NotEqual(IntPtr.Zero, channelBinding.DangerousGetHandle());
-
-                    // Validate the ChannelBinding's description.
-                    string channelBindingDescription = channelBinding.ToString();
-                    Assert.NotNull(channelBindingDescription);
-                    Assert.NotEmpty(channelBindingDescription);
-                    Assert.True((channelBindingDescription.Length + 1) % 3 == 0, $"Unexpected length {channelBindingDescription.Length}");
-                    for (int i = 0; i < channelBindingDescription.Length; i++)
+                    char c = channelBindingDescription[i];
+                    if (i % 3 == 2)
                     {
-                        char c = channelBindingDescription[i];
-                        if (i % 3 == 2)
-                        {
-                            Assert.Equal(' ', c);
-                        }
-                        else
-                        {
-                            Assert.True((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F'), $"Expected hex, got {c}");
-                        }
+                        Assert.Equal(' ', c);
+                    }
+                    else
+                    {
+                        Assert.True((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F'), $"Expected hex, got {c}");
                     }
                 }
-                else
+            }
+        }
+
+        [Fact]
+        [PlatformSpecific(~TestPlatforms.Linux)]
+        public void HttpClientUsesSslCertEnvironmentVariables()
+        {
+            // We set SSL_CERT_DIR and SSL_CERT_FILE to empty locations.
+            // The HttpClient should fail to validate the server certificate.
+
+            var psi = new ProcessStartInfo();
+            string sslCertDir = GetTestFilePath();
+            Directory.CreateDirectory(sslCertDir);
+            psi.Environment.Add("SSL_CERT_DIR", sslCertDir);
+
+            string sslCertFile = GetTestFilePath();
+            File.WriteAllText(sslCertFile, "");
+            psi.Environment.Add("SSL_CERT_FILE", sslCertFile);
+
+            RemoteExecutor.Invoke(async (useSocketsHttpHandlerString, useHttp2String) =>
+            {
+                const string Url = "https://www.microsoft.com";
+
+                using (HttpClient client = CreateHttpClient(useSocketsHttpHandlerString, useHttp2String))
                 {
-                    // Backend doesn't support getting the details to create the CBT.
-                    Assert.True(channelBinding.IsInvalid, "Expected invalid binding");
-                    Assert.Equal(IntPtr.Zero, channelBinding.DangerousGetHandle());
-                    Assert.Null(channelBinding.ToString());
+                    await Assert.ThrowsAsync<HttpRequestException>(() => client.GetAsync(Url));
                 }
-            }
+            }, UseSocketsHttpHandler.ToString(), UseHttp2.ToString(), new RemoteInvokeOptions { StartInfo = psi }).Dispose();
         }
     }
 }
diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.SslProtocols.Unix.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.SslProtocols.Unix.cs
deleted file mode 100644 (file)
index e7631e3..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.IO;
-using System.Net.Security;
-using System.Net.Sockets;
-using System.Net.Test.Common;
-using System.Runtime.InteropServices;
-using System.Security.Authentication;
-using System.Threading;
-using System.Threading.Tasks;
-using Xunit;
-
-namespace System.Net.Http.Functional.Tests
-{
-    public abstract partial class HttpClientHandler_SslProtocols_Test
-    {
-        private bool BackendSupportsSslConfiguration =>
-            UseSocketsHttpHandler || TestHelper.NativeHandlerSupportsSslConfiguration();
-    }
-}
diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.SslProtocols.Windows.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.SslProtocols.Windows.cs
deleted file mode 100644 (file)
index 961275b..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-
-namespace System.Net.Http.Functional.Tests
-{
-    public abstract partial class HttpClientHandler_SslProtocols_Test
-    {
-        private static bool BackendSupportsSslConfiguration => true;
-    }
-}
index b908350..b6928d4 100644 (file)
@@ -56,11 +56,6 @@ namespace System.Net.Http.Functional.Tests
         [Fact]
         public async Task SetProtocols_AfterRequest_ThrowsException()
         {
-            if (!BackendSupportsSslConfiguration)
-            {
-                return;
-            }
-
             using (HttpClientHandler handler = CreateHttpClientHandler())
             using (HttpClient client = CreateHttpClient(handler))
             {
@@ -110,11 +105,6 @@ namespace System.Net.Http.Functional.Tests
         [MemberData(nameof(GetAsync_AllowedSSLVersion_Succeeds_MemberData))]
         public async Task GetAsync_AllowedSSLVersion_Succeeds(SslProtocols acceptedProtocol, bool requestOnlyThisProtocol)
         {
-            if (!BackendSupportsSslConfiguration)
-            {
-                return;
-            }
-
 #pragma warning disable 0618
             if (IsCurlHandler && PlatformDetection.IsRedHatFamily6 && acceptedProtocol == SslProtocols.Ssl3)
             {
@@ -233,11 +223,6 @@ namespace System.Net.Http.Functional.Tests
         [Fact]
         public async Task GetAsync_NoSpecifiedProtocol_DefaultsToTls12()
         {
-            if (!BackendSupportsSslConfiguration)
-            {
-                return;
-            }
-
             using (HttpClientHandler handler = CreateHttpClientHandler())
             using (HttpClient client = CreateHttpClient(handler))
             {
@@ -269,11 +254,6 @@ namespace System.Net.Http.Functional.Tests
         public async Task GetAsync_AllowedClientSslVersionDiffersFromServer_ThrowsException(
             SslProtocols allowedClientProtocols, SslProtocols acceptedServerProtocols)
         {
-            if (!BackendSupportsSslConfiguration)
-            {
-                return;
-            }
-
             if (IsWinHttpHandler &&
                 allowedClientProtocols == (SslProtocols.Tls11 | SslProtocols.Tls12) &&
                 acceptedServerProtocols == SslProtocols.Tls)
index 32c00aa..0c395c8 100644 (file)
@@ -10,7 +10,8 @@ using Xunit.Abstractions;
 
 namespace System.Net.Http.Functional.Tests
 {
-
+    // Test only WinHttpHandler since the CurlHandler was removed
+    [PlatformSpecific(TestPlatforms.Windows)]
     public class PlatformHandler_HttpClientHandler : HttpClientHandlerTestBase
     {
         protected override bool UseSocketsHttpHandler => false;
@@ -61,36 +62,48 @@ namespace System.Net.Http.Functional.Tests
         }
     }
 
+    // Test only WinHttpHandler since the CurlHandler was removed
+    [PlatformSpecific(TestPlatforms.Windows)]
     public sealed class PlatformHandler_HttpClientHandler_Asynchrony_Test : HttpClientHandler_Asynchrony_Test
     {
         public PlatformHandler_HttpClientHandler_Asynchrony_Test(ITestOutputHelper output) : base(output) { }
         protected override bool UseSocketsHttpHandler => false;
     }
 
+    // Test only WinHttpHandler since the CurlHandler was removed
+    [PlatformSpecific(TestPlatforms.Windows)]
     public sealed class PlatformHandler_HttpProtocolTests : HttpProtocolTests
     {
         public PlatformHandler_HttpProtocolTests(ITestOutputHelper output) : base(output) { }
         protected override bool UseSocketsHttpHandler => false;
     }
 
+    // Test only WinHttpHandler since the CurlHandler was removed
+    [PlatformSpecific(TestPlatforms.Windows)]
     public sealed class PlatformHandler_HttpProtocolTests_Dribble : HttpProtocolTests_Dribble
     {
         public PlatformHandler_HttpProtocolTests_Dribble(ITestOutputHelper output) : base(output) { }
         protected override bool UseSocketsHttpHandler => false;
     }
 
+    // Test only WinHttpHandler since the CurlHandler was removed
+    [PlatformSpecific(TestPlatforms.Windows)]
     public sealed class PlatformHandler_DiagnosticsTest : DiagnosticsTest
     {
         public PlatformHandler_DiagnosticsTest(ITestOutputHelper output) : base(output) { }
         protected override bool UseSocketsHttpHandler => false;
     }
 
+    // Test only WinHttpHandler since the CurlHandler was removed
+    [PlatformSpecific(TestPlatforms.Windows)]
     public sealed class PlatformHandler_HttpClient_SelectedSites_Test : HttpClient_SelectedSites_Test
     {
         public PlatformHandler_HttpClient_SelectedSites_Test(ITestOutputHelper output) : base(output) { }
         protected override bool UseSocketsHttpHandler => false;
     }
 
+    // Test only WinHttpHandler since the CurlHandler was removed
+    [PlatformSpecific(TestPlatforms.Windows)]
     public sealed class PlatformHandler_HttpClientEKUTest : HttpClientEKUTest
     {
         public PlatformHandler_HttpClientEKUTest(ITestOutputHelper output) : base(output) { }
@@ -98,12 +111,16 @@ namespace System.Net.Http.Functional.Tests
     }
 
 #if NETCOREAPP
+    // Test only WinHttpHandler since the CurlHandler was removed
+    [PlatformSpecific(TestPlatforms.Windows)]
     public sealed class PlatformHandler_HttpClientHandler_Decompression_Tests : HttpClientHandler_Decompression_Test
     {
         public PlatformHandler_HttpClientHandler_Decompression_Tests(ITestOutputHelper output) : base(output) { }
         protected override bool UseSocketsHttpHandler => false;
     }
 
+    // Test only WinHttpHandler since the CurlHandler was removed
+    [PlatformSpecific(TestPlatforms.Windows)]
     public sealed class PlatformHandler_HttpClientHandler_DangerousAcceptAllCertificatesValidator_Test : HttpClientHandler_DangerousAcceptAllCertificatesValidator_Test
     {
         public PlatformHandler_HttpClientHandler_DangerousAcceptAllCertificatesValidator_Test(ITestOutputHelper output) : base(output) { }
@@ -111,78 +128,104 @@ namespace System.Net.Http.Functional.Tests
     }
 #endif
 
+    // Test only WinHttpHandler since the CurlHandler was removed
+    [PlatformSpecific(TestPlatforms.Windows)]
     public sealed class PlatformHandler_HttpClientHandler_ClientCertificates_Test : HttpClientHandler_ClientCertificates_Test
     {
         public PlatformHandler_HttpClientHandler_ClientCertificates_Test(ITestOutputHelper output) : base(output) { }
         protected override bool UseSocketsHttpHandler => false;
     }
 
+    // Test only WinHttpHandler since the CurlHandler was removed
+    [PlatformSpecific(TestPlatforms.Windows)]
     public sealed class PlatformHandler_HttpClientHandler_DefaultProxyCredentials_Test : HttpClientHandler_DefaultProxyCredentials_Test
     {
         public PlatformHandler_HttpClientHandler_DefaultProxyCredentials_Test(ITestOutputHelper output) : base(output) { }
         protected override bool UseSocketsHttpHandler => false;
     }
 
+    // Test only WinHttpHandler since the CurlHandler was removed
+    [PlatformSpecific(TestPlatforms.Windows)]
     public sealed class PlatformHandler_HttpClientHandler_MaxConnectionsPerServer_Test : HttpClientHandler_MaxConnectionsPerServer_Test
     {
         public PlatformHandler_HttpClientHandler_MaxConnectionsPerServer_Test(ITestOutputHelper output) : base(output) { }
         protected override bool UseSocketsHttpHandler => false;
     }
 
+    // Test only WinHttpHandler since the CurlHandler was removed
+    [PlatformSpecific(TestPlatforms.Windows)]
     public sealed class PlatformHandler_HttpClientHandler_ServerCertificates_Test : HttpClientHandler_ServerCertificates_Test
     {
         public PlatformHandler_HttpClientHandler_ServerCertificates_Test(ITestOutputHelper output) : base(output) { }
         protected override bool UseSocketsHttpHandler => false;
     }
 
+    // Test only WinHttpHandler since the CurlHandler was removed
+    [PlatformSpecific(TestPlatforms.Windows)]
     public sealed class PlatformHandler_PostScenarioTest : PostScenarioTest
     {
         public PlatformHandler_PostScenarioTest(ITestOutputHelper output) : base(output) { }
         protected override bool UseSocketsHttpHandler => false;
     }
 
+    // Test only WinHttpHandler since the CurlHandler was removed
+    [PlatformSpecific(TestPlatforms.Windows)]
     public sealed class PlatformHandler_ResponseStreamTest : ResponseStreamTest
     {
         public PlatformHandler_ResponseStreamTest(ITestOutputHelper output) : base(output) { }
         protected override bool UseSocketsHttpHandler => false;
     }
 
+    // Test only WinHttpHandler since the CurlHandler was removed
+    [PlatformSpecific(TestPlatforms.Windows)]
     public sealed class PlatformHandler_HttpClientHandler_SslProtocols_Test : HttpClientHandler_SslProtocols_Test
     {
         public PlatformHandler_HttpClientHandler_SslProtocols_Test(ITestOutputHelper output) : base(output) { }
         protected override bool UseSocketsHttpHandler => false;
     }
 
+    // Test only WinHttpHandler since the CurlHandler was removed
+    [PlatformSpecific(TestPlatforms.Windows)]
     public sealed class PlatformHandler_HttpClientHandler_Proxy_Test : HttpClientHandler_Proxy_Test
     {
         public PlatformHandler_HttpClientHandler_Proxy_Test(ITestOutputHelper output) : base(output) { }
         protected override bool UseSocketsHttpHandler => false;
     }
 
+    // Test only WinHttpHandler since the CurlHandler was removed
+    [PlatformSpecific(TestPlatforms.Windows)]
     public sealed class PlatformHandler_SchSendAuxRecordHttpTest : SchSendAuxRecordHttpTest
     {
         public PlatformHandler_SchSendAuxRecordHttpTest(ITestOutputHelper output) : base(output) { }
         protected override bool UseSocketsHttpHandler => false;
     }
 
+    // Test only WinHttpHandler since the CurlHandler was removed
+    [PlatformSpecific(TestPlatforms.Windows)]
     public sealed class PlatformHandler_HttpClientHandlerTest : HttpClientHandlerTest
     {
         public PlatformHandler_HttpClientHandlerTest(ITestOutputHelper output) : base(output) { }
         protected override bool UseSocketsHttpHandler => false;
     }
 
+    // Test only WinHttpHandler since the CurlHandler was removed
+    [PlatformSpecific(TestPlatforms.Windows)]
     public sealed class PlatformHandlerTest_AutoRedirect : HttpClientHandlerTest_AutoRedirect
     {
         public PlatformHandlerTest_AutoRedirect(ITestOutputHelper output) : base(output) { }
         protected override bool UseSocketsHttpHandler => false;
     }
 
+    // Test only WinHttpHandler since the CurlHandler was removed
+    [PlatformSpecific(TestPlatforms.Windows)]
     public sealed class PlatformHandler_DefaultCredentialsTest : DefaultCredentialsTest
     {
         public PlatformHandler_DefaultCredentialsTest(ITestOutputHelper output) : base(output) { }
         protected override bool UseSocketsHttpHandler => false;
     }
 
+    // Test only WinHttpHandler since the CurlHandler was removed
+    [PlatformSpecific(TestPlatforms.Windows)]
     public sealed class PlatformHandler_IdnaProtocolTests : IdnaProtocolTests
     {
         public PlatformHandler_IdnaProtocolTests(ITestOutputHelper output) : base(output) { }
@@ -191,36 +234,48 @@ namespace System.Net.Http.Functional.Tests
         protected override bool SupportsIdna => !PlatformDetection.IsWindows7;
     }
 
+    // Test only WinHttpHandler since the CurlHandler was removed
+    [PlatformSpecific(TestPlatforms.Windows)]
     public sealed class PlatformHandler_HttpRetryProtocolTests : HttpRetryProtocolTests
     {
         public PlatformHandler_HttpRetryProtocolTests(ITestOutputHelper output) : base(output) { }
         protected override bool UseSocketsHttpHandler => false;
     }
 
+    // Test only WinHttpHandler since the CurlHandler was removed
+    [PlatformSpecific(TestPlatforms.Windows)]
     public sealed class PlatformHandlerTest_Cookies : HttpClientHandlerTest_Cookies
     {
         public PlatformHandlerTest_Cookies(ITestOutputHelper output) : base(output) { }
         protected override bool UseSocketsHttpHandler => false;
     }
 
+    // Test only WinHttpHandler since the CurlHandler was removed
+    [PlatformSpecific(TestPlatforms.Windows)]
     public sealed class PlatformHandlerTest_Cookies_Http11 : HttpClientHandlerTest_Cookies_Http11
     {
         public PlatformHandlerTest_Cookies_Http11(ITestOutputHelper output) : base(output) { }
         protected override bool UseSocketsHttpHandler => false;
     }
 
+    // Test only WinHttpHandler since the CurlHandler was removed
+    [PlatformSpecific(TestPlatforms.Windows)]
     public sealed class PlatformHandler_HttpClientHandler_MaxResponseHeadersLength_Test : HttpClientHandler_MaxResponseHeadersLength_Test
     {
         public PlatformHandler_HttpClientHandler_MaxResponseHeadersLength_Test(ITestOutputHelper output) : base(output) { }
         protected override bool UseSocketsHttpHandler => false;
     }
 
+    // Test only WinHttpHandler since the CurlHandler was removed
+    [PlatformSpecific(TestPlatforms.Windows)]
     public sealed class PlatformHandler_HttpClientHandler_Cancellation_Test : HttpClientHandler_Cancellation_Test
     {
         public PlatformHandler_HttpClientHandler_Cancellation_Test(ITestOutputHelper output) : base(output) { }
         protected override bool UseSocketsHttpHandler => false;
     }
 
+    // Test only WinHttpHandler since the CurlHandler was removed
+    [PlatformSpecific(TestPlatforms.Windows)]
     public sealed class PlatformHandler_HttpClientHandler_Authentication_Test : HttpClientHandler_Authentication_Test
     {
         public PlatformHandler_HttpClientHandler_Authentication_Test(ITestOutputHelper output) : base(output) { }
@@ -229,11 +284,15 @@ namespace System.Net.Http.Functional.Tests
 
     // Enable this to run HTTP2 tests on platform handler
 #if PLATFORM_HANDLER_HTTP2_TESTS
+    // Test only WinHttpHandler since the CurlHandler was removed
+    [PlatformSpecific(TestPlatforms.Windows)]
     public sealed class PlatformHandlerTest_Http2 : HttpClientHandlerTest_Http2
     {
         protected override bool UseSocketsHttpHandler => false;
     }
-
+    
+    // Test only WinHttpHandler since the CurlHandler was removed
+    [PlatformSpecific(TestPlatforms.Windows)]
     [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.SupportsAlpn))]
     public sealed class PlatformHandlerTest_Cookies_Http2 : HttpClientHandlerTest_Cookies
     {
index db72b15..161fd7d 100644 (file)
@@ -2089,6 +2089,8 @@ namespace System.Net.Http.Functional.Tests
         }
     }
 
+    // Test only WinHttpHandler since the CurlHandler was removed
+    [PlatformSpecific(TestPlatforms.Windows)]
     public sealed class SocketsHttpHandler_ExternalConfiguration_Test : HttpClientHandlerTestBase
     {
         public SocketsHttpHandler_ExternalConfiguration_Test(ITestOutputHelper output) : base(output) { }
index e6067c3..af715a0 100644 (file)
@@ -8,10 +8,7 @@
   </PropertyGroup>
   <ItemGroup>
     <Compile Include="$(CommonPath)\Interop\Unix\Interop.Libraries.cs" Condition="'$(TargetsUnix)' == 'true'">
-      <Link>Common\Interop\Unix\System.Net.Http.Native\Interop.VersionInfo.cs</Link>
-    </Compile>
-    <Compile Include="$(CommonPath)\Interop\Unix\System.Net.Http.Native\Interop.VersionInfo.cs" Condition="'$(TargetsUnix)' == 'true'">
-      <Link>Common\Interop\Unix\System.Net.Http.Native\Interop.VersionInfo.cs</Link>
+      <Link>Common\Interop\Unix\Interop.Libraries.cs</Link>
     </Compile>
     <Compile Include="$(CommonPath)\Interop\Unix\System.Net.Security.Native\Interop.NetSecurityNative.IsNtlmInstalled.cs" Condition="'$(TargetsUnix)' == 'true'">
       <Link>Common\Interop\Unix\System.Net.Security.Native\Interop.NetSecurityNative.IsNtlmInstalled.cs</Link>
     <Compile Include="HttpClientHandlerTest.Proxy.cs" />
     <Compile Include="HttpClientHandlerTest.ResponseDrain.cs" />
     <Compile Include="HttpClientHandlerTest.ServerCertificates.cs" />
-    <Compile Include="HttpClientHandlerTest.ServerCertificates.Unix.cs" Condition="'$(TargetsUnix)' == 'true'" />
-    <Compile Include="HttpClientHandlerTest.ServerCertificates.Windows.cs" Condition="'$(TargetsWindows)' == 'true'" />
     <Compile Include="HttpClientHandlerTest.SslProtocols.cs" />
-    <Compile Include="HttpClientHandlerTest.SslProtocols.Unix.cs" Condition="'$(TargetsUnix)' == 'true'" />
-    <Compile Include="HttpClientHandlerTest.SslProtocols.Windows.cs" Condition="'$(TargetsWindows)' == 'true'" />
     <Compile Include="DiagnosticsTests.cs" />
     <Compile Include="HttpClientHandlerTestBase.cs" />
     <Compile Include="HttpClientTest.cs" />
index e3aa7af..92aba12 100644 (file)
@@ -154,34 +154,6 @@ namespace System.Net.Http.Functional.Tests
             allowUnencryptedHttp2Field.SetValue(settings, true);
         }
 
-        public static bool NativeHandlerSupportsSslConfiguration()
-        {
-#if TargetsWindows
-            return true;
-#else
-            if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
-            {
-                return false;
-            }
-
-            // For other Unix-based systems it's true if (and only if) the currect openssl backend
-            // is used with libcurl.
-            bool hasAnyOpenSsl =
-                Interop.Http.GetSslVersionDescription()?.StartsWith(Interop.Http.OpenSslDescriptionPrefix, StringComparison.OrdinalIgnoreCase) ?? false;
-
-            if (!hasAnyOpenSsl)
-            {
-                return false;
-            }
-
-            // We're on an OpenSSL-based system, with an OpenSSL backend.
-            // Ask the product how it feels about this.
-            Type interopHttp = typeof(HttpClient).Assembly.GetType("Interop+Http");
-            PropertyInfo hasMatchingOpenSslVersion = interopHttp.GetProperty("HasMatchingOpenSslVersion", BindingFlags.Static | BindingFlags.NonPublic);
-            return (bool)hasMatchingOpenSslVersion.GetValue(null);
-#endif
-        }
-
         public static byte[] GenerateRandomContent(int size)
         {
             byte[] data = new byte[size];
diff --git a/src/libraries/System.Net.Http/tests/UnitTests/Headers/CurlResponseHeaderReaderTest.cs b/src/libraries/System.Net.Http/tests/UnitTests/Headers/CurlResponseHeaderReaderTest.cs
deleted file mode 100644 (file)
index bf10f68..0000000
+++ /dev/null
@@ -1,206 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Collections.Generic;
-using System.Linq;
-
-using Xunit;
-
-namespace System.Net.Http.Tests
-{
-    public class CurlResponseParseUtilsTest
-    {
-        private const string StatusCodeTemplate = "HTTP/1.1 {0} {1}";
-        private const string MissingSpaceFormat = "HTTP/1.1 {0}InvalidPhrase";
-
-        private const string StatusCodeVersionFormat = "HTTP/{0}.{1} 200 OK";
-        private const string StatusCodeMajorVersionOnlyFormat = "HTTP/{0} 200 OK";
-
-        private const string ValidHeader = "Content-Type: text/xml; charset=utf-8";
-        private const string HeaderNameWithInvalidChar = "Content{0}Type: text/xml; charset=utf-8";
-
-        private const string invalidChars = "()<>@,;\\\"/[]?={} \t";
-
-        public static readonly IEnumerable<object[]> ValidStatusCodeLines = GetStatusCodeLines(StatusCodeTemplate);
-        public static IEnumerable<object[]> InvalidStatusCodeLines => GetStatusCodeLines(MissingSpaceFormat).Select(o => new object[] { o[0] });
-        public static readonly IEnumerable<object[]> StatusCodeVersionLines = GetStatusCodeLinesForMajorVersions(1, 10).Concat(GetStatusCodeLinesForMajorMinorVersions(1, 10));
-        public static readonly IEnumerable<object[]> InvalidHeaderLines = GetInvalidHeaderLines();
-
-        private static IEnumerable<object[]> GetStatusCodeLines(string template)
-        {
-            const string reasonPhrase = "Test Phrase";
-            foreach (int code in Enum.GetValues(typeof(HttpStatusCode)))
-            {
-                yield return new object[] { string.Format(template, code, reasonPhrase), code, reasonPhrase};
-            }
-        }
-
-        private static IEnumerable<object[]> GetStatusCodeLinesForMajorVersions(int min, int max)
-        {
-            for (int major = min; major < max; major++)
-            {
-                yield return new object[] { string.Format(StatusCodeMajorVersionOnlyFormat, major), major, 0 };
-            }
-        }
-
-        private static IEnumerable<object[]> GetStatusCodeLinesForMajorMinorVersions(int min, int max)
-        {
-            for (int major = min; major < max; major++)
-            {
-                for (int minor = min; minor < max; minor++)
-                {
-                    yield return new object[] {string.Format(StatusCodeVersionFormat, major, minor), major, minor};
-                }
-            }
-        }
-
-        private static IEnumerable<object[]> GetInvalidHeaderLines()
-        {
-            foreach (char c in invalidChars)
-            {
-                yield return new object[] { string.Format(HeaderNameWithInvalidChar, c) };
-            }
-        }
-
-        #region StatusCode
-        [Theory, MemberData(nameof(ValidStatusCodeLines))]
-        public unsafe void ReadStatusLine_ValidStatusCode_ResponseMessageValueSet(string statusLine, HttpStatusCode expectedCode, string expectedPhrase)
-        {
-            byte[] buffer = statusLine.Select(c => checked((byte)c)).ToArray();
-
-            fixed (byte* pBuffer = buffer)
-            {
-                var reader = new CurlResponseHeaderReader(new IntPtr(pBuffer), checked((ulong)buffer.Length));
-                using (var response = new HttpResponseMessage())
-                {
-                    Assert.True(reader.ReadStatusLine(response));
-                    Assert.Equal(expectedCode, response.StatusCode);
-                    Assert.Equal(expectedPhrase, response.ReasonPhrase);
-                }
-            }
-        }
-
-        [Theory, MemberData(nameof(InvalidStatusCodeLines))]
-        public unsafe void ReadStatusLine_InvalidStatusCode_ThrowsHttpRequestException(string statusLine)
-        {
-            byte[] buffer = statusLine.Select(c => checked((byte)c)).ToArray();
-
-            fixed (byte* pBuffer = buffer)
-            {
-                var reader = new CurlResponseHeaderReader(new IntPtr(pBuffer), checked((ulong)buffer.Length));
-                using (var response = new HttpResponseMessage())
-                {
-                    Assert.Throws<HttpRequestException>(() => reader.ReadStatusLine(response));
-                }
-            }
-        }
-
-        [Theory, MemberData(nameof(StatusCodeVersionLines))]
-        public unsafe void ReadStatusLine_ValidStatusCodeLine_ResponseMessageVersionSet(string statusLine, int major, int minor)
-        {
-            byte[] buffer = statusLine.Select(c => checked((byte)c)).ToArray();
-
-            fixed (byte* pBuffer = buffer)
-            {
-                var reader = new CurlResponseHeaderReader(new IntPtr(pBuffer), checked((ulong)buffer.Length));
-                using (var response = new HttpResponseMessage())
-                {
-                    Assert.True(reader.ReadStatusLine(response));
-                    int expectedMajor = 0;
-                    int expectedMinor = 0;
-                    if (major == 1 && (minor == 0 || minor == 1))
-                    {
-                        expectedMajor = 1;
-                        expectedMinor = minor;
-                    }
-                    else if (major == 2 && minor == 0)
-                    {
-                        expectedMajor = 2;
-                        expectedMinor = 0;
-                    }
-
-                    Assert.Equal(expectedMajor, response.Version.Major);
-                    Assert.Equal(expectedMinor, response.Version.Minor);
-                }
-            }
-        }
-
-        #endregion
-
-        #region Headers
-        public static IEnumerable<object[]> ReadHeader_ValidHeaderLine_HeaderReturned_MemberData()
-        {
-            var namesAndValues = new KeyValuePair<string, string>[]
-            {
-                new KeyValuePair<string, string>("TestHeader", "Test header value"),
-                new KeyValuePair<string, string>("TestHeader", ""),
-                new KeyValuePair<string, string>("Server", "IIS"),
-                new KeyValuePair<string, string>("Server", "I:I:S"),
-            };
-            var whitespaces = new string[] { "", " ", "    ", " \t" };
-
-            foreach (KeyValuePair<string, string> nameAndValue in namesAndValues)
-            {
-                foreach (string beforeColon in whitespaces) // only "" is valid according to the RFC, but we parse more leniently
-                {
-                    foreach (string afterColon in whitespaces)
-                    {
-                        yield return new object[] { $"{nameAndValue.Key}{beforeColon}:{afterColon}{nameAndValue.Value}", nameAndValue.Key, nameAndValue.Value };
-                    }
-                }
-            }
-        }
-
-        [Theory]
-        [MemberData(nameof(ReadHeader_ValidHeaderLine_HeaderReturned_MemberData))]
-        public unsafe void ReadHeader_ValidHeaderLine_HeaderReturned(string headerLine, string expectedHeaderName, string expectedHeaderValue)
-        {
-            byte[] buffer = headerLine.Select(c => checked((byte)c)).ToArray();
-            fixed (byte* pBuffer = buffer)
-            {
-                var reader = new CurlResponseHeaderReader(new IntPtr(pBuffer), checked((ulong)buffer.Length));
-
-                string headerName;
-                string headerValue;
-                Assert.True(reader.ReadHeader(out headerName, out headerValue));
-                Assert.Equal(expectedHeaderName, headerName);
-                Assert.Equal(expectedHeaderValue, headerValue);
-            }
-        }
-
-        [Fact]
-        public unsafe void ReadHeader_EmptyBuffer_ReturnsFalse()
-        {
-            byte[] buffer = new byte[2]; // Non-empty array so we can get a valid pointer using fixed.
-            ulong length = 0; // But a length of 0 for empty.
-
-            fixed (byte* pBuffer = buffer)
-            {
-                var reader = new CurlResponseHeaderReader(new IntPtr(pBuffer), length);
-
-                string headerName;
-                string headerValue;
-                Assert.False(reader.ReadHeader(out headerName, out headerValue));
-                Assert.Null(headerName);
-                Assert.Null(headerValue);
-            }
-        }
-
-        [Theory, MemberData(nameof(InvalidHeaderLines))]
-        public unsafe void ReadHeaderName_InvalidHeaderLine_ThrowsHttpRequestException(string headerLine)
-        {
-            byte[] buffer = headerLine.Select(c => checked((byte)c)).ToArray();
-
-            fixed (byte* pBuffer = buffer)
-            {
-                var reader = new CurlResponseHeaderReader(new IntPtr(pBuffer), checked((ulong)buffer.Length));
-
-                string headerName;
-                string headerValue;
-                Assert.Throws<HttpRequestException>(() => reader.ReadHeader(out headerName, out headerValue));
-            }
-        }
-        #endregion
-    }
-}
index 1d2aeb4..1a256d9 100644 (file)
     <Compile Include="..\..\src\System\Net\Http\StringContent.cs">
       <Link>ProductionCode\System\Net\Http\StringContent.cs</Link>
     </Compile>
-    <Compile Include="..\..\src\System\Net\Http\CurlHandler\CurlResponseHeaderReader.cs">
-      <Link>ProductionCode\System\Net\Http\CurlResponseHeaderReader.cs</Link>
-    </Compile>
     <Compile Include="..\..\src\System\Net\Http\SocketsHttpHandler\ArrayBuffer.cs">
       <Link>ProductionCode\System\Net\Http\SocketsHttpHandler\ArrayBuffer.cs</Link>
     </Compile>
     <Compile Include="Headers\CacheControlHeaderValueTest.cs" />
     <Compile Include="Headers\ContentDispositionHeaderValueTest.cs" />
     <Compile Include="Headers\ContentRangeHeaderValueTest.cs" />
-    <Compile Include="Headers\CurlResponseHeaderReaderTest.cs" />
     <Compile Include="Headers\DateHeaderParserTest.cs" />
     <Compile Include="Headers\EntityTagHeaderValueTest.cs" />
     <Compile Include="Headers\GenericHeaderParserTest\AuthenticationParserTest.cs" />
index 114029e..60dc9a8 100644 (file)
@@ -98,9 +98,6 @@
     <Compile Include="System\Net\WebExceptionPal.Windows.cs" />
   </ItemGroup>
   <ItemGroup Condition=" '$(TargetsUnix)' == 'true' ">
-    <Compile Include="$(CommonPath)\Interop\Unix\System.Net.Http.Native\Interop.CURLcode.cs">
-      <Link>Common\Interop\Unix\System.Net.Http.Native\Interop.CURLcode.cs</Link>
-    </Compile>
     <Compile Include="$(CommonPath)\System\Net\ContextAwareResult.Unix.cs">
       <Link>Common\System\Net\ContextAwareResult.Unix.cs</Link>
     </Compile>
index 7ad711c..e29734b 100644 (file)
@@ -11,8 +11,6 @@ namespace System.Net
     {
         internal static WebExceptionStatus GetStatusFromException(HttpRequestException ex)
         {
-            WebExceptionStatus status;
-
             // Issue 2384: update WebException.GetStatusFromException after System.Net.Http API changes
             //
             // For now, we use the .HResult of the exception to help us map to a suitable
@@ -20,17 +18,7 @@ namespace System.Net
             // the underlying .NET Core and .NET Native versions of the System.Net.Http stack.
             // In the future, the HttpRequestException will have its own .Status property that is
             // an enum type that is more compatible directly with the WebExceptionStatus enum.
-            switch (ex.HResult)
-            {
-                case (int)Interop.Http.CURLcode.CURLE_COULDNT_RESOLVE_HOST:
-                    status = WebExceptionStatus.NameResolutionFailure;
-                    break;
-                default:
-                    status = GetStatusFromExceptionHelper(ex);
-                    break;
-            }
-
-            return status;
+            return GetStatusFromExceptionHelper(ex);
         }
     }
 }