Esempio n. 1
0
        public async Task GetAsync_ResponseVersion0X_ThrowsOr10(int responseMinorVersion)
        {
            bool reportAs10 = PlatformDetection.IsFullFramework;

            await LoopbackServer.CreateServerAsync(async (server, url) =>
            {
                using (HttpClient client = CreateHttpClient())
                {
                    HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, url);
                    request.Version            = HttpVersion.Version11;

                    Task <HttpResponseMessage> getResponseTask = client.SendAsync(request);
                    Task <List <string> > serverTask           =
                        LoopbackServer.ReadRequestAndSendResponseAsync(server,
                                                                       $"HTTP/0.{responseMinorVersion} 200 OK\r\nDate: {DateTimeOffset.UtcNow:R}\r\nContent-Length: 0\r\n\r\n",
                                                                       new LoopbackServer.Options {
                        ResponseStreamWrapper = GetStream
                    });

                    if (reportAs10)
                    {
                        await TestHelper.WhenAllCompletedOrAnyFailed(getResponseTask, serverTask);

                        using (HttpResponseMessage response = await getResponseTask)
                        {
                            Assert.Equal(1, response.Version.Major);
                            Assert.Equal(0, response.Version.Minor);
                        }
                    }
                    else
                    {
                        await Assert.ThrowsAsync <HttpRequestException>(async() => await TestHelper.WhenAllCompletedOrAnyFailed(getResponseTask, serverTask));
                    }
                }
            });
        }
Esempio n. 2
0
        public async Task GetAsync_ResponseHasNormalLineEndings_Success(string lineEnding)
        {
            await LoopbackServer.CreateServerAsync(async (server, url) =>
            {
                using (HttpClient client = CreateHttpClient())
                {
                    Task <HttpResponseMessage> getResponseTask = client.GetAsync(url);
                    Task <List <string> > serverTask           = LoopbackServer.ReadRequestAndSendResponseAsync(server,
                                                                                                                $"HTTP/1.1 200 OK{lineEnding}Date: {DateTimeOffset.UtcNow:R}{lineEnding}Server: TestServer{lineEnding}Content-Length: 0{lineEnding}{lineEnding}",
                                                                                                                new LoopbackServer.Options {
                        ResponseStreamWrapper = GetStream
                    });

                    await TestHelper.WhenAllCompletedOrAnyFailed(getResponseTask, serverTask);

                    using (HttpResponseMessage response = await getResponseTask)
                    {
                        Assert.Equal(200, (int)response.StatusCode);
                        Assert.Equal("OK", response.ReasonPhrase);
                        Assert.Equal("TestServer", response.Headers.Server.ToString());
                    }
                }
            });
        }
        public async Task HttpClientHandler_MultipleAuthenticateHeaders_PicksSupported(string authenticateHeader, string supportedAuth, string unsupportedAuth)
        {
            if (PlatformDetection.IsWindowsNanoServer || (IsCurlHandler && authenticateHeader.Contains("Digest")))
            {
                // TODO: #28065: Fix failing authentication test cases on different httpclienthandlers.
                return;
            }

            var options = new LoopbackServer.Options {
                Domain = Domain, Username = Username, Password = Password
            };
            await LoopbackServer.CreateServerAsync(async (server, url) =>
            {
                HttpClientHandler handler     = CreateHttpClientHandler();
                handler.UseDefaultCredentials = false;

                var credentials = new CredentialCache();
                credentials.Add(url, supportedAuth, new NetworkCredential(Username, Password, Domain));
                credentials.Add(url, unsupportedAuth, new NetworkCredential(Username, Password, Domain));

                Task serverTask = server.AcceptConnectionPerformAuthenticationAndCloseAsync(authenticateHeader);
                await TestHelper.WhenAllCompletedOrAnyFailed(CreateAndValidateRequest(handler, url, HttpStatusCode.OK, credentials), serverTask);
            }, options);
        }
Esempio n. 4
0
        public async Task SetDelegate_ConnectionSucceeds(SslProtocols acceptedProtocol, bool requestOnlyThisProtocol)
        {
            using (var handler = new HttpClientHandler()
            {
                ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator
            })
                using (var client = new HttpClient(handler))
                {
                    if (requestOnlyThisProtocol)
                    {
                        handler.SslProtocols = acceptedProtocol;
                    }

                    var options = new LoopbackServer.Options {
                        UseSsl = true, SslProtocols = acceptedProtocol
                    };
                    await LoopbackServer.CreateServerAsync(async (server, url) =>
                    {
                        await TestHelper.WhenAllCompletedOrAnyFailed(
                            LoopbackServer.ReadRequestAndSendResponseAsync(server, options: options),
                            client.GetAsync(url));
                    }, options);
                }
        }
 public async Task GetAsync_NoSpecifiedProtocol_DefaultsToTls12()
 {
     using (var handler = new HttpClientHandler()
     {
         ServerCertificateCustomValidationCallback = LoopbackServer.AllowAllCertificates
     })
         using (var client = new HttpClient(handler))
         {
             var options = new LoopbackServer.Options {
                 UseSsl = true
             };
             await LoopbackServer.CreateServerAsync(async (server, url) =>
             {
                 await TestHelper.WhenAllCompletedOrAnyFailed(
                     client.GetAsync(url),
                     LoopbackServer.AcceptSocketAsync(server, async(s, stream, reader, writer) =>
                 {
                     Assert.Equal(SslProtocols.Tls12, Assert.IsType <SslStream>(stream).SslProtocol);
                     await LoopbackServer.ReadWriteAcceptedAsync(s, reader, writer);
                     return(null);
                 }, options));
             }, options);
         }
 }
        public async Task ProxyTunnelRequest_GetAsync_Success()
        {
            if (IsWinHttpHandler)
            {
                return;
            }

            const string Content = "Hello world";

            using (LoopbackProxyServer proxyServer = LoopbackProxyServer.Create())
            {
                HttpClientHandler handler = CreateHttpClientHandler();
                handler.Proxy = new WebProxy(proxyServer.Uri);
                handler.ServerCertificateCustomValidationCallback = TestHelper.AllowAllCertificates;
                using (HttpClient client = CreateHttpClient(handler))
                {
                    var options = new LoopbackServer.Options {
                        UseSsl = true
                    };
                    await LoopbackServer.CreateServerAsync(async (server, uri) =>
                    {
                        Assert.Equal(proxyServer.Uri, handler.Proxy.GetProxy(uri));

                        Task <HttpResponseMessage> clientTask = client.GetAsync(uri);
                        await server.AcceptConnectionSendResponseAndCloseAsync(content: Content);
                        using (var response = await clientTask)
                        {
                            Assert.Equal(HttpStatusCode.OK, response.StatusCode);
                            Assert.Equal(Content, await response.Content.ReadAsStringAsync());
                        }
                    }, options);
                }

                Assert.Contains("CONNECT", proxyServer.Requests[0].RequestLine);
            }
        }
        public async Task ProxyTunnelRequest_OriginServerSendsProxyAuthChallenge_NoProxyAuthPerformed()
        {
            if (IsWinHttpHandler)
            {
                return;
            }

            using (LoopbackProxyServer proxyServer = LoopbackProxyServer.Create())
            {
                HttpClientHandler handler = CreateHttpClientHandler();
                handler.Proxy = new WebProxy(proxyServer.Uri)
                {
                    Credentials = ConstructCredentials(new NetworkCredential("username", "password"), proxyServer.Uri, BasicAuth, true)
                };
                handler.ServerCertificateCustomValidationCallback = TestHelper.AllowAllCertificates;
                using (HttpClient client = CreateHttpClient(handler))
                {
                    var options = new LoopbackServer.Options {
                        UseSsl = true
                    };
                    await LoopbackServer.CreateServerAsync(async (server, uri) =>
                    {
                        Assert.Equal(proxyServer.Uri, handler.Proxy.GetProxy(uri));

                        Task <HttpResponseMessage> clientTask = client.GetAsync(uri);
                        await server.AcceptConnectionSendResponseAndCloseAsync(statusCode: HttpStatusCode.ProxyAuthenticationRequired, additionalHeaders: "Proxy-Authenticate: Basic");
                        using (var response = await clientTask)
                        {
                            Assert.Equal(HttpStatusCode.ProxyAuthenticationRequired, response.StatusCode);
                        }
                    }, options);
                }

                Assert.Contains("CONNECT", proxyServer.Requests[0].RequestLine);
            }
        }
Esempio n. 8
0
        public async Task InfiniteSingleHeader_ThrowsException()
        {
            await LoopbackServer.CreateServerAsync(async (server, url) =>
            {
                using (HttpClientHandler handler = CreateHttpClientHandler())
                    using (HttpClient client = CreateHttpClient(handler))
                    {
                        Task <HttpResponseMessage> getAsync = client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead);
                        await server.AcceptConnectionAsync(async connection =>
                        {
                            var cts         = new CancellationTokenSource();
                            Task serverTask = Task.Run(async delegate
                            {
                                await connection.ReadRequestHeaderAndSendCustomResponseAsync("HTTP/1.1 200 OK\r\nContent-Length: 0\r\nMyInfiniteHeader: ");
                                try
                                {
                                    while (!cts.IsCancellationRequested)
                                    {
                                        await connection.Writer.WriteAsync(new string('s', 16000));
                                        await Task.Delay(1);
                                    }
                                }
                                catch { }
                            });

                            Exception e = await Assert.ThrowsAsync <HttpRequestException>(() => getAsync);
                            cts.Cancel();
                            if (!IsWinHttpHandler)
                            {
                                Assert.Contains((handler.MaxResponseHeadersLength * 1024).ToString(), e.ToString());
                            }
                            await serverTask;
                        });
                    }
            });
        }
Esempio n. 9
0
        public async Task GetAsync_AddMultipleCookieHeaders_CookiesSent()
        {
            if (IsNetfxHandler)
            {
                // Netfx handler does not support custom cookie header
                return;
            }

            await LoopbackServer.CreateServerAsync(async (server, url) =>
            {
                HttpClientHandler handler = CreateHttpClientHandler();
                using (HttpClient client = new HttpClient(handler))
                {
                    HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Get, url);
                    requestMessage.Headers.Add("Cookie", "A=1");
                    requestMessage.Headers.Add("Cookie", "B=2");
                    requestMessage.Headers.Add("Cookie", "C=3");

                    Task <HttpResponseMessage> getResponseTask = client.SendAsync(requestMessage);
                    Task <List <string> > serverTask           = server.AcceptConnectionSendResponseAndCloseAsync();

                    List <string> requestLines = await serverTask;

                    Assert.Equal(1, requestLines.Count(s => s.StartsWith("Cookie: ")));

                    // Multiple Cookie header values are treated as any other header values and are
                    // concatenated using ", " as the separator.

                    var cookieValues = requestLines.Single(s => s.StartsWith("Cookie: ")).Substring(8).Split(new string[] { ", " }, StringSplitOptions.None);
                    Assert.Contains("A=1", cookieValues);
                    Assert.Contains("B=2", cookieValues);
                    Assert.Contains("C=3", cookieValues);
                    Assert.Equal(3, cookieValues.Count());
                }
            });
        }
        private static void CreateServerAndGet(HttpClient client, HttpCompletionOption completionOption, string responseText)
        {
            LoopbackServer.CreateServerAsync((server, url) =>
            {
                Task <HttpResponseMessage> getAsync = client.GetAsync(url, completionOption);

                LoopbackServer.AcceptSocketAsync(server, (s, stream, reader, writer) =>
                {
                    while (!string.IsNullOrEmpty(reader.ReadLine()))
                    {
                        ;
                    }

                    writer.Write(responseText);
                    writer.Flush();
                    s.Shutdown(SocketShutdown.Send);

                    return(Task.CompletedTask);
                }).GetAwaiter().GetResult();

                getAsync.GetAwaiter().GetResult().Dispose();
                return(Task.CompletedTask);
            }).GetAwaiter().GetResult();
        }
Esempio n. 11
0
        public async Task GetAsync_RequestVersion10_Success()
        {
            await LoopbackServer.CreateServerAsync(async (server, url) =>
            {
                using (HttpClient client = CreateHttpClient())
                {
                    HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, url);
                    request.Version            = HttpVersion.Version10;

                    Task <HttpResponseMessage> getResponseTask = client.SendAsync(request);
                    Task <List <string> > serverTask           =
                        LoopbackServer.ReadRequestAndSendResponseAsync(server,
                                                                       $"HTTP/1.1 200 OK\r\nDate: {DateTimeOffset.UtcNow:R}\r\nContent-Length: 0\r\n\r\n",
                                                                       new LoopbackServer.Options {
                        ResponseStreamWrapper = GetStream
                    });

                    await TestHelper.WhenAllCompletedOrAnyFailed(getResponseTask, serverTask);

                    var requestLines = await serverTask;
                    Assert.Equal($"GET {url.PathAndQuery} HTTP/1.0", requestLines[0]);
                }
            });
        }
Esempio n. 12
0
        public async Task SetDelegate_ConnectionSucceeds(SslProtocols acceptedProtocol, bool requestOnlyThisProtocol)
        {
            // Overriding flag for the same reason we skip tests on Catalina
            // On OSX 10.13-10.14 we can override this flag to enable the scenario
            // Issue: #22089
            requestOnlyThisProtocol |= PlatformDetection.IsMacOsHighSierraOrHigher && acceptedProtocol == SslProtocols.Tls;

            using (HttpClientHandler handler = CreateHttpClientHandler())
                using (HttpClient client = CreateHttpClient(handler))
                {
                    handler.ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;

                    if (requestOnlyThisProtocol)
                    {
                        handler.SslProtocols = acceptedProtocol;
                    }
                    else
                    {
                        // Explicitly setting protocols clears implementation default
                        // restrictions on minimum TLS/SSL version
                        // We currently know that some platforms like Debian 10 OpenSSL
                        // will by default block < TLS 1.2
                        handler.SslProtocols = SslProtocols.Tls13 | SslProtocols.Tls12 | SslProtocols.Tls11 | SslProtocols.Tls;
                    }

                    var options = new LoopbackServer.Options {
                        UseSsl = true, SslProtocols = acceptedProtocol
                    };
                    await LoopbackServer.CreateServerAsync(async (server, url) =>
                    {
                        await TestHelper.WhenAllCompletedOrAnyFailed(
                            server.AcceptConnectionSendResponseAndCloseAsync(),
                            client.GetAsync(url));
                    }, options);
                }
        }
Esempio n. 13
0
 private async Task GetAsyncSuccessHelper(string statusLine, int expectedStatusCode, string expectedReason)
 {
     await LoopbackServer.CreateServerAsync(async (server, url) =>
     {
         using (HttpClient client = CreateHttpClient())
         {
             Task <HttpResponseMessage> getResponseTask = client.GetAsync(url);
             await TestHelper.WhenAllCompletedOrAnyFailed(
                 getResponseTask,
                 LoopbackServer.ReadRequestAndSendResponseAsync(server,
                                                                $"{statusLine}\r\n" +
                                                                $"Date: {DateTimeOffset.UtcNow:R}\r\n" +
                                                                "\r\n",
                                                                new LoopbackServer.Options {
                 ResponseStreamWrapper = GetStream
             }));
             using (HttpResponseMessage response = await getResponseTask)
             {
                 Assert.Equal(expectedStatusCode, (int)response.StatusCode);
                 Assert.Equal(expectedReason, response.ReasonPhrase);
             }
         }
     });
 }
Esempio n. 14
0
        public async Task GetAsync_AllowedSSLVersionDiffersFromServer_ThrowsException(
            SslProtocols allowedProtocol, SslProtocols acceptedProtocol, Type exceptedServerException)
        {
            if (!BackendSupportsSslConfiguration)
            {
                return;
            }
            using (HttpClientHandler handler = CreateHttpClientHandler())
                using (var client = new HttpClient(handler))
                {
                    handler.SslProtocols = allowedProtocol;
                    handler.ServerCertificateCustomValidationCallback = TestHelper.AllowAllCertificates;

                    var options = new LoopbackServer.Options {
                        UseSsl = true, SslProtocols = acceptedProtocol
                    };
                    await LoopbackServer.CreateServerAsync(async (server, url) =>
                    {
                        await TestHelper.WhenAllCompletedOrAnyFailed(
                            Assert.ThrowsAsync(exceptedServerException, () => server.AcceptConnectionSendResponseAndCloseAsync()),
                            Assert.ThrowsAsync <HttpRequestException>(() => client.GetAsync(url)));
                    }, options);
                }
        }
        public async Task GetAsync_AllowAutoRedirectTrue_RetainsOriginalFragmentIfAppropriate(
            string origFragment, string redirFragment, string expectedFragment, bool useRelativeRedirect)
        {
            if (IsWinHttpHandler)
            {
                // According to https://tools.ietf.org/html/rfc7231#section-7.1.2,
                // "If the Location value provided in a 3xx (Redirection) response does
                //  not have a fragment component, a user agent MUST process the
                //  redirection as if the value inherits the fragment component of the
                //  URI reference used to generate the request target(i.e., the
                //  redirection inherits the original reference's fragment, if any)."
                // WINHTTP is not doing this, and thus neither is WinHttpHandler.
                // It also sometimes doesn't include the fragments for redirects
                // even in other cases.
                return;
            }

            HttpClientHandler handler = CreateHttpClientHandler();

            handler.AllowAutoRedirect = true;
            using (HttpClient client = CreateHttpClient(handler))
            {
                await LoopbackServer.CreateServerAsync(async (origServer, origUrl) =>
                {
                    origUrl = new UriBuilder(origUrl)
                    {
                        Fragment = origFragment
                    }.Uri;
                    Uri redirectUrl = new UriBuilder(origUrl)
                    {
                        Fragment = redirFragment
                    }.Uri;
                    if (useRelativeRedirect)
                    {
                        redirectUrl = new Uri(redirectUrl.GetComponents(UriComponents.PathAndQuery | UriComponents.Fragment, UriFormat.SafeUnescaped), UriKind.Relative);
                    }
                    Uri expectedUrl = new UriBuilder(origUrl)
                    {
                        Fragment = expectedFragment
                    }.Uri;

                    // Make and receive the first request that'll be redirected.
                    Task <HttpResponseMessage> getResponse = client.GetAsync(origUrl);
                    Task firstRequest = origServer.AcceptConnectionSendResponseAndCloseAsync(HttpStatusCode.Found, $"Location: {redirectUrl}\r\n");
                    Assert.Equal(firstRequest, await Task.WhenAny(firstRequest, getResponse));

                    // Receive the second request.
                    Task <List <string> > secondRequest = origServer.AcceptConnectionSendResponseAndCloseAsync();
                    await TestHelper.WhenAllCompletedOrAnyFailed(secondRequest, getResponse);

                    // Make sure the server received the second request for the right Uri.
                    Assert.NotEmpty(secondRequest.Result);
                    string[] statusLineParts = secondRequest.Result[0].Split(' ');
                    Assert.Equal(3, statusLineParts.Length);
                    Assert.Equal(expectedUrl.GetComponents(UriComponents.PathAndQuery, UriFormat.SafeUnescaped), statusLineParts[1]);

                    // Make sure the request message was updated with the correct redirected location.
                    using (HttpResponseMessage response = await getResponse)
                    {
                        Assert.Equal(200, (int)response.StatusCode);
                        Assert.Equal(expectedUrl.ToString(), response.RequestMessage.RequestUri.ToString());
                    }
                });
            }
        }
        public async Task Manual_CertificateSentMatchesCertificateReceived_Success(
            int numberOfRequests,
            bool reuseClient) // validate behavior with and without connection pooling, which impacts client cert usage
        {
            if (BackendDoesNotSupportCustomCertificateHandling) // can't use [Conditional*] right now as it's evaluated at the wrong time for the managed handler
            {
                _output.WriteLine($"Skipping {nameof(Manual_CertificateSentMatchesCertificateReceived_Success)}()");
                return;
            }

            var options = new LoopbackServer.Options { UseSsl = true };

            Func<X509Certificate2, HttpClient> createClient = (cert) =>
            {
                var handler = new HttpClientHandler() { ServerCertificateCustomValidationCallback = delegate { return true; } };
                handler.ClientCertificates.Add(cert);
                return new HttpClient(handler);
            };

            Func<HttpClient, Socket, Uri, X509Certificate2, Task> makeAndValidateRequest = async (client, server, url, cert) =>
            {
                await TestHelper.WhenAllCompletedOrAnyFailed(
                    client.GetStringAsync(url),
                    LoopbackServer.AcceptSocketAsync(server, async (socket, stream, reader, writer) =>
                    {
                        SslStream sslStream = Assert.IsType<SslStream>(stream);
                        Assert.Equal(cert, sslStream.RemoteCertificate);
                        await LoopbackServer.ReadWriteAcceptedAsync(socket, reader, writer);
                        return null;
                    }, options));
            };

            await LoopbackServer.CreateServerAsync(async (server, url) =>
            {
                if (reuseClient)
                {
                    using (X509Certificate2 cert = Configuration.Certificates.GetClientCertificate())
                    {
                        using (HttpClient client = createClient(cert))
                        {
                            for (int i = 0; i < numberOfRequests; i++)
                            {
                                await makeAndValidateRequest(client, server, url, cert);

                                GC.Collect();
                                GC.WaitForPendingFinalizers();
                            }
                        }
                    }
                }
                else
                {
                    for (int i = 0; i < numberOfRequests; i++)
                    {
                        using (X509Certificate2 cert = Configuration.Certificates.GetClientCertificate())
                        {
                            using (HttpClient client = createClient(cert))
                            {
                                await makeAndValidateRequest(client, server, url, cert);
                            }
                        }

                        GC.Collect();
                        GC.WaitForPendingFinalizers();
                    }
                }
            }, options);
        }
Esempio n. 17
0
        public async Task AllowAutoRedirect_True_PostToGetDoesNotSendTE(int statusCode)
        {
            if (IsCurlHandler && statusCode == 300)
            {
                // ISSUE #26434:
                // CurlHandler doesn't change POST to GET for 300 response (see above test).
                return;
            }

            if (IsWinHttpHandler)
            {
                // ISSUE #27440:
                // This test occasionally fails on WinHttpHandler.
                // Likely this is due to the way the loopback server is sending the response before reading the entire request.
                // We should change the server behavior here.
                return;
            }

            HttpClientHandler handler = CreateHttpClientHandler();

            using (var client = new HttpClient(handler))
            {
                await LoopbackServer.CreateServerAsync(async (origServer, origUrl) =>
                {
                    var request     = new HttpRequestMessage(HttpMethod.Post, origUrl);
                    request.Content = new StringContent(ExpectedContent);
                    request.Headers.TransferEncodingChunked = true;

                    Task <HttpResponseMessage> getResponseTask = client.SendAsync(request);

                    await LoopbackServer.CreateServerAsync(async(redirServer, redirUrl) =>
                    {
                        // Original URL will redirect to a different URL
                        Task serverTask = origServer.AcceptConnectionAsync(async connection =>
                        {
                            // Send Connection: close so the client will close connection after request is sent,
                            // meaning we can just read to the end to get the content
                            await connection.ReadRequestHeaderAndSendResponseAsync((HttpStatusCode)statusCode, $"Location: {redirUrl}\r\nConnection: close\r\n");
                            connection.Socket.Shutdown(SocketShutdown.Send);
                            await connection.Reader.ReadToEndAsync();
                        });

                        await Task.WhenAny(getResponseTask, serverTask);
                        Assert.False(getResponseTask.IsCompleted, $"{getResponseTask.Status}: {getResponseTask.Exception}");
                        await serverTask;

                        // Redirected URL answers with success
                        List <string> receivedRequest = null;
                        string receivedContent        = null;
                        Task serverTask2 = redirServer.AcceptConnectionAsync(async connection =>
                        {
                            // Send Connection: close so the client will close connection after request is sent,
                            // meaning we can just read to the end to get the content
                            receivedRequest = await connection.ReadRequestHeaderAndSendResponseAsync(additionalHeaders: "Connection: close\r\n");
                            connection.Socket.Shutdown(SocketShutdown.Send);
                            receivedContent = await connection.Reader.ReadToEndAsync();
                        });

                        await TestHelper.WhenAllCompletedOrAnyFailed(getResponseTask, serverTask2);

                        string[] statusLineParts = receivedRequest[0].Split(' ');
                        Assert.Equal("GET", statusLineParts[0]);
                        Assert.DoesNotContain(receivedRequest, line => line.StartsWith("Transfer-Encoding"));
                        Assert.DoesNotContain(receivedRequest, line => line.StartsWith("Content-Length"));

                        using (HttpResponseMessage response = await getResponseTask)
                        {
                            Assert.Equal(200, (int)response.StatusCode);
                        }
                    });
                });
            }
        }
Esempio n. 18
0
        public async Task GetAsyncVersion11_BadResponseVersion_ThrowsOr00(int responseMajorVersion, int responseMinorVersion)
        {
            // Full framework reports 1.0 or 1.1, depending on minor version, instead of throwing
            bool reportAs1X = PlatformDetection.IsFullFramework;

            // CurlHandler reports these as 0.0, except for 2.0 which is reported as 2.0, instead of throwing.
            bool reportAs00 = false;
            bool reportAs20 = false;

            if (!PlatformDetection.IsWindows && !UseSocketsHttpHandler)
            {
                if (responseMajorVersion == 2 && responseMinorVersion == 0)
                {
                    reportAs20 = true;
                }
                else
                {
                    reportAs00 = true;
                }
            }

            await LoopbackServer.CreateServerAsync(async (server, url) =>
            {
                using (HttpClient client = CreateHttpClient())
                {
                    HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, url);
                    request.Version            = HttpVersion.Version11;

                    Task <HttpResponseMessage> getResponseTask = client.SendAsync(request);
                    Task <List <string> > serverTask           =
                        LoopbackServer.ReadRequestAndSendResponseAsync(server,
                                                                       $"HTTP/{responseMajorVersion}.{responseMinorVersion} 200 OK\r\nDate: {DateTimeOffset.UtcNow:R}\r\nContent-Length: 0\r\n\r\n",
                                                                       new LoopbackServer.Options {
                        ResponseStreamWrapper = GetStream_ClientDisconnectOk
                    });

                    if (reportAs00)
                    {
                        await TestHelper.WhenAllCompletedOrAnyFailed(getResponseTask, serverTask);

                        using (HttpResponseMessage response = await getResponseTask)
                        {
                            Assert.Equal(0, response.Version.Major);
                            Assert.Equal(0, response.Version.Minor);
                        }
                    }
                    else if (reportAs20)
                    {
                        await TestHelper.WhenAllCompletedOrAnyFailed(getResponseTask, serverTask);

                        using (HttpResponseMessage response = await getResponseTask)
                        {
                            Assert.Equal(2, response.Version.Major);
                            Assert.Equal(0, response.Version.Minor);
                        }
                    }
                    else if (reportAs1X)
                    {
                        await TestHelper.WhenAllCompletedOrAnyFailed(getResponseTask, serverTask);

                        using (HttpResponseMessage response = await getResponseTask)
                        {
                            Assert.Equal(1, response.Version.Major);
                            Assert.Equal(responseMinorVersion == 0 ? 0 : 1, response.Version.Minor);
                        }
                    }
                    else
                    {
                        await Assert.ThrowsAsync <HttpRequestException>(async() => await TestHelper.WhenAllCompletedOrAnyFailed(getResponseTask, serverTask));
                    }
                }
            });
        }
Esempio n. 19
0
        public async Task GetAsync_SetCookieContainerAndMultipleCookieHeaders_BothCookiesSent()
        {
            if (IsNetfxHandler)
            {
                // Netfx handler does not support custom cookie header
                return;
            }

            if (IsCurlHandler)
            {
                // Issue #26983
                // CurlHandler ignores container cookies when custom Cookie header is set.
                return;
            }

            await LoopbackServer.CreateServerAsync(async (server, url) =>
            {
                HttpClientHandler handler = CreateHttpClientHandler();
                handler.CookieContainer   = CreateSingleCookieContainer(url);

                using (HttpClient client = new HttpClient(handler))
                {
                    HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Get, url);
                    requestMessage.Headers.Add("Cookie", "A=1");
                    requestMessage.Headers.Add("Cookie", "B=2");

                    Task <HttpResponseMessage> getResponseTask = client.SendAsync(requestMessage);
                    Task <List <string> > serverTask           = LoopbackServer.ReadRequestAndSendResponseAsync(server);
                    await TestHelper.WhenAllCompletedOrAnyFailed(getResponseTask, serverTask);

                    List <string> requestLines = await serverTask;

                    Assert.Equal(1, requestLines.Count(s => s.StartsWith("Cookie: ")));

                    // Multiple Cookie header values are treated as any other header values and are
                    // concatenated using ", " as the separator.  The container cookie is concatenated to
                    // one of these values using the "; " cookie separator.

                    var cookieValues = requestLines.Single(s => s.StartsWith("Cookie: ")).Substring(8).Split(new string[] { ", " }, StringSplitOptions.None);
                    Assert.Equal(2, cookieValues.Count());

                    // Find container cookie and remove it so we can validate the rest of the cookie header values
                    bool sawContainerCookie = false;
                    for (int i = 0; i < cookieValues.Length; i++)
                    {
                        if (cookieValues[i].Contains(';'))
                        {
                            Assert.False(sawContainerCookie);

                            var cookies = cookieValues[i].Split(new string[] { "; " }, StringSplitOptions.None);
                            Assert.Equal(2, cookies.Count());
                            Assert.Contains(s_expectedCookieHeaderValue, cookies);

                            sawContainerCookie = true;
                            cookieValues[i]    = cookies.Where(c => c != s_expectedCookieHeaderValue).Single();
                        }
                    }

                    Assert.Contains("A=1", cookieValues);
                    Assert.Contains("B=2", cookieValues);
                }
            });
        }
Esempio n. 20
0
        public void SendAsync_ExpectedDiagnosticSourceActivityLogging()
        {
            RemoteInvoke(() =>
            {
                bool requestLogged       = false;
                bool responseLogged      = false;
                bool activityStartLogged = false;
                bool activityStopLogged  = false;
                bool exceptionLogged     = false;

                Activity parentActivity = new Activity("parent");
                parentActivity.AddBaggage("correlationId", Guid.NewGuid().ToString());
                parentActivity.AddBaggage("moreBaggage", Guid.NewGuid().ToString());
                parentActivity.AddTag("tag", "tag"); //add tag to ensure it is not injected into request
                parentActivity.Start();

                var diagnosticListenerObserver = new FakeDiagnosticListenerObserver(kvp =>
                {
                    if (kvp.Key.Equals("System.Net.Http.Request"))
                    {
                        requestLogged = true;
                    }
                    else if (kvp.Key.Equals("System.Net.Http.Response"))
                    {
                        responseLogged = true;
                    }
                    else if (kvp.Key.Equals("System.Net.Http.Exception"))
                    {
                        exceptionLogged = true;
                    }
                    else if (kvp.Key.Equals("System.Net.Http.HttpRequestOut.Start"))
                    {
                        Assert.NotNull(kvp.Value);
                        Assert.NotNull(Activity.Current);
                        Assert.Equal(parentActivity, Activity.Current.Parent);
                        GetPropertyValueFromAnonymousTypeInstance <HttpRequestMessage>(kvp.Value, "Request");

                        activityStartLogged = true;
                    }
                    else if (kvp.Key.Equals("System.Net.Http.HttpRequestOut.Stop"))
                    {
                        Assert.NotNull(kvp.Value);
                        Assert.NotNull(Activity.Current);
                        Assert.Equal(parentActivity, Activity.Current.Parent);
                        Assert.True(Activity.Current.Duration != TimeSpan.Zero);
                        GetPropertyValueFromAnonymousTypeInstance <HttpRequestMessage>(kvp.Value, "Request");
                        GetPropertyValueFromAnonymousTypeInstance <HttpResponseMessage>(kvp.Value, "Response");
                        var requestStatus = GetPropertyValueFromAnonymousTypeInstance <TaskStatus>(kvp.Value, "RequestTaskStatus");
                        Assert.Equal(TaskStatus.RanToCompletion, requestStatus);

                        activityStopLogged = true;
                    }
                });

                using (DiagnosticListener.AllListeners.Subscribe(diagnosticListenerObserver))
                {
                    diagnosticListenerObserver.Enable();
                    using (var client = new HttpClient())
                    {
                        LoopbackServer.CreateServerAsync(async(server, url) =>
                        {
                            Task <List <string> > requestLines = LoopbackServer.AcceptSocketAsync(server,
                                                                                                  (s, stream, reader, writer) => LoopbackServer.ReadWriteAcceptedAsync(s, reader, writer));
                            Task response = client.GetAsync(url);
                            await Task.WhenAll(response, requestLines);

                            AssertHeadersAreInjected(requestLines.Result, parentActivity);
                        }).Wait();
                    }

                    Assert.True(activityStartLogged, "HttpRequestOut.Start was not logged.");
                    Assert.False(requestLogged, "Request was logged when Activity logging was enabled.");
                    // Poll with a timeout since logging response is not synchronized with returning a response.
                    WaitForTrue(() => activityStopLogged, TimeSpan.FromSeconds(1), "HttpRequestOut.Stop was not logged within 1 second timeout.");
                    Assert.False(exceptionLogged, "Exception was logged for successful request");
                    Assert.False(responseLogged, "Response was logged when Activity logging was enabled.");
                    diagnosticListenerObserver.Disable();
                }

                return(SuccessExitCode);
            }).Dispose();
        }
        public async Task ConnectMethod_Success()
        {
            await LoopbackServer.CreateServerAsync(async (server, url) =>
            {
                using (HttpClient client = CreateHttpClient())
                {
                    HttpRequestMessage request = new HttpRequestMessage(new HttpMethod("CONNECT"), url)
                    {
                        Version = UseVersion
                    };
                    request.Headers.Host = "foo.com:345";

                    // We need to use ResponseHeadersRead here, otherwise we will hang trying to buffer the response body.
                    Task <HttpResponseMessage> responseTask = client.SendAsync(TestAsync, request, HttpCompletionOption.ResponseHeadersRead);

                    await server.AcceptConnectionAsync(async connection =>
                    {
                        // Verify that Host header exist and has same value and URI authority.
                        List <string> lines = await connection.ReadRequestHeaderAsync().ConfigureAwait(false);
                        string authority    = lines[0].Split()[1];
                        foreach (string line in lines)
                        {
                            if (line.StartsWith("Host:", StringComparison.InvariantCultureIgnoreCase))
                            {
                                Assert.Equal("Host: foo.com:345", line);
                                break;
                            }
                        }

                        Task serverTask = connection.SendResponseAsync(HttpStatusCode.OK);
                        await TestHelper.WhenAllCompletedOrAnyFailed(responseTask, serverTask).ConfigureAwait(false);

                        using (Stream clientStream = await(await responseTask).Content.ReadAsStreamAsync())
                        {
                            Assert.True(clientStream.CanWrite);
                            Assert.True(clientStream.CanRead);
                            Assert.False(clientStream.CanSeek);

                            TextReader clientReader = new StreamReader(clientStream);
                            TextWriter clientWriter = new StreamWriter(clientStream)
                            {
                                AutoFlush = true
                            };
                            TextWriter serverWriter = connection.Writer;

                            const string helloServer   = "hello server";
                            const string helloClient   = "hello client";
                            const string goodbyeServer = "goodbye server";
                            const string goodbyeClient = "goodbye client";

                            clientWriter.WriteLine(helloServer);
                            Assert.Equal(helloServer, connection.ReadLine());
                            serverWriter.WriteLine(helloClient);
                            Assert.Equal(helloClient, clientReader.ReadLine());
                            clientWriter.WriteLine(goodbyeServer);
                            Assert.Equal(goodbyeServer, connection.ReadLine());
                            serverWriter.WriteLine(goodbyeClient);
                            Assert.Equal(goodbyeClient, clientReader.ReadLine());
                        }
                    });
                }
            });
        }
        public async Task Manual_CertificateSentMatchesCertificateReceived_Success(
            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;
            }

            if (!UseSocketsHttpHandler)
            {
                // Issue #9543: fails sporadically on WinHttpHandler/CurlHandler
                return;
            }

            var options = new LoopbackServer.Options {
                UseSsl = true
            };

            Func <X509Certificate2, HttpClient> createClient = (cert) =>
            {
                StandardSocketsHttpHandler handler = CreateSocketsHttpHandler();
                handler.SslOptions.RemoteCertificateValidationCallback = SecurityHelper.AllowAllCertificates;
                handler.SslOptions.ClientCertificates = new X509CertificateCollection();
                handler.SslOptions.ClientCertificates.Add(cert);
                Assert.True(handler.SslOptions.ClientCertificates.Contains(cert));
                handler.SslOptions.LocalCertificateSelectionCallback = (object sender, string targetHost, X509CertificateCollection localCertificates, X509Certificate remoteCertificate, string[] acceptableIssuers) => cert;
                return(new HttpClient(handler));
            };

            Func <HttpClient, LoopbackServer, Uri, X509Certificate2, Task> makeAndValidateRequest = async(client, server, url, cert) =>
            {
                await TestHelper.WhenAllCompletedOrAnyFailed(
                    client.GetStringAsync(url),
                    server.AcceptConnectionAsync(async connection =>
                {
                    SslStream sslStream = Assert.IsType <SslStream>(connection.Stream);
                    Assert.Equal(cert, sslStream.RemoteCertificate);
                    await connection.ReadRequestHeaderAndSendResponseAsync();
                }));
            };

            await LoopbackServer.CreateServerAsync(async (server, url) =>
            {
                using (X509Certificate2 cert = Configuration.Certificates.GetClientCertificate())
                {
                    if (reuseClient)
                    {
                        using (HttpClient client = createClient(cert))
                        {
                            for (int i = 0; i < numberOfRequests; i++)
                            {
                                await makeAndValidateRequest(client, server, url, cert);

                                GC.Collect();
                                GC.WaitForPendingFinalizers();
                            }
                        }
                    }
                    else
                    {
                        for (int i = 0; i < numberOfRequests; i++)
                        {
                            using (HttpClient client = createClient(cert))
                            {
                                await makeAndValidateRequest(client, server, url, cert);
                            }

                            GC.Collect();
                            GC.WaitForPendingFinalizers();
                        }
                    }
                }
            }, options);
        }
Esempio n. 23
0
        public async Task GetAsync_CancelPendingRequests_DoesntCancelReadAsyncOnResponseStream(CancellationMode mode, bool copyToAsync)
        {
            if (IsNetfxHandler)
            {
                // throws ObjectDisposedException as part of Stream.CopyToAsync/ReadAsync
                return;
            }
            if (IsCurlHandler)
            {
                // Issue #27065
                // throws OperationCanceledException from Stream.CopyToAsync/ReadAsync
                return;
            }

            using (HttpClient client = CreateHttpClient())
            {
                client.Timeout = Timeout.InfiniteTimeSpan;

                await LoopbackServer.CreateServerAsync(async (server, url) =>
                {
                    var clientReadSomeBody = new TaskCompletionSource <bool>();
                    var clientFinished     = new TaskCompletionSource <bool>();

                    var responseContentSegment = new string('s', 3000);
                    int responseSegments       = 4;
                    int contentLength          = responseContentSegment.Length * responseSegments;

                    Task serverTask = server.AcceptConnectionAsync(async connection =>
                    {
                        await connection.ReadRequestHeaderAndSendCustomResponseAsync(
                            $"HTTP/1.1 200 OK\r\n" +
                            $"Date: {DateTimeOffset.UtcNow:R}\r\n" +
                            $"Content-Length: {contentLength}\r\n" +
                            $"\r\n");

                        for (int i = 0; i < responseSegments; i++)
                        {
                            await connection.Writer.WriteAsync(responseContentSegment);
                            if (i == 0)
                            {
                                await clientReadSomeBody.Task;
                            }
                        }

                        await clientFinished.Task;
                    });


                    using (HttpResponseMessage resp = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead))
                        using (Stream respStream = await resp.Content.ReadAsStreamAsync())
                        {
                            var result = new MemoryStream();
                            int b      = respStream.ReadByte();
                            Assert.NotEqual(-1, b);
                            result.WriteByte((byte)b);

                            Cancel(mode, client, null); // should not cancel the operation, as using ResponseHeadersRead
                            clientReadSomeBody.SetResult(true);

                            if (copyToAsync)
                            {
                                await respStream.CopyToAsync(result, 10, new CancellationTokenSource().Token);
                            }
                            else
                            {
                                byte[] buffer = new byte[10];
                                int bytesRead;
                                while ((bytesRead = await respStream.ReadAsync(buffer, 0, buffer.Length)) > 0)
                                {
                                    result.Write(buffer, 0, bytesRead);
                                }
                            }

                            Assert.Equal(contentLength, result.Length);
                        }

                    clientFinished.SetResult(true);
                    await serverTask;
                });
            }
        }
Esempio n. 24
0
        public async Task GetAsync_ResponseContentRead_CancelUsingTimeoutOrToken_TaskCanceledQuickly(
            bool useTimeout, bool startResponseBody)
        {
            var               cts               = new CancellationTokenSource(); // ignored if useTimeout==true
            TimeSpan          timeout           = useTimeout ? new TimeSpan(0, 0, 1) : Timeout.InfiniteTimeSpan;
            CancellationToken cancellationToken = useTimeout ? CancellationToken.None : cts.Token;

            using (var client = new HttpClient()
            {
                Timeout = timeout
            })
            {
                var triggerResponseWrite = new TaskCompletionSource <bool>(TaskCreationOptions.RunContinuationsAsynchronously);
                var triggerRequestCancel = new TaskCompletionSource <bool>(TaskCreationOptions.RunContinuationsAsynchronously);

                await LoopbackServer.CreateServerAsync(async (server, url) =>
                {
                    Task serverTask = LoopbackServer.AcceptSocketAsync(server, async(socket, stream, reader, writer) =>
                    {
                        while (!string.IsNullOrEmpty(await reader.ReadLineAsync()))
                        {
                            ;
                        }
                        await writer.WriteAsync(
                            "HTTP/1.1 200 OK\r\n" +
                            $"Date: {DateTimeOffset.UtcNow:R}\r\n" +
                            "Content-Length: 16000\r\n" +
                            "\r\n" +
                            (startResponseBody ? "less than 16000 bytes" : ""));

                        await Task.Delay(1000);
                        triggerRequestCancel.SetResult(true); // allow request to cancel
                        await triggerResponseWrite.Task;      // pause until we're released

                        return(null);
                    });

                    var stopwatch = Stopwatch.StartNew();
                    if (PlatformDetection.IsFullFramework)
                    {
                        // .NET Framework throws WebException instead of OperationCanceledException.
                        await Assert.ThrowsAnyAsync <WebException>(async() =>
                        {
                            Task <HttpResponseMessage> getResponse = client.GetAsync(url, HttpCompletionOption.ResponseContentRead, cancellationToken);
                            await triggerRequestCancel.Task;
                            cts.Cancel();
                            await getResponse;
                        });
                    }
                    else
                    {
                        await Assert.ThrowsAnyAsync <OperationCanceledException>(async() =>
                        {
                            Task <HttpResponseMessage> getResponse = client.GetAsync(url, HttpCompletionOption.ResponseContentRead, cancellationToken);
                            await triggerRequestCancel.Task;
                            cts.Cancel();
                            await getResponse;
                        });
                    }
                    stopwatch.Stop();
                    _output.WriteLine("GetAsync() completed at: {0}", stopwatch.Elapsed.ToString());

                    triggerResponseWrite.SetResult(true);
                    Assert.True(stopwatch.Elapsed < new TimeSpan(0, 0, 30), $"Elapsed time {stopwatch.Elapsed} should be less than 30 seconds, was {stopwatch.Elapsed.TotalSeconds}");
                });
            }
        }
Esempio n. 25
0
        public async Task Manual_CertificateSentMatchesCertificateReceived_Success(
            int numberOfRequests,
            bool reuseClient) // validate behavior with and without connection pooling, which impacts client cert usage
        {
            var options = new LoopbackServer.Options {
                UseSsl = true
            };

            using (X509Certificate2 cert = Configuration.Certificates.GetClientCertificate())
            {
                Func <HttpClient> createClient = () =>
                {
                    var handler = new HttpClientHandler()
                    {
                        ServerCertificateCustomValidationCallback = delegate { return(true); }
                    };
                    handler.ClientCertificates.Add(cert);
                    return(new HttpClient(handler));
                };

                Func <HttpClient, Socket, Uri, Task> makeAndValidateRequest = async(client, server, url) =>
                {
                    await TestHelper.WhenAllCompletedOrAnyFailed(
                        client.GetStringAsync(url),
                        LoopbackServer.AcceptSocketAsync(server, async(socket, stream, reader, writer) =>
                    {
                        SslStream sslStream = Assert.IsType <SslStream>(stream);
                        Assert.Equal(cert, sslStream.RemoteCertificate);
                        await LoopbackServer.ReadWriteAcceptedAsync(socket, reader, writer);
                        return(null);
                    }, options));
                };

                await LoopbackServer.CreateServerAsync(async (server, url) =>
                {
                    if (reuseClient)
                    {
                        using (HttpClient client = createClient())
                        {
                            for (int i = 0; i < numberOfRequests; i++)
                            {
                                await makeAndValidateRequest(client, server, url);

                                GC.Collect();
                                GC.WaitForPendingFinalizers();
                            }
                        }
                    }
                    else
                    {
                        for (int i = 0; i < numberOfRequests; i++)
                        {
                            using (HttpClient client = createClient())
                            {
                                await makeAndValidateRequest(client, server, url);
                            }

                            GC.Collect();
                            GC.WaitForPendingFinalizers();
                        }
                    }
                }, options);
            }
        }
Esempio n. 26
0
        public async Task Manual_CertificateSentMatchesCertificateReceived_Success(
            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
            };

            Func <X509Certificate2, HttpClient> createClient = (cert) =>
            {
                HttpClientHandler handler = CreateHttpClientHandler();
                handler.ServerCertificateCustomValidationCallback = delegate { return(true); };
                handler.ClientCertificates.Add(cert);
                Assert.True(handler.ClientCertificates.Contains(cert));
                return(new HttpClient(handler));
            };

            Func <HttpClient, LoopbackServer, Uri, X509Certificate2, Task> makeAndValidateRequest = async(client, server, url, cert) =>
            {
                await TestHelper.WhenAllCompletedOrAnyFailed(
                    client.GetStringAsync(url),
                    server.AcceptConnectionAsync(async connection =>
                {
                    SslStream sslStream = Assert.IsType <SslStream>(connection.Stream);

                    // We can't do Assert.Equal(cert, sslStream.RemoteCertificate) because
                    // on .NET Framework sslStream.RemoteCertificate is always an X509Certificate
                    // object which is not equal to the X509Certificate2 object we use in the tests.
                    // So, we'll just compare a few properties to make sure it's the right certificate.
                    Assert.Equal(cert.Subject, sslStream.RemoteCertificate.Subject);
                    Assert.Equal(cert.Issuer, sslStream.RemoteCertificate.Issuer);

                    await connection.ReadRequestHeaderAndSendResponseAsync(additionalHeaders: "Connection: close\r\n");
                }));
            };

            await LoopbackServer.CreateServerAsync(async (server, url) =>
            {
                using (X509Certificate2 cert = Configuration.Certificates.GetClientCertificate())
                {
                    if (reuseClient)
                    {
                        using (HttpClient client = createClient(cert))
                        {
                            for (int i = 0; i < numberOfRequests; i++)
                            {
                                await makeAndValidateRequest(client, server, url, cert);

                                GC.Collect();
                                GC.WaitForPendingFinalizers();
                            }
                        }
                    }
                    else
                    {
                        for (int i = 0; i < numberOfRequests; i++)
                        {
                            using (HttpClient client = createClient(cert))
                            {
                                await makeAndValidateRequest(client, server, url, cert);
                            }

                            GC.Collect();
                            GC.WaitForPendingFinalizers();
                        }
                    }
                }
            }, options);
        }
Esempio n. 27
0
        public async Task MaxConnectionsPerServer_WaitingConnectionsAreCancelable()
        {
            if (IsWinHttpHandler)
            {
                // Issue #27064:
                // Throws WinHttpException ("The server returned an invalid or unrecognized response")
                // while parsing headers.
                return;
            }
            if (IsNetfxHandler)
            {
                // Throws HttpRequestException wrapping a WebException for the canceled request
                // instead of throwing an OperationCanceledException or a canceled WebException directly.
                return;
            }

            using (HttpClientHandler handler = CreateHttpClientHandler())
                using (HttpClient client = new HttpClient(handler))
                {
                    handler.MaxConnectionsPerServer = 1;
                    client.Timeout = Timeout.InfiniteTimeSpan;

                    await LoopbackServer.CreateServerAsync(async (server, url) =>
                    {
                        var serverAboutToBlock  = new TaskCompletionSource <bool>();
                        var blockServerResponse = new TaskCompletionSource <bool>();

                        Task serverTask1 = LoopbackServer.AcceptSocketAsync(server, async(socket1, stream1, reader1, writer1) =>
                        {
                            while (!string.IsNullOrEmpty(await reader1.ReadLineAsync()))
                            {
                                ;
                            }
                            await writer1.WriteAsync($"HTTP/1.1 200 OK\r\nDate: {DateTimeOffset.UtcNow:R}\r\n");
                            serverAboutToBlock.SetResult(true);
                            await blockServerResponse.Task;
                            await writer1.WriteAsync("Content-Length: 5\r\n\r\nhello");
                            return(null);
                        });

                        Task get1 = client.GetAsync(url);
                        await serverAboutToBlock.Task;

                        var cts   = new CancellationTokenSource();
                        Task get2 = ValidateClientCancellationAsync(() => client.GetAsync(url, cts.Token));
                        Task get3 = ValidateClientCancellationAsync(() => client.GetAsync(url, cts.Token));

                        Task get4 = client.GetAsync(url);

                        cts.Cancel();
                        await get2;
                        await get3;

                        blockServerResponse.SetResult(true);
                        await new[] { get1, serverTask1 }.WhenAllOrAnyFailed();

                        Task serverTask4 = LoopbackServer.AcceptSocketAsync(server, async(socket2, stream2, reader2, writer2) =>
                        {
                            while (!string.IsNullOrEmpty(await reader2.ReadLineAsync()))
                            {
                                ;
                            }
                            await writer2.WriteAsync($"HTTP/1.1 200 OK\r\nDate: {DateTimeOffset.UtcNow:R}\r\nContent-Length: 0\r\n\r\n");
                            return(null);
                        });

                        await new[] { get4, serverTask4 }.WhenAllOrAnyFailed();
                    });
                }
        }