diff --git a/src/libraries/Common/src/Interop/Windows/WinHttp/Interop.winhttp_types.cs b/src/libraries/Common/src/Interop/Windows/WinHttp/Interop.winhttp_types.cs index 42b58b7df198d7..9dcdcc8428d00b 100644 --- a/src/libraries/Common/src/Interop/Windows/WinHttp/Interop.winhttp_types.cs +++ b/src/libraries/Common/src/Interop/Windows/WinHttp/Interop.winhttp_types.cs @@ -159,8 +159,10 @@ internal static partial class WinHttp public const uint WINHTTP_OPTION_ENABLE_HTTP_PROTOCOL = 133; public const uint WINHTTP_OPTION_HTTP_PROTOCOL_USED = 134; public const uint WINHTTP_PROTOCOL_FLAG_HTTP2 = 0x1; + public const uint WINHTTP_PROTOCOL_FLAG_HTTP3 = 0x2; public const uint WINHTTP_HTTP2_PLUS_CLIENT_CERT_FLAG = 0x1; public const uint WINHTTP_OPTION_DISABLE_STREAM_QUEUE = 139; + public const uint WINHTTP_OPTION_HTTP_PROTOCOL_REQUIRED = 145; public const uint WINHTTP_OPTION_UPGRADE_TO_WEB_SOCKET = 114; public const uint WINHTTP_OPTION_WEB_SOCKET_CLOSE_TIMEOUT = 115; diff --git a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Cancellation.cs b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Cancellation.cs index b0a274ad787fcf..13117768c99f99 100644 --- a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Cancellation.cs +++ b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Cancellation.cs @@ -36,10 +36,10 @@ public async Task PostAsync_CancelDuringRequestContentSend_TaskCanceledQuickly(b return; } - if (IsWinHttpHandler && UseVersion >= HttpVersion20.Value) + /*if (IsWinHttpHandler && UseVersion >= HttpVersion20.Value) { return; - } + }*/ if (PlatformDetection.IsBrowser && LoopbackServerFactory.Version < HttpVersion20.Value) { @@ -100,10 +100,10 @@ public async Task GetAsync_CancelDuringResponseHeadersReceived_TaskCanceledQuick return; } - if (IsWinHttpHandler && UseVersion >= HttpVersion20.Value) + /*if (IsWinHttpHandler && UseVersion >= HttpVersion20.Value) { return; - } + }*/ using (HttpClient client = CreateHttpClient()) { @@ -208,10 +208,10 @@ public async Task GetAsync_CancelDuringResponseBodyReceived_Unbuffered_TaskCance return; } - if (IsWinHttpHandler && UseVersion >= HttpVersion20.Value) + /*if (IsWinHttpHandler && UseVersion >= HttpVersion20.Value) { return; - } + }*/ using (HttpClient client = CreateHttpClient()) { @@ -271,10 +271,10 @@ await ValidateClientCancellationAsync(async () => [SkipOnPlatform(TestPlatforms.Browser, "Browser doesn't have blocking synchronous Stream.ReadByte and so it waits for whole body")] public async Task GetAsync_CancelPendingRequests_DoesntCancelReadAsyncOnResponseStream(CancellationMode mode, bool copyToAsync) { - if (IsWinHttpHandler && UseVersion >= HttpVersion20.Value) + /*if (IsWinHttpHandler && UseVersion >= HttpVersion20.Value) { return; - } + }*/ using (HttpClient client = CreateHttpClient()) { diff --git a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Decompression.cs b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Decompression.cs index 02724599c120ee..cb8c511c439a90 100644 --- a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Decompression.cs +++ b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Decompression.cs @@ -331,7 +331,7 @@ await LoopbackServer.CreateServerAsync(async (server, url) => break; } } - + Assert.True(acceptEncodingValid, "Accept-Encoding missing or invalid"); using (HttpResponseMessage response = await clientTask) diff --git a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Proxy.cs b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Proxy.cs index c2031f5aa75ed8..2d2b75030fc668 100644 --- a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Proxy.cs +++ b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.Proxy.cs @@ -29,11 +29,6 @@ public HttpClientHandler_Proxy_Test(ITestOutputHelper output) : base(output) { } [Fact] public async Task Dispose_HandlerWithProxy_ProxyNotDisposed() { - if (IsWinHttpHandler && UseVersion >= HttpVersion20.Value) - { - return; - } - var proxy = new TrackDisposalProxy(); await LoopbackServerFactory.CreateClientAndServerAsync(async uri => diff --git a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.ServerCertificates.cs b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.ServerCertificates.cs index 0ed517ae168426..a3b8d55b956f6f 100644 --- a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.ServerCertificates.cs +++ b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.ServerCertificates.cs @@ -40,10 +40,10 @@ public HttpClientHandler_ServerCertificates_Test(ITestOutputHelper output) : bas [Fact] public void Ctor_ExpectedDefaultValues() { - if (IsWinHttpHandler && UseVersion >= HttpVersion20.Value) + /*if (IsWinHttpHandler && UseVersion >= HttpVersion20.Value) { return; - } + }*/ using (HttpClientHandler handler = CreateHttpClientHandler()) { @@ -55,10 +55,10 @@ public void Ctor_ExpectedDefaultValues() [Fact] public void ServerCertificateCustomValidationCallback_SetGet_Roundtrips() { - if (IsWinHttpHandler && UseVersion >= HttpVersion20.Value) + /*if (IsWinHttpHandler && UseVersion >= HttpVersion20.Value) { return; - } + }*/ using (HttpClientHandler handler = CreateHttpClientHandler()) { diff --git a/src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpHandler.cs b/src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpHandler.cs index f73a48f54ecedf..6bc5c4b5d8bb31 100644 --- a/src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpHandler.cs +++ b/src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpHandler.cs @@ -904,6 +904,14 @@ private async Task StartRequestAsync(WinHttpRequestState state) { httpVersion = "HTTP/1.1"; } + else if (state.RequestMessage.Version == HttpVersion20) + { + httpVersion = "HTTP/2.0"; + } + else if (state.RequestMessage.Version == HttpVersion30) + { + httpVersion = "HTTP/3.0"; + } OpenRequestHandle(state, connectHandle, httpVersion, out WinHttpChunkMode chunkedModeForSend, out SafeWinHttpHandle requestHandle); state.RequestHandle = requestHandle; @@ -1269,7 +1277,13 @@ private void SetRequestHandleOptions(WinHttpRequestState state) SetRequestHandleClientCertificateOptions(state.RequestHandle, state.RequestMessage.RequestUri); SetRequestHandleCredentialsOptions(state); SetRequestHandleBufferingOptions(state.RequestHandle); - SetRequestHandleHttp2Options(state.RequestHandle, state.RequestMessage.Version); + bool forceVersion = +#if NET + state.RequestMessage.VersionPolicy != HttpVersionPolicy.RequestVersionOrLower; +#else + false; +#endif + SetRequestHandleHttpProtocolOptions(state.RequestHandle, state.RequestMessage.Version, forceVersion); } private static void SetRequestHandleProxyOptions(WinHttpRequestState state) @@ -1509,20 +1523,38 @@ private void SetRequestHandleBufferingOptions(SafeWinHttpHandle requestHandle) SetWinHttpOption(requestHandle, Interop.WinHttp.WINHTTP_OPTION_MAX_RESPONSE_DRAIN_SIZE, ref optionData); } - private void SetRequestHandleHttp2Options(SafeWinHttpHandle requestHandle, Version requestVersion) + private void SetRequestHandleHttpProtocolOptions(SafeWinHttpHandle requestHandle, Version requestVersion, bool forceVersion) { Debug.Assert(requestHandle != null); - uint optionData = (requestVersion == HttpVersion20) ? Interop.WinHttp.WINHTTP_PROTOCOL_FLAG_HTTP2 : 0; + uint optionData = (requestVersion == HttpVersion30) ? Interop.WinHttp.WINHTTP_PROTOCOL_FLAG_HTTP3 : + (requestVersion == HttpVersion20) ? Interop.WinHttp.WINHTTP_PROTOCOL_FLAG_HTTP2 : 0; if (Interop.WinHttp.WinHttpSetOption( requestHandle, Interop.WinHttp.WINHTTP_OPTION_ENABLE_HTTP_PROTOCOL, ref optionData)) { - if (NetEventSource.Log.IsEnabled()) NetEventSource.Info(this, $"HTTP/2 option supported, setting to {optionData}"); + if (NetEventSource.Log.IsEnabled()) NetEventSource.Info(this, $"HTTP/{requestVersion.Major} option supported, setting to {optionData}"); } else { - if (NetEventSource.Log.IsEnabled()) NetEventSource.Info(this, "HTTP/2 option not supported"); + if (NetEventSource.Log.IsEnabled()) NetEventSource.Info(this, $"HTTP/{requestVersion.Major} option not supported"); + return; + } + + if (optionData != 0 && forceVersion) + { + uint protocolRequired = 1; + if (Interop.WinHttp.WinHttpSetOption( + requestHandle, + Interop.WinHttp.WINHTTP_OPTION_HTTP_PROTOCOL_REQUIRED, + ref protocolRequired)) + { + if (NetEventSource.Log.IsEnabled()) NetEventSource.Info(this, "HTTP protocol required option set"); + } + else + { + if (NetEventSource.Log.IsEnabled()) NetEventSource.Info(this, "HTTP protocol required option not supported"); + } } } diff --git a/src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/HttpClientHandlerTestBase.WinHttpHandler.cs b/src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/HttpClientHandlerTestBase.WinHttpHandler.cs index 81773638085d93..b54ca6a85b729d 100644 --- a/src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/HttpClientHandlerTestBase.WinHttpHandler.cs +++ b/src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/HttpClientHandlerTestBase.WinHttpHandler.cs @@ -41,8 +41,12 @@ protected static LoopbackServerFactory GetFactoryForVersion(Version useVersion) { return useVersion.Major switch { + 1 => Http11LoopbackServerFactory.Singleton, 2 => Http2LoopbackServerFactory.Singleton, - _ => Http11LoopbackServerFactory.Singleton +#if NET + 3 => Http3LoopbackServerFactory.Singleton, +#endif + _ => throw new InvalidOperationException($"Unexpected HTTP version: {useVersion}") }; } diff --git a/src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/PlatformHandlerTest.cs b/src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/PlatformHandlerTest.cs index 7822189896649b..b67694935cddae 100644 --- a/src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/PlatformHandlerTest.cs +++ b/src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/PlatformHandlerTest.cs @@ -191,108 +191,6 @@ public PlatformHandlerTest_Cookies_Http2(ITestOutputHelper output) : base(output } #endif - public sealed class PlatformHandler_HttpClientHandler_Asynchrony_Http2_Test : HttpClientHandler_Asynchrony_Test - { - protected override Version UseVersion => HttpVersion20.Value; - - public PlatformHandler_HttpClientHandler_Asynchrony_Http2_Test(ITestOutputHelper output) : base(output) { } - } - - public sealed class PlatformHandler_HttpProtocol_Http2_Tests : HttpProtocolTests - { - protected override Version UseVersion => HttpVersion20.Value; - - public PlatformHandler_HttpProtocol_Http2_Tests(ITestOutputHelper output) : base(output) { } - } - - public sealed class PlatformHandler_HttpProtocolTests_Http2_Dribble : HttpProtocolTests_Dribble - { - protected override Version UseVersion => HttpVersion20.Value; - - public PlatformHandler_HttpProtocolTests_Http2_Dribble(ITestOutputHelper output) : base(output) { } - } - - public sealed class PlatformHandler_HttpClient_SelectedSites_Http2_Test : HttpClient_SelectedSites_Test - { - protected override Version UseVersion => HttpVersion20.Value; - - public PlatformHandler_HttpClient_SelectedSites_Http2_Test(ITestOutputHelper output) : base(output) { } - } - - public sealed class PlatformHandler_HttpClientEKU_Http2_Test : HttpClientEKUTest - { - protected override Version UseVersion => HttpVersion20.Value; - - public PlatformHandler_HttpClientEKU_Http2_Test(ITestOutputHelper output) : base(output) { } - } - - public sealed class PlatformHandler_HttpClientHandler_Decompression_Http2_Tests : HttpClientHandler_Decompression_Test - { - protected override Version UseVersion => HttpVersion20.Value; - - public PlatformHandler_HttpClientHandler_Decompression_Http2_Tests(ITestOutputHelper output) : base(output) { } - } - - public sealed class PlatformHandler_HttpClientHandler_DangerousAcceptAllCertificatesValidator_Http2_Test : HttpClientHandler_DangerousAcceptAllCertificatesValidator_Test - { - protected override Version UseVersion => HttpVersion20.Value; - - public PlatformHandler_HttpClientHandler_DangerousAcceptAllCertificatesValidator_Http2_Test(ITestOutputHelper output) : base(output) { } - } - - public sealed class PlatformHandler_HttpClientHandler_ClientCertificates_Http2_Test : HttpClientHandler_ClientCertificates_Test - { - protected override Version UseVersion => HttpVersion20.Value; - - public PlatformHandler_HttpClientHandler_ClientCertificates_Http2_Test(ITestOutputHelper output) : base(output) { } - } - - public sealed class PlatformHandler_HttpClientHandler_DefaultProxyCredentials_Http2_Test : HttpClientHandler_DefaultProxyCredentials_Test - { - protected override Version UseVersion => HttpVersion20.Value; - - public PlatformHandler_HttpClientHandler_DefaultProxyCredentials_Http2_Test(ITestOutputHelper output) : base(output) { } - } - - [SkipOnPlatform(TestPlatforms.Browser, "MaxConnectionsPerServer not supported on Browser")] - public sealed class PlatformHandler_HttpClientHandler_MaxConnectionsPerServer_Http2_Test : HttpClientHandler_MaxConnectionsPerServer_Test - { - protected override Version UseVersion => HttpVersion20.Value; - - public PlatformHandler_HttpClientHandler_MaxConnectionsPerServer_Http2_Test(ITestOutputHelper output) : base(output) { } - } - - public sealed class PlatformHandler_HttpClientHandler_ServerCertificates_Http2_Test : HttpClientHandler_ServerCertificates_Test - { - protected override Version UseVersion => HttpVersion20.Value; - - public PlatformHandler_HttpClientHandler_ServerCertificates_Http2_Test(ITestOutputHelper output) : base(output) - { - AllowAllCertificates = false; - } - } - - public sealed class PlatformHandler_PostScenario_Http2_Test : PostScenarioTest - { - protected override Version UseVersion => HttpVersion20.Value; - - public PlatformHandler_PostScenario_Http2_Test(ITestOutputHelper output) : base(output) { } - } - - public sealed class PlatformHandler_HttpClientHandler_SslProtocols_Http2_Test : HttpClientHandler_SslProtocols_Test - { - protected override Version UseVersion => HttpVersion20.Value; - - public PlatformHandler_HttpClientHandler_SslProtocols_Http2_Test(ITestOutputHelper output) : base(output) { } - } - - public sealed class PlatformHandler_HttpClientHandler_Proxy_Http2_Test : HttpClientHandler_Proxy_Test - { - protected override Version UseVersion => HttpVersion20.Value; - - public PlatformHandler_HttpClientHandler_Proxy_Http2_Test(ITestOutputHelper output) : base(output) { } - } - [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsWindows10Version1607OrGreater))] public sealed class PlatformHandler_HttpClientHandler_Http2_Test : HttpClientHandlerTest { @@ -300,61 +198,25 @@ public sealed class PlatformHandler_HttpClientHandler_Http2_Test : HttpClientHan public PlatformHandler_HttpClientHandler_Http2_Test(ITestOutputHelper output) : base(output) { } } +#endif - public sealed class PlatformHandlerTest_AutoRedirect_Http2 : HttpClientHandlerTest_AutoRedirect - { - protected override Version UseVersion => HttpVersion20.Value; - - public PlatformHandlerTest_AutoRedirect_Http2(ITestOutputHelper output) : base(output) { } - } - - public sealed class PlatformHandler_DefaultCredentials_Http2_Test : DefaultCredentialsTest - { - protected override Version UseVersion => HttpVersion20.Value; - - public PlatformHandler_DefaultCredentials_Http2_Test(ITestOutputHelper output) : base(output) { } - } - - public sealed class PlatformHandler_IdnaProtocol_Http2_Tests : IdnaProtocolTests - { - protected override Version UseVersion => HttpVersion20.Value; - - public PlatformHandler_IdnaProtocol_Http2_Tests(ITestOutputHelper output) : base(output) { } - } - - public sealed class PlatformHandlerTest_Cookies_Http11_Http2 : HttpClientHandlerTest_Cookies_Http11 - { - protected override Version UseVersion => HttpVersion20.Value; - - public PlatformHandlerTest_Cookies_Http11_Http2(ITestOutputHelper output) : base(output) { } - } - +#if NET +#if !WINHTTPHANDLER_TEST // [ActiveIssue("https://github.com/dotnet/runtime/issues/33930")] [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsWindows10Version1607OrGreater))] - public sealed class PlatformHandler_HttpClientHandler_MaxResponseHeadersLength_Http2_Test : HttpClientHandler_MaxResponseHeadersLength_Test + public sealed class PlatformHandlerTest_Cookies_Http3 : HttpClientHandlerTest_Cookies { - protected override Version UseVersion => HttpVersion20.Value; + protected override Version UseVersion => HttpVersion.Version30; - public PlatformHandler_HttpClientHandler_MaxResponseHeadersLength_Http2_Test(ITestOutputHelper output) : base(output) { } - } - - public sealed class PlatformHandler_HttpClientHandler_Cancellation_Http2_Test : HttpClientHandler_Cancellation_Test - { - protected override Version UseVersion => HttpVersion20.Value; - - public PlatformHandler_HttpClientHandler_Cancellation_Http2_Test(ITestOutputHelper output) : base(output) { } + public PlatformHandlerTest_Cookies_Http3(ITestOutputHelper output) : base(output) { } } +#endif - public sealed class PlatformHandler_HttpClientHandler_Authentication_Http2_Test : HttpClientHandler_Authentication_Test + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsWindows10Version1607OrGreater))] + public sealed class PlatformHandler_HttpClientHandler_Http3_Test : HttpClientHandlerTest { - protected override Version UseVersion => HttpVersion20.Value; + protected override Version UseVersion => HttpVersion.Version30; - public PlatformHandler_HttpClientHandler_Authentication_Http2_Test(ITestOutputHelper output) : base(output) { } + public PlatformHandler_HttpClientHandler_Http3_Test(ITestOutputHelper output) : base(output) { } } #endif - public sealed class PlatformHandler_ResponseStream_Http2_Test : ResponseStreamTest - { - protected override Version UseVersion => HttpVersion20.Value; - - public PlatformHandler_ResponseStream_Http2_Test(ITestOutputHelper output) : base(output) { } - } } diff --git a/src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/System.Net.Http.WinHttpHandler.Functional.Tests.csproj b/src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/System.Net.Http.WinHttpHandler.Functional.Tests.csproj index c5c7099713aa5f..4a90073d5e8b0e 100644 --- a/src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/System.Net.Http.WinHttpHandler.Functional.Tests.csproj +++ b/src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/System.Net.Http.WinHttpHandler.Functional.Tests.csproj @@ -149,6 +149,12 @@ + + + diff --git a/src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/WinHttpClientHandler.cs b/src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/WinHttpClientHandler.cs index 0de22799d68841..7181e166417990 100644 --- a/src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/WinHttpClientHandler.cs +++ b/src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/WinHttpClientHandler.cs @@ -181,10 +181,12 @@ protected override Task SendAsync(HttpRequestMessage reques } } - if(_requestVersion >= HttpVersion20.Value) +#if NET + if (_requestVersion == request.Version && request.Version >= HttpVersion.Version30) { - request.Version = _requestVersion; + request.VersionPolicy = HttpVersionPolicy.RequestVersionExact; } +#endif return base.SendAsync(request, cancellationToken); } diff --git a/src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/WinHttpHandlerTest.cs b/src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/WinHttpHandlerTest.cs index 7e6c086eaa2ec8..2cda919ca12384 100644 --- a/src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/WinHttpHandlerTest.cs +++ b/src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/WinHttpHandlerTest.cs @@ -10,6 +10,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.DotNet.RemoteExecutor; +using TestUtilities; using Xunit; using Xunit.Abstractions; @@ -21,18 +22,50 @@ namespace System.Net.Http.WinHttpHandlerFunctional.Tests // Note: Disposing the HttpClient object automatically disposes the handler within. So, it is not necessary // to separately Dispose (or have a 'using' statement) for the handler. - public class WinHttpHandlerTest + public class WinHttpHandlerTest : HttpClientHandlerTestBase { private const string SlowServer = "http://httpbin.org/drip?numbytes=1&duration=1&delay=40&code=200"; - private readonly ITestOutputHelper _output; - public static IEnumerable HttpVersions = [[HttpVersion.Version11, Configuration.Http.SecureRemoteEchoServer], [HttpVersion20.Value, Configuration.Http.Http2RemoteEchoServer]]; public WinHttpHandlerTest(ITestOutputHelper output) + : base(output) + { } + +#if NET + [Theory] + [InlineData(1, 1)] + [InlineData(2, 0)] + [InlineData(3, 0)] + public async Task GetAsync_Succeeds(int major, int minor) { - _output = output; + using var _ = new TestEventListener(_output, TestEventListener.NetworkingEvents); + Version version = new Version(major, minor); + LoopbackServerFactory factory = major switch + { + 1 => Http11LoopbackServerFactory.Singleton, + 2 => Http2LoopbackServerFactory.Singleton, + 3 => Http3LoopbackServerFactory.Singleton, + _ => throw new InvalidOperationException($"Unexpected HTTP version: {version}") + }; + await factory.CreateServerAsync(async (server, url) => + { + WinHttpClientHandler handler = CreateHttpClientHandler(version); + using (HttpClient client = CreateHttpClient(handler)) + { + client.DefaultRequestVersion = version; + client.DefaultVersionPolicy = HttpVersionPolicy.RequestVersionExact; + Task clientTask = client.GetAsync(url); + + Task serverTask = server.AcceptConnectionSendResponseAndCloseAsync(); + + await TestHelper.WhenAllCompletedOrAnyFailed(clientTask, serverTask); + using HttpResponseMessage response = await clientTask; + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + } + }); } +#endif [OuterLoop] [Fact]