public async Task SendAsync_HttpRequestMsgResponseHeadersRead_StatusCodeOK(Configuration.Http.RemoteServer remoteServer) { // Sync API supported only up to HTTP/1.1 if (!TestAsync && remoteServer.HttpVersion.Major >= 2) { return; } HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, remoteServer.EchoUri) { Version = remoteServer.HttpVersion }; using (HttpClient client = CreateHttpClientForRemoteServer(remoteServer)) { using (HttpResponseMessage response = await client.SendAsync(TestAsync, request, HttpCompletionOption.ResponseHeadersRead)) { string responseContent = await response.Content.ReadAsStringAsync(); _output.WriteLine(responseContent); TestHelper.VerifyResponseBody( responseContent, response.Content.Headers.ContentMD5, false, null); } } }
public async Task PostNonRewindableContentUsingAuth_PreAuthenticate_Success(Configuration.Http.RemoteServer remoteServer) { HttpContent content = new StreamContent(new CustomContent.CustomStream(Encoding.UTF8.GetBytes(ExpectedContent), false)); var credential = new NetworkCredential(UserName, Password); await PostUsingAuthHelper(remoteServer, ExpectedContent, content, credential, preAuthenticate : true); }
public async Task DefaultHeaders_SetCredentials_ClearedOnRedirect(Configuration.Http.RemoteServer remoteServer, int statusCode) { if (statusCode == 308 && (IsWinHttpHandler && PlatformDetection.WindowsVersion < 10)) { // 308 redirects are not supported on old versions of WinHttp, or on .NET Framework. return; } HttpClientHandler handler = CreateHttpClientHandler(); using (HttpClient client = CreateHttpClientForRemoteServer(remoteServer, handler)) { string credentialString = _credential.UserName + ":" + _credential.Password; client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", credentialString); Uri uri = remoteServer.RedirectUriForDestinationUri( statusCode: statusCode, destinationUri: remoteServer.EchoUri, hops: 1); _output.WriteLine("Uri: {0}", uri); using (HttpResponseMessage response = await client.GetAsync(uri)) { string responseText = await response.Content.ReadAsStringAsync(); _output.WriteLine(responseText); Assert.False(TestHelper.JsonMessageContainsKey(responseText, "Authorization")); } } }
public async Task GetAsync_LargeRequestHeader_HeadersAndValuesSent(Configuration.Http.RemoteServer remoteServer, Uri uri) { // Unfortunately, our remote servers seem to have pretty strict limits (around 16K?) // on the total size of the request header. // TODO: Figure out how to reconfigure remote endpoints to allow larger request headers, // and then increase the limits in this test. string headerValue = new string('a', 2048); const int headerCount = 6; using (HttpClient client = CreateHttpClientForRemoteServer(remoteServer)) { for (int i = 0; i < headerCount; i++) { client.DefaultRequestHeaders.Add($"Header-{i}", headerValue); } using (HttpResponseMessage httpResponse = await client.GetAsync(uri)) { Assert.Equal(HttpStatusCode.OK, httpResponse.StatusCode); string responseText = await httpResponse.Content.ReadAsStringAsync(); for (int i = 0; i < headerCount; i++) { Assert.True(TestHelper.JsonMessageContainsKeyValue(responseText, $"Header-{i}", headerValue)); } } } }
public async Task GetAsync_SetAutomaticDecompression_ContentDecompressed(Configuration.Http.RemoteServer remoteServer, Uri uri) { // Sync API supported only up to HTTP/1.1 if (!TestAsync && remoteServer.HttpVersion.Major >= 2) { return; } HttpClientHandler handler = CreateHttpClientHandler(); handler.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate; using (HttpClient client = CreateHttpClientForRemoteServer(remoteServer, handler)) { using (HttpResponseMessage response = await client.SendAsync(TestAsync, CreateRequest(HttpMethod.Get, uri, remoteServer.HttpVersion))) { Assert.Equal(HttpStatusCode.OK, response.StatusCode); string responseContent = await response.Content.ReadAsStringAsync(); _output.WriteLine(responseContent); TestHelper.VerifyResponseBody( responseContent, response.Content.Headers.ContentMD5, false, null); } } }
public async Task ReadAsStreamAsync_Cancel_TaskIsCanceled(Configuration.Http.RemoteServer remoteServer) { var cts = new CancellationTokenSource(); using (HttpClient client = CreateHttpClientForRemoteServer(remoteServer)) using (HttpResponseMessage response = await client.GetAsync(remoteServer.EchoUri, HttpCompletionOption.ResponseHeadersRead)) using (Stream stream = await response.Content.ReadAsStreamAsync()) { var buffer = new byte[2048]; Task task = stream.ReadAsync(buffer, 0, buffer.Length, cts.Token); cts.Cancel(); // Verify that the task completed. Assert.True(((IAsyncResult)task).AsyncWaitHandle.WaitOne(new TimeSpan(0, 5, 0))); Assert.True(task.IsCompleted, "Task was not yet completed"); if (task.IsFaulted) { // Propagate exception for debugging task.GetAwaiter().GetResult(); } Assert.True( task.Status == TaskStatus.RanToCompletion || task.Status == TaskStatus.Canceled); } }
public async Task GetStreamAsync_ReadZeroBytes_Success(Configuration.Http.RemoteServer remoteServer) { using (HttpClient client = CreateHttpClientForRemoteServer(remoteServer)) using (Stream stream = await client.GetStreamAsync(remoteServer.EchoUri)) { Assert.Equal(0, stream.Read(new byte[1], 0, 0)); Assert.Equal(0, stream.Read(new Span <byte>(new byte[1], 0, 0))); Assert.Equal(0, await stream.ReadAsync(new byte[1], 0, 0)); } }
private async Task PostAsync_Redirect_LargePayload_Helper(Configuration.Http.RemoteServer remoteServer, int statusCode, bool expectRedirectToPost) { using (var fs = new FileStream( Path.Combine(Path.GetTempPath(), Path.GetTempFileName()), FileMode.Create, FileAccess.ReadWrite, FileShare.None, 0x1000, FileOptions.DeleteOnClose)) { string contentString = string.Join("", Enumerable.Repeat("Content", 100000)); byte[] contentBytes = Encoding.UTF32.GetBytes(contentString); fs.Write(contentBytes, 0, contentBytes.Length); fs.Flush(flushToDisk: true); fs.Position = 0; Uri redirectUri = remoteServer.RedirectUriForDestinationUri( statusCode: statusCode, destinationUri: remoteServer.VerifyUploadUri, hops: 1); var content = new StreamContent(fs); // Compute MD5 of request body data. This will be verified by the server when it receives the request. if (PlatformDetection.IsBrowser) { // [ActiveIssue("https://github.com/dotnet/runtime/issues/37669", TestPlatforms.Browser)] content.Headers.Add("Content-MD5-Skip", "browser"); } else { content.Headers.ContentMD5 = TestHelper.ComputeMD5Hash(contentBytes); } using (HttpClient client = CreateHttpClientForRemoteServer(remoteServer)) using (HttpResponseMessage response = await client.PostAsync(redirectUri, content)) { try { Assert.Equal(HttpStatusCode.OK, response.StatusCode); } catch { _output.WriteLine($"{(int)response.StatusCode} {response.ReasonPhrase}"); throw; } if (expectRedirectToPost) { IEnumerable <string> headerValue = response.Headers.GetValues("X-HttpRequest-Method"); Assert.Equal("POST", headerValue.First()); } } } }
public async Task PostAsync_CallMethod_StreamContent(Configuration.Http.RemoteServer remoteServer, HttpContent content, byte[] expectedData) { using (HttpClient client = CreateHttpClientForRemoteServer(remoteServer)) { content.Headers.ContentMD5 = TestHelper.ComputeMD5Hash(expectedData); using (HttpResponseMessage response = await client.PostAsync(remoteServer.VerifyUploadUri, content)) { Assert.Equal(HttpStatusCode.OK, response.StatusCode); } } }
public async Task PostAsync_RedirectWith307_LargePayload(Configuration.Http.RemoteServer remoteServer) { if (remoteServer.HttpVersion == new Version(2, 0)) { // This is occasionally timing out in CI with SocketsHttpHandler and HTTP2, particularly on Linux // Likely this is just a very slow test and not a product issue, so just increasing the timeout may be the right fix. // Disable until we can investigate further. return; } await PostAsync_Redirect_LargePayload_Helper(remoteServer, 307, true); }
public async Task PostAsync_EmptyContent_ContentTypeHeaderNotSent(Configuration.Http.RemoteServer remoteServer) { using (HttpClient client = CreateHttpClientForRemoteServer(remoteServer)) using (HttpResponseMessage response = await client.PostAsync(remoteServer.EchoUri, null)) { string responseContent = await response.Content.ReadAsStringAsync(); bool sentContentType = TestHelper.JsonMessageContainsKey(responseContent, "Content-Type"); Assert.False(sentContentType); } }
public async Task SendAsync_MultipleRequestsReusingSameClient_Success(Configuration.Http.RemoteServer remoteServer) { using (HttpClient client = CreateHttpClientForRemoteServer(remoteServer)) { for (int i = 0; i < 3; i++) { using (HttpResponseMessage response = await client.GetAsync(remoteServer.EchoUri)) { Assert.Equal(HttpStatusCode.OK, response.StatusCode); } } } }
public async Task PostNonRewindableContentUsingAuth_PreAuthenticate_Success(Configuration.Http.RemoteServer remoteServer) { // Sync API supported only up to HTTP/1.1 if (!TestAsync && remoteServer.HttpVersion.Major >= 2) { return; } HttpContent content = new StreamContent(new CustomContent.CustomStream(Encoding.UTF8.GetBytes(ExpectedContent), false)); var credential = new NetworkCredential(UserName, Password); await PostUsingAuthHelper(remoteServer, ExpectedContent, content, credential, preAuthenticate : true); }
public async Task GetAsync_ServerNeedsAuthAndSetCredential_StatusCodeOK(Configuration.Http.RemoteServer remoteServer) { HttpClientHandler handler = CreateHttpClientHandler(); handler.Credentials = _credential; using (HttpClient client = CreateHttpClientForRemoteServer(remoteServer, handler)) { Uri uri = remoteServer.BasicAuthUriForCreds(userName: Username, password: Password); using (HttpResponseMessage response = await client.GetAsync(uri)) { Assert.Equal(HttpStatusCode.OK, response.StatusCode); } } }
public async Task PostAsync_CallMethod_UnicodeStringContent(Configuration.Http.RemoteServer remoteServer) { using (HttpClient client = CreateHttpClientForRemoteServer(remoteServer)) { string data = "\ub4f1\uffc7\u4e82\u67ab4\uc6d4\ud1a0\uc694\uc77c\uffda3\u3155\uc218\uffdb"; var content = new StringContent(data, Encoding.UTF8); content.Headers.ContentMD5 = TestHelper.ComputeMD5Hash(data); using (HttpResponseMessage response = await client.PostAsync(remoteServer.VerifyUploadUri, content)) { Assert.Equal(HttpStatusCode.OK, response.StatusCode); } } }
private async Task PostUsingAuthHelper( Configuration.Http.RemoteServer remoteServer, string requestBody, HttpContent requestContent, NetworkCredential credential, bool preAuthenticate) { Uri serverUri = remoteServer.BasicAuthUriForCreds(UserName, Password); HttpClientHandler handler = CreateHttpClientHandler(); handler.PreAuthenticate = preAuthenticate; handler.Credentials = credential; using (HttpClient client = CreateHttpClientForRemoteServer(remoteServer, handler)) { // Send HEAD request to help bypass the 401 auth challenge for the latter POST assuming // that the authentication will be cached and re-used later when PreAuthenticate is true. var request = new HttpRequestMessage(HttpMethod.Head, serverUri) { Version = remoteServer.HttpVersion }; using (HttpResponseMessage response = await client.SendAsync(TestAsync, request)) { Assert.Equal(HttpStatusCode.OK, response.StatusCode); } // Now send POST request. request = new HttpRequestMessage(HttpMethod.Post, serverUri) { Version = remoteServer.HttpVersion }; request.Content = requestContent; requestContent.Headers.ContentLength = null; request.Headers.TransferEncodingChunked = true; using (HttpResponseMessage response = await client.SendAsync(TestAsync, request)) { Assert.Equal(HttpStatusCode.OK, response.StatusCode); string responseContent = await response.Content.ReadAsStringAsync(); _output.WriteLine(responseContent); TestHelper.VerifyResponseBody( responseContent, response.Content.Headers.ContentMD5, true, requestBody); } } }
public async Task PostLargeContentUsingContentLengthSemantics_Success(Configuration.Http.RemoteServer remoteServer, int contentLength) { var rand = new Random(42); var sb = new StringBuilder(contentLength); for (int i = 0; i < contentLength; i++) { sb.Append((char)(rand.Next(0, 26) + 'a')); } string content = sb.ToString(); await PostHelper(remoteServer, content, new StringContent(content), useContentLengthUpload : true, useChunkedEncodingUpload : false); }
public async Task GetAsync_SetAutomaticDecompression_HeadersRemoved(Configuration.Http.RemoteServer remoteServer, Uri uri) { HttpClientHandler handler = CreateHttpClientHandler(); handler.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate; using (HttpClient client = CreateHttpClientForRemoteServer(remoteServer, handler)) using (HttpResponseMessage response = await client.GetAsync(uri, HttpCompletionOption.ResponseHeadersRead)) { Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.False(response.Content.Headers.Contains("Content-Encoding"), "Content-Encoding unexpectedly found"); Assert.False(response.Content.Headers.Contains("Content-Length"), "Content-Length unexpectedly found"); } }
public async Task PostRewindableContentUsingAuth_NoPreAuthenticate_Success(Configuration.Http.RemoteServer remoteServer) { if (remoteServer.HttpVersion == new Version(2, 0)) { // This is occasionally timing out in CI with SocketsHttpHandler and HTTP2, particularly on Linux // Likely this is just a very slow test and not a product issue, so just increasing the timeout may be the right fix. // Disable until we can investigate further. return; } HttpContent content = new StreamContent(new CustomContent.CustomStream(Encoding.UTF8.GetBytes(ExpectedContent), true)); var credential = new NetworkCredential(UserName, Password); await PostUsingAuthHelper(remoteServer, ExpectedContent, content, credential, false); }
public async Task SendAsync_SimpleGet_Success(Configuration.Http.RemoteServer remoteServer) { using (HttpClient client = CreateHttpClientForRemoteServer(remoteServer)) using (HttpResponseMessage response = await client.GetAsync(remoteServer.EchoUri)) { string responseContent = await response.Content.ReadAsStringAsync(); _output.WriteLine(responseContent); TestHelper.VerifyResponseBody( responseContent, response.Content.Headers.ContentMD5, false, null); } }
protected HttpClient CreateHttpClientForRemoteServer(Configuration.Http.RemoteServer remoteServer, HttpClientHandler httpClientHandler) { HttpMessageHandler wrappedHandler = httpClientHandler; // ActiveIssue #39293: WinHttpHandler will downgrade to 1.1 if you set Transfer-Encoding: chunked. // So, skip this verification if we're not using SocketsHttpHandler. if (PlatformDetection.SupportsAlpn && IsSocketsHttpHandler(httpClientHandler)) { wrappedHandler = new VersionCheckerHttpHandler(httpClientHandler, remoteServer.HttpVersion); } var client = new HttpClient(wrappedHandler); SetDefaultRequestVersion(client, remoteServer.HttpVersion); return(client); }
public async Task GetAsync_RequestHeadersAddCustomHeaders_HeaderAndValueSent(Configuration.Http.RemoteServer remoteServer, string name, string value, Uri uri) { using (HttpClient client = CreateHttpClientForRemoteServer(remoteServer)) { _output.WriteLine($"name={name}, value={value}"); client.DefaultRequestHeaders.Add(name, value); using (HttpResponseMessage httpResponse = await client.GetAsync(uri)) { Assert.Equal(HttpStatusCode.OK, httpResponse.StatusCode); string responseText = await httpResponse.Content.ReadAsStringAsync(); _output.WriteLine(responseText); Assert.True(TestHelper.JsonMessageContainsKeyValue(responseText, name, value)); } } }
public async Task PostAsync_ReuseRequestContent_Success(Configuration.Http.RemoteServer remoteServer) { const string ContentString = "This is the content string."; using (HttpClient client = CreateHttpClientForRemoteServer(remoteServer)) { var content = new StringContent(ContentString); for (int i = 0; i < 2; i++) { using (HttpResponseMessage response = await client.PostAsync(remoteServer.EchoUri, content)) { Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.Contains(ContentString, await response.Content.ReadAsStringAsync()); } } } }
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)) { bool callbackCalled = false; handler.CheckCertificateRevocationList = checkRevocation; handler.ServerCertificateCustomValidationCallback = (request, cert, chain, errors) => { callbackCalled = true; Assert.NotNull(request); X509ChainStatusFlags flags = chain.ChainStatus.Aggregate(X509ChainStatusFlags.NoError, (cur, status) => cur | status.Status); bool ignoreErrors = // https://github.com/dotnet/corefx/issues/21922#issuecomment-315555237 RuntimeInformation.IsOSPlatform(OSPlatform.OSX) && checkRevocation && errors == SslPolicyErrors.RemoteCertificateChainErrors && flags == X509ChainStatusFlags.RevocationStatusUnknown; Assert.True(ignoreErrors || errors == SslPolicyErrors.None, $"Expected {SslPolicyErrors.None}, got {errors} with chain status {flags}"); Assert.True(chain.ChainElements.Count > 0); Assert.NotEmpty(cert.Subject); // UWP always uses CheckCertificateRevocationList=true regardless of setting the property and // the getter always returns true. So, for this next Assert, it is better to get the property // value back from the handler instead of using the parameter value of the test. Assert.Equal( handler.CheckCertificateRevocationList ? X509RevocationMode.Online : X509RevocationMode.NoCheck, chain.ChainPolicy.RevocationMode); return(true); }; using (HttpResponseMessage response = await client.GetAsync(url)) { Assert.Equal(HttpStatusCode.OK, response.StatusCode); } Assert.True(callbackCalled); } }
private async Task PostHelper( Configuration.Http.RemoteServer remoteServer, string requestBody, HttpContent requestContent, bool useContentLengthUpload, bool useChunkedEncodingUpload) { using (HttpClient client = CreateHttpClientForRemoteServer(remoteServer)) { if (requestContent != null) { if (useContentLengthUpload) { // Ensure that Content-Length is populated (see https://github.com/dotnet/runtime/issues/25086) requestContent.Headers.ContentLength = requestContent.Headers.ContentLength; } else { requestContent.Headers.ContentLength = null; } // Compute MD5 of request body data. This will be verified by the server when it // receives the request. if (PlatformDetection.IsBrowser) { // [ActiveIssue("https://github.com/dotnet/runtime/issues/37669", TestPlatforms.Browser)] requestContent.Headers.Add("Content-MD5-Skip", "browser"); } else { requestContent.Headers.ContentMD5 = TestHelper.ComputeMD5Hash(requestBody); } } if (useChunkedEncodingUpload) { client.DefaultRequestHeaders.TransferEncodingChunked = true; } using (HttpResponseMessage response = await client.PostAsync(remoteServer.VerifyUploadUri, requestContent)) { Assert.Equal(HttpStatusCode.OK, response.StatusCode); } } }
protected HttpClient CreateHttpClientForRemoteServer(Configuration.Http.RemoteServer remoteServer, HttpMessageHandler httpClientHandler) { HttpMessageHandler wrappedHandler = httpClientHandler; // WinHttpHandler will downgrade to 1.1 if you set Transfer-Encoding: chunked. // So, skip this verification if we're not using SocketsHttpHandler. if (PlatformDetection.SupportsAlpn && !IsWinHttpHandler) { wrappedHandler = new VersionCheckerHttpHandler(httpClientHandler, remoteServer.HttpVersion); } return(new HttpClient(wrappedHandler) { #if !NETFRAMEWORK DefaultRequestVersion = remoteServer.HttpVersion #endif }); }
public async Task PostAsync_Redirect_ResultingGetFormattedCorrectly(Configuration.Http.RemoteServer remoteServer) { const string ContentString = "This is the content string."; var content = new StringContent(ContentString); Uri redirectUri = remoteServer.RedirectUriForDestinationUri( 302, remoteServer.EchoUri, 1); using (HttpClient client = CreateHttpClientForRemoteServer(remoteServer)) using (HttpResponseMessage response = await client.PostAsync(redirectUri, content)) { Assert.Equal(HttpStatusCode.OK, response.StatusCode); string responseContent = await response.Content.ReadAsStringAsync(); Assert.DoesNotContain(ContentString, responseContent); Assert.DoesNotContain("Content-Length", responseContent); } }
public async Task PostAsync_CallMethod_NullContent(Configuration.Http.RemoteServer remoteServer) { using (HttpClient client = CreateHttpClientForRemoteServer(remoteServer)) { using (HttpResponseMessage response = await client.PostAsync(remoteServer.EchoUri, null)) { Assert.Equal(HttpStatusCode.OK, response.StatusCode); string responseContent = await response.Content.ReadAsStringAsync(); _output.WriteLine(responseContent); TestHelper.VerifyResponseBody( responseContent, response.Content.Headers.ContentMD5, false, string.Empty); } } }
public async Task PostAsync_CallMethod_StreamContent(Configuration.Http.RemoteServer remoteServer, HttpContent content, byte[] expectedData) { using (HttpClient client = CreateHttpClientForRemoteServer(remoteServer)) { if (PlatformDetection.IsBrowser) { // [ActiveIssue("https://github.com/dotnet/runtime/issues/37669", TestPlatforms.Browser)] content.Headers.Add("Content-MD5-Skip", "browser"); } else { content.Headers.ContentMD5 = TestHelper.ComputeMD5Hash(expectedData); } using (HttpResponseMessage response = await client.PostAsync(remoteServer.VerifyUploadUri, content)) { Assert.Equal(HttpStatusCode.OK, response.StatusCode); } } }
public async Task GetAsync_SetAutomaticDecompression_HeadersRemoved(Configuration.Http.RemoteServer remoteServer, Uri uri) { // Sync API supported only up to HTTP/1.1 if (!TestAsync && remoteServer.HttpVersion.Major >= 2) { return; } HttpClientHandler handler = CreateHttpClientHandler(); handler.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate; using (HttpClient client = CreateHttpClientForRemoteServer(remoteServer, handler)) using (HttpResponseMessage response = await client.SendAsync(TestAsync, CreateRequest(HttpMethod.Get, uri, remoteServer.HttpVersion), HttpCompletionOption.ResponseHeadersRead)) { Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.False(response.Content.Headers.Contains("Content-Encoding"), "Content-Encoding unexpectedly found"); Assert.False(response.Content.Headers.Contains("Content-Length"), "Content-Length unexpectedly found"); } }