* move remote redirect and decompression tests to HttpClientHandler_RemoteServerTest
Co-authored-by: Geoffrey Kizer <geoffrek@windows.microsoft.com>
// The .NET Foundation licenses this file to you under the MIT license.
using System.Collections.Generic;
-using System.Net.Http.Headers;
using System.Net.Sockets;
using System.Net.Test.Common;
using System.Threading.Tasks;
namespace System.Net.Http.Functional.Tests
{
- using Configuration = System.Net.Test.Common.Configuration;
-
#if WINHTTPHANDLER_TEST
using HttpClientHandler = System.Net.Http.WinHttpClientHandler;
#endif
public abstract class HttpClientHandlerTest_AutoRedirect : HttpClientHandlerTestBase
{
- private const string ExpectedContent = "Test content";
- private const string Username = "testuser";
- private const string Password = "password";
-
- private readonly NetworkCredential _credential = new NetworkCredential(Username, Password);
-
- public static IEnumerable<object[]> RemoteServersAndRedirectStatusCodes()
- {
- foreach (Configuration.Http.RemoteServer remoteServer in Configuration.Http.RemoteServers)
- {
- yield return new object[] { remoteServer, 300 };
- yield return new object[] { remoteServer, 301 };
- yield return new object[] { remoteServer, 302 };
- yield return new object[] { remoteServer, 303 };
- yield return new object[] { remoteServer, 307 };
- yield return new object[] { remoteServer, 308 };
- }
- }
+ public HttpClientHandlerTest_AutoRedirect(ITestOutputHelper output) : base(output) { }
public static IEnumerable<object[]> RedirectStatusCodesOldMethodsNewMethods()
{
yield return new object[] { statusCode, "MYCUSTOMMETHOD", statusCode == 303 ? "GET" : "MYCUSTOMMETHOD" };
}
}
- public HttpClientHandlerTest_AutoRedirect(ITestOutputHelper output) : base(output) { }
-
- [OuterLoop("Uses external servers")]
- [Theory, MemberData(nameof(RemoteServersAndRedirectStatusCodes))]
- public async Task GetAsync_AllowAutoRedirectFalse_RedirectFromHttpToHttp_StatusCodeRedirect(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();
- handler.AllowAutoRedirect = false;
- using (HttpClient client = CreateHttpClientForRemoteServer(remoteServer, handler))
- {
- Uri uri = remoteServer.RedirectUriForDestinationUri(
- statusCode: statusCode,
- destinationUri: remoteServer.EchoUri,
- hops: 1);
- _output.WriteLine("Uri: {0}", uri);
- using (HttpResponseMessage response = await client.GetAsync(uri))
- {
- Assert.Equal(statusCode, (int)response.StatusCode);
- Assert.Equal(uri, response.RequestMessage.RequestUri);
- }
- }
- }
[Theory, MemberData(nameof(RedirectStatusCodesOldMethodsNewMethods))]
public async Task AllowAutoRedirect_True_ValidateNewMethodUsedOnRedirection(
await LoopbackServer.CreateServerAsync(async (origServer, origUrl) =>
{
var request = new HttpRequestMessage(HttpMethod.Post, origUrl) { Version = UseVersion };
- request.Content = new StringContent(ExpectedContent);
+ request.Content = new StringContent("hello world");
request.Headers.TransferEncodingChunked = true;
Task<HttpResponseMessage> getResponseTask = client.SendAsync(TestAsync, request);
}
}
- [OuterLoop("Uses external servers")]
- [Theory, MemberData(nameof(RemoteServersAndRedirectStatusCodes))]
- public async Task GetAsync_AllowAutoRedirectTrue_RedirectFromHttpToHttp_StatusCodeOK(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();
- handler.AllowAutoRedirect = true;
- using (HttpClient client = CreateHttpClientForRemoteServer(remoteServer, handler))
- {
- Uri uri = remoteServer.RedirectUriForDestinationUri(
- statusCode: statusCode,
- destinationUri: remoteServer.EchoUri,
- hops: 1);
- _output.WriteLine("Uri: {0}", uri);
- using (HttpResponseMessage response = await client.GetAsync(uri))
- {
- Assert.Equal(HttpStatusCode.OK, response.StatusCode);
- Assert.Equal(remoteServer.EchoUri, response.RequestMessage.RequestUri);
- }
- }
- }
-
- [OuterLoop("Uses external servers")]
- [Fact]
- public async Task GetAsync_AllowAutoRedirectTrue_RedirectFromHttpToHttps_StatusCodeOK()
- {
- HttpClientHandler handler = CreateHttpClientHandler();
- handler.AllowAutoRedirect = true;
- using (HttpClient client = CreateHttpClient(handler))
- {
- Uri uri = Configuration.Http.RemoteHttp11Server.RedirectUriForDestinationUri(
- statusCode: 302,
- destinationUri: Configuration.Http.RemoteSecureHttp11Server.EchoUri,
- hops: 1);
- _output.WriteLine("Uri: {0}", uri);
- using (HttpResponseMessage response = await client.GetAsync(uri))
- {
- Assert.Equal(HttpStatusCode.OK, response.StatusCode);
- Assert.Equal(Configuration.Http.SecureRemoteEchoServer, response.RequestMessage.RequestUri);
- }
- }
- }
-
- [OuterLoop("Uses external servers")]
- [Fact]
- public async Task GetAsync_AllowAutoRedirectTrue_RedirectFromHttpsToHttp_StatusCodeRedirect()
- {
- HttpClientHandler handler = CreateHttpClientHandler();
- handler.AllowAutoRedirect = true;
- using (HttpClient client = CreateHttpClient(handler))
- {
- Uri uri = Configuration.Http.RemoteSecureHttp11Server.RedirectUriForDestinationUri(
- statusCode: 302,
- destinationUri: Configuration.Http.RemoteHttp11Server.EchoUri,
- hops: 1);
- _output.WriteLine("Uri: {0}", uri);
-
- using (HttpResponseMessage response = await client.GetAsync(uri))
- {
- Assert.Equal(HttpStatusCode.Redirect, response.StatusCode);
- Assert.Equal(uri, response.RequestMessage.RequestUri);
- }
- }
- }
-
[Fact]
public async Task GetAsync_AllowAutoRedirectTrue_RedirectWithoutLocation_ReturnsOriginalResponse()
{
}
}
- [OuterLoop("Uses external servers")]
- [Theory, MemberData(nameof(RemoteServersMemberData))]
- public async Task GetAsync_AllowAutoRedirectTrue_RedirectToUriWithParams_RequestMsgUriSet(Configuration.Http.RemoteServer remoteServer)
- {
- HttpClientHandler handler = CreateHttpClientHandler();
- handler.AllowAutoRedirect = true;
- Uri targetUri = remoteServer.BasicAuthUriForCreds(userName: Username, password: Password);
- using (HttpClient client = CreateHttpClientForRemoteServer(remoteServer, handler))
- {
- Uri uri = remoteServer.RedirectUriForDestinationUri(
- statusCode: 302,
- destinationUri: targetUri,
- hops: 1);
- _output.WriteLine("Uri: {0}", uri);
- using (HttpResponseMessage response = await client.GetAsync(uri))
- {
- Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode);
- Assert.Equal(targetUri, response.RequestMessage.RequestUri);
- }
- }
- }
-
- [OuterLoop("Uses external servers")]
- [Theory]
- [InlineData(3, 2)]
- [InlineData(3, 3)]
- [InlineData(3, 4)]
- public async Task GetAsync_MaxAutomaticRedirectionsNServerHops_ThrowsIfTooMany(int maxHops, int hops)
- {
- if (IsWinHttpHandler && !PlatformDetection.IsWindows10Version1703OrGreater)
- {
- // Skip this test if using WinHttpHandler but on a release prior to Windows 10 Creators Update.
- _output.WriteLine("Skipping test due to Windows 10 version prior to Version 1703.");
- return;
- }
-
- HttpClientHandler handler = CreateHttpClientHandler();
- handler.MaxAutomaticRedirections = maxHops;
- using (HttpClient client = CreateHttpClient(handler))
- {
- Task<HttpResponseMessage> t = client.GetAsync(Configuration.Http.RemoteHttp11Server.RedirectUriForDestinationUri(
- statusCode: 302,
- destinationUri: Configuration.Http.RemoteHttp11Server.EchoUri,
- hops: hops));
-
- if (hops <= maxHops)
- {
- using (HttpResponseMessage response = await t)
- {
- Assert.Equal(HttpStatusCode.OK, response.StatusCode);
- Assert.Equal(Configuration.Http.RemoteEchoServer, response.RequestMessage.RequestUri);
- }
- }
- else
- {
- if (!IsWinHttpHandler)
- {
- using (HttpResponseMessage response = await t)
- {
- Assert.Equal(HttpStatusCode.Redirect, response.StatusCode);
- }
- }
- else
- {
- await Assert.ThrowsAsync<HttpRequestException>(() => t);
- }
- }
- }
- }
-
- [OuterLoop("Uses external servers")]
- [Theory, MemberData(nameof(RemoteServersMemberData))]
- public async Task GetAsync_AllowAutoRedirectTrue_RedirectWithRelativeLocation(Configuration.Http.RemoteServer remoteServer)
- {
- HttpClientHandler handler = CreateHttpClientHandler();
- handler.AllowAutoRedirect = true;
- using (HttpClient client = CreateHttpClientForRemoteServer(remoteServer, handler))
- {
- Uri uri = remoteServer.RedirectUriForDestinationUri(
- statusCode: 302,
- destinationUri: remoteServer.EchoUri,
- hops: 1,
- relative: true);
- _output.WriteLine("Uri: {0}", uri);
-
- using (HttpResponseMessage response = await client.GetAsync(uri))
- {
- Assert.Equal(HttpStatusCode.OK, response.StatusCode);
- Assert.Equal(remoteServer.EchoUri, response.RequestMessage.RequestUri);
- }
- }
- }
-
[Theory]
[InlineData(200)]
[InlineData(201)]
});
}
}
-
- [Theory, MemberData(nameof(RemoteServersMemberData))]
- [OuterLoop("Uses external servers")]
- public async Task GetAsync_CredentialIsNetworkCredentialUriRedirect_StatusCodeUnauthorized(Configuration.Http.RemoteServer remoteServer)
- {
- HttpClientHandler handler = CreateHttpClientHandler();
- handler.Credentials = _credential;
- using (HttpClient client = CreateHttpClientForRemoteServer(remoteServer, handler))
- {
- Uri redirectUri = remoteServer.RedirectUriForCreds(
- statusCode: 302,
- userName: Username,
- password: Password);
- using (HttpResponseMessage unAuthResponse = await client.GetAsync(redirectUri))
- {
- Assert.Equal(HttpStatusCode.Unauthorized, unAuthResponse.StatusCode);
- }
- }
- }
-
- [Theory, MemberData(nameof(RemoteServersMemberData))]
- [OuterLoop("Uses external servers")]
- public async Task HttpClientHandler_CredentialIsNotCredentialCacheAfterRedirect_StatusCodeOK(Configuration.Http.RemoteServer remoteServer)
- {
- HttpClientHandler handler = CreateHttpClientHandler();
- handler.Credentials = _credential;
- using (HttpClient client = CreateHttpClientForRemoteServer(remoteServer, handler))
- {
- Uri redirectUri = remoteServer.RedirectUriForCreds(
- statusCode: 302,
- userName: Username,
- password: Password);
- using (HttpResponseMessage unAuthResponse = await client.GetAsync(redirectUri))
- {
- Assert.Equal(HttpStatusCode.Unauthorized, unAuthResponse.StatusCode);
- }
-
- // Use the same handler to perform get request, authentication should succeed after redirect.
- Uri uri = remoteServer.BasicAuthUriForCreds(userName: Username, password: Password);
- using (HttpResponseMessage authResponse = await client.GetAsync(uri))
- {
- Assert.Equal(HttpStatusCode.OK, authResponse.StatusCode);
- }
- }
- }
-
- [OuterLoop("Uses external servers")]
- [Theory, MemberData(nameof(RemoteServersAndRedirectStatusCodes))]
- public async Task GetAsync_CredentialIsCredentialCacheUriRedirect_StatusCodeOK(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;
- }
-
- Uri uri = remoteServer.BasicAuthUriForCreds(userName: Username, password: Password);
- Uri redirectUri = remoteServer.RedirectUriForCreds(
- statusCode: statusCode,
- userName: Username,
- password: Password);
- _output.WriteLine(uri.AbsoluteUri);
- _output.WriteLine(redirectUri.AbsoluteUri);
- var credentialCache = new CredentialCache();
- credentialCache.Add(uri, "Basic", _credential);
-
- HttpClientHandler handler = CreateHttpClientHandler();
- handler.Credentials = credentialCache;
- using (HttpClient client = CreateHttpClientForRemoteServer(remoteServer, handler))
- {
- using (HttpResponseMessage response = await client.GetAsync(redirectUri))
- {
- Assert.Equal(HttpStatusCode.OK, response.StatusCode);
- Assert.Equal(uri, response.RequestMessage.RequestUri);
- }
- }
- }
-
- [OuterLoop("Uses external servers")]
- [Theory, MemberData(nameof(RemoteServersAndRedirectStatusCodes))]
- 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"));
- }
- }
- }
}
}
namespace System.Net.Http.Functional.Tests
{
- using Configuration = System.Net.Test.Common.Configuration;
-
#if WINHTTPHANDLER_TEST
using HttpClientHandler = System.Net.Http.WinHttpClientHandler;
#endif
#endif
public HttpClientHandler_Decompression_Test(ITestOutputHelper output) : base(output) { }
- public static IEnumerable<object[]> RemoteServersAndCompressionUris()
- {
- foreach (Configuration.Http.RemoteServer remoteServer in Configuration.Http.RemoteServers)
- {
- yield return new object[] { remoteServer, remoteServer.GZipUri };
-
- // Remote deflate endpoint isn't correctly following the deflate protocol.
- //yield return new object[] { remoteServer, remoteServer.DeflateUri };
- }
- }
-
[Theory]
[InlineData("gzip", false)]
[InlineData("gzip", true)]
});
}
- [OuterLoop("Uses external servers")]
- [SkipOnPlatform(TestPlatforms.Browser, "AutomaticDecompression not supported on Browser")]
- [Theory, MemberData(nameof(RemoteServersAndCompressionUris))]
- public async Task GetAsync_SetAutomaticDecompression_ContentDecompressed_GZip(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);
- }
- }
- }
-
- // The remote server endpoint was written to use DeflateStream, which isn't actually a correct
- // implementation of the deflate protocol (the deflate protocol requires the zlib wrapper around
- // deflate). Until we can get that updated (and deal with previous releases still testing it
- // via a DeflateStream-based implementation), we utilize httpbin.org to help validate behavior.
- [OuterLoop("Uses external servers")]
- [Theory]
- [InlineData("http://httpbin.org/deflate", "\"deflated\": true")]
- [InlineData("https://httpbin.org/deflate", "\"deflated\": true")]
- [SkipOnPlatform(TestPlatforms.Browser, "AutomaticDecompression not supported on Browser")]
- public async Task GetAsync_SetAutomaticDecompression_ContentDecompressed_Deflate(string uri, string expectedContent)
- {
- if (IsWinHttpHandler)
- {
- // WinHttpHandler targets netstandard2.0 and still erroneously uses DeflateStream rather than ZlibStream for deflate.
- return;
- }
-
- HttpClientHandler handler = CreateHttpClientHandler();
- handler.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
- using (HttpClient client = CreateHttpClient(handler))
- {
- Assert.Contains(expectedContent, await client.GetStringAsync(uri));
- }
- }
-
- [OuterLoop("Uses external servers")]
- [Theory, MemberData(nameof(RemoteServersAndCompressionUris))]
- [SkipOnPlatform(TestPlatforms.Browser, "AutomaticDecompression not supported on Browser")]
- 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");
- }
- }
-
[Theory]
#if NETCOREAPP
[InlineData(DecompressionMethods.Brotli, "br", "")]
using System.Collections.Generic;
using System.IO;
using System.Linq;
+using System.Net.Http.Headers;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
}
}
+ public static IEnumerable<object[]> RemoteServersAndRedirectStatusCodes()
+ {
+ foreach (Configuration.Http.RemoteServer remoteServer in Configuration.Http.RemoteServers)
+ {
+ yield return new object[] { remoteServer, 300 };
+ yield return new object[] { remoteServer, 301 };
+ yield return new object[] { remoteServer, 302 };
+ yield return new object[] { remoteServer, 303 };
+ yield return new object[] { remoteServer, 307 };
+ yield return new object[] { remoteServer, 308 };
+ }
+ }
+
+ [OuterLoop("Uses external servers")]
+ [Theory, MemberData(nameof(RemoteServersAndRedirectStatusCodes))]
+ public async Task GetAsync_AllowAutoRedirectFalse_RedirectFromHttpToHttp_StatusCodeRedirect(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();
+ handler.AllowAutoRedirect = false;
+ using (HttpClient client = CreateHttpClientForRemoteServer(remoteServer, handler))
+ {
+ Uri uri = remoteServer.RedirectUriForDestinationUri(
+ statusCode: statusCode,
+ destinationUri: remoteServer.EchoUri,
+ hops: 1);
+ _output.WriteLine("Uri: {0}", uri);
+ using (HttpResponseMessage response = await client.GetAsync(uri))
+ {
+ Assert.Equal(statusCode, (int)response.StatusCode);
+ Assert.Equal(uri, response.RequestMessage.RequestUri);
+ }
+ }
+ }
+
+ [OuterLoop("Uses external servers")]
+ [Theory, MemberData(nameof(RemoteServersAndRedirectStatusCodes))]
+ public async Task GetAsync_AllowAutoRedirectTrue_RedirectFromHttpToHttp_StatusCodeOK(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();
+ handler.AllowAutoRedirect = true;
+ using (HttpClient client = CreateHttpClientForRemoteServer(remoteServer, handler))
+ {
+ Uri uri = remoteServer.RedirectUriForDestinationUri(
+ statusCode: statusCode,
+ destinationUri: remoteServer.EchoUri,
+ hops: 1);
+ _output.WriteLine("Uri: {0}", uri);
+ using (HttpResponseMessage response = await client.GetAsync(uri))
+ {
+ Assert.Equal(HttpStatusCode.OK, response.StatusCode);
+ Assert.Equal(remoteServer.EchoUri, response.RequestMessage.RequestUri);
+ }
+ }
+ }
+
+ [OuterLoop("Uses external servers")]
+ [Fact]
+ public async Task GetAsync_AllowAutoRedirectTrue_RedirectFromHttpToHttps_StatusCodeOK()
+ {
+ HttpClientHandler handler = CreateHttpClientHandler();
+ handler.AllowAutoRedirect = true;
+ using (HttpClient client = CreateHttpClient(handler))
+ {
+ Uri uri = Configuration.Http.RemoteHttp11Server.RedirectUriForDestinationUri(
+ statusCode: 302,
+ destinationUri: Configuration.Http.RemoteSecureHttp11Server.EchoUri,
+ hops: 1);
+ _output.WriteLine("Uri: {0}", uri);
+ using (HttpResponseMessage response = await client.GetAsync(uri))
+ {
+ Assert.Equal(HttpStatusCode.OK, response.StatusCode);
+ Assert.Equal(Configuration.Http.SecureRemoteEchoServer, response.RequestMessage.RequestUri);
+ }
+ }
+ }
+
+ [OuterLoop("Uses external servers")]
+ [Fact]
+ public async Task GetAsync_AllowAutoRedirectTrue_RedirectFromHttpsToHttp_StatusCodeRedirect()
+ {
+ HttpClientHandler handler = CreateHttpClientHandler();
+ handler.AllowAutoRedirect = true;
+ using (HttpClient client = CreateHttpClient(handler))
+ {
+ Uri uri = Configuration.Http.RemoteSecureHttp11Server.RedirectUriForDestinationUri(
+ statusCode: 302,
+ destinationUri: Configuration.Http.RemoteHttp11Server.EchoUri,
+ hops: 1);
+ _output.WriteLine("Uri: {0}", uri);
+
+ using (HttpResponseMessage response = await client.GetAsync(uri))
+ {
+ Assert.Equal(HttpStatusCode.Redirect, response.StatusCode);
+ Assert.Equal(uri, response.RequestMessage.RequestUri);
+ }
+ }
+ }
+
+ [OuterLoop("Uses external servers")]
+ [Theory, MemberData(nameof(RemoteServersMemberData))]
+ public async Task GetAsync_AllowAutoRedirectTrue_RedirectToUriWithParams_RequestMsgUriSet(Configuration.Http.RemoteServer remoteServer)
+ {
+ HttpClientHandler handler = CreateHttpClientHandler();
+ handler.AllowAutoRedirect = true;
+ Uri targetUri = remoteServer.BasicAuthUriForCreds(userName: Username, password: Password);
+ using (HttpClient client = CreateHttpClientForRemoteServer(remoteServer, handler))
+ {
+ Uri uri = remoteServer.RedirectUriForDestinationUri(
+ statusCode: 302,
+ destinationUri: targetUri,
+ hops: 1);
+ _output.WriteLine("Uri: {0}", uri);
+ using (HttpResponseMessage response = await client.GetAsync(uri))
+ {
+ Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode);
+ Assert.Equal(targetUri, response.RequestMessage.RequestUri);
+ }
+ }
+ }
+
+ [OuterLoop("Uses external servers")]
+ [Theory]
+ [InlineData(3, 2)]
+ [InlineData(3, 3)]
+ [InlineData(3, 4)]
+ public async Task GetAsync_MaxAutomaticRedirectionsNServerHops_ThrowsIfTooMany(int maxHops, int hops)
+ {
+ if (IsWinHttpHandler && !PlatformDetection.IsWindows10Version1703OrGreater)
+ {
+ // Skip this test if using WinHttpHandler but on a release prior to Windows 10 Creators Update.
+ _output.WriteLine("Skipping test due to Windows 10 version prior to Version 1703.");
+ return;
+ }
+
+ HttpClientHandler handler = CreateHttpClientHandler();
+ handler.MaxAutomaticRedirections = maxHops;
+ using (HttpClient client = CreateHttpClient(handler))
+ {
+ Task<HttpResponseMessage> t = client.GetAsync(Configuration.Http.RemoteHttp11Server.RedirectUriForDestinationUri(
+ statusCode: 302,
+ destinationUri: Configuration.Http.RemoteHttp11Server.EchoUri,
+ hops: hops));
+
+ if (hops <= maxHops)
+ {
+ using (HttpResponseMessage response = await t)
+ {
+ Assert.Equal(HttpStatusCode.OK, response.StatusCode);
+ Assert.Equal(Configuration.Http.RemoteEchoServer, response.RequestMessage.RequestUri);
+ }
+ }
+ else
+ {
+ if (!IsWinHttpHandler)
+ {
+ using (HttpResponseMessage response = await t)
+ {
+ Assert.Equal(HttpStatusCode.Redirect, response.StatusCode);
+ }
+ }
+ else
+ {
+ await Assert.ThrowsAsync<HttpRequestException>(() => t);
+ }
+ }
+ }
+ }
+
+ [OuterLoop("Uses external servers")]
+ [Theory, MemberData(nameof(RemoteServersMemberData))]
+ public async Task GetAsync_AllowAutoRedirectTrue_RedirectWithRelativeLocation(Configuration.Http.RemoteServer remoteServer)
+ {
+ HttpClientHandler handler = CreateHttpClientHandler();
+ handler.AllowAutoRedirect = true;
+ using (HttpClient client = CreateHttpClientForRemoteServer(remoteServer, handler))
+ {
+ Uri uri = remoteServer.RedirectUriForDestinationUri(
+ statusCode: 302,
+ destinationUri: remoteServer.EchoUri,
+ hops: 1,
+ relative: true);
+ _output.WriteLine("Uri: {0}", uri);
+
+ using (HttpResponseMessage response = await client.GetAsync(uri))
+ {
+ Assert.Equal(HttpStatusCode.OK, response.StatusCode);
+ Assert.Equal(remoteServer.EchoUri, response.RequestMessage.RequestUri);
+ }
+ }
+ }
+
+ [Theory, MemberData(nameof(RemoteServersMemberData))]
+ [OuterLoop("Uses external servers")]
+ public async Task GetAsync_CredentialIsNetworkCredentialUriRedirect_StatusCodeUnauthorized(Configuration.Http.RemoteServer remoteServer)
+ {
+ HttpClientHandler handler = CreateHttpClientHandler();
+ handler.Credentials = _credential;
+ using (HttpClient client = CreateHttpClientForRemoteServer(remoteServer, handler))
+ {
+ Uri redirectUri = remoteServer.RedirectUriForCreds(
+ statusCode: 302,
+ userName: Username,
+ password: Password);
+ using (HttpResponseMessage unAuthResponse = await client.GetAsync(redirectUri))
+ {
+ Assert.Equal(HttpStatusCode.Unauthorized, unAuthResponse.StatusCode);
+ }
+ }
+ }
+
+ [Theory, MemberData(nameof(RemoteServersMemberData))]
+ [OuterLoop("Uses external servers")]
+ public async Task HttpClientHandler_CredentialIsNotCredentialCacheAfterRedirect_StatusCodeOK(Configuration.Http.RemoteServer remoteServer)
+ {
+ HttpClientHandler handler = CreateHttpClientHandler();
+ handler.Credentials = _credential;
+ using (HttpClient client = CreateHttpClientForRemoteServer(remoteServer, handler))
+ {
+ Uri redirectUri = remoteServer.RedirectUriForCreds(
+ statusCode: 302,
+ userName: Username,
+ password: Password);
+ using (HttpResponseMessage unAuthResponse = await client.GetAsync(redirectUri))
+ {
+ Assert.Equal(HttpStatusCode.Unauthorized, unAuthResponse.StatusCode);
+ }
+
+ // Use the same handler to perform get request, authentication should succeed after redirect.
+ Uri uri = remoteServer.BasicAuthUriForCreds(userName: Username, password: Password);
+ using (HttpResponseMessage authResponse = await client.GetAsync(uri))
+ {
+ Assert.Equal(HttpStatusCode.OK, authResponse.StatusCode);
+ }
+ }
+ }
+
+ [OuterLoop("Uses external servers")]
+ [Theory, MemberData(nameof(RemoteServersAndRedirectStatusCodes))]
+ public async Task GetAsync_CredentialIsCredentialCacheUriRedirect_StatusCodeOK(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;
+ }
+
+ Uri uri = remoteServer.BasicAuthUriForCreds(userName: Username, password: Password);
+ Uri redirectUri = remoteServer.RedirectUriForCreds(
+ statusCode: statusCode,
+ userName: Username,
+ password: Password);
+ _output.WriteLine(uri.AbsoluteUri);
+ _output.WriteLine(redirectUri.AbsoluteUri);
+ var credentialCache = new CredentialCache();
+ credentialCache.Add(uri, "Basic", _credential);
+
+ HttpClientHandler handler = CreateHttpClientHandler();
+ handler.Credentials = credentialCache;
+ using (HttpClient client = CreateHttpClientForRemoteServer(remoteServer, handler))
+ {
+ using (HttpResponseMessage response = await client.GetAsync(redirectUri))
+ {
+ Assert.Equal(HttpStatusCode.OK, response.StatusCode);
+ Assert.Equal(uri, response.RequestMessage.RequestUri);
+ }
+ }
+ }
+
+ [OuterLoop("Uses external servers")]
+ [Theory, MemberData(nameof(RemoteServersAndRedirectStatusCodes))]
+ 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 static IEnumerable<object[]> RemoteServersAndCompressionUris()
+ {
+ foreach (Configuration.Http.RemoteServer remoteServer in Configuration.Http.RemoteServers)
+ {
+ yield return new object[] { remoteServer, remoteServer.GZipUri };
+
+ // Remote deflate endpoint isn't correctly following the deflate protocol.
+ //yield return new object[] { remoteServer, remoteServer.DeflateUri };
+ }
+ }
+
+ [OuterLoop("Uses external servers")]
+ [SkipOnPlatform(TestPlatforms.Browser, "AutomaticDecompression not supported on Browser")]
+ [Theory, MemberData(nameof(RemoteServersAndCompressionUris))]
+ public async Task GetAsync_SetAutomaticDecompression_ContentDecompressed_GZip(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);
+ }
+ }
+ }
+
+ // The remote server endpoint was written to use DeflateStream, which isn't actually a correct
+ // implementation of the deflate protocol (the deflate protocol requires the zlib wrapper around
+ // deflate). Until we can get that updated (and deal with previous releases still testing it
+ // via a DeflateStream-based implementation), we utilize httpbin.org to help validate behavior.
+ [OuterLoop("Uses external servers")]
+ [Theory]
+ [InlineData("http://httpbin.org/deflate", "\"deflated\": true")]
+ [InlineData("https://httpbin.org/deflate", "\"deflated\": true")]
+ [SkipOnPlatform(TestPlatforms.Browser, "AutomaticDecompression not supported on Browser")]
+ public async Task GetAsync_SetAutomaticDecompression_ContentDecompressed_Deflate(string uri, string expectedContent)
+ {
+ if (IsWinHttpHandler)
+ {
+ // WinHttpHandler targets netstandard2.0 and still erroneously uses DeflateStream rather than ZlibStream for deflate.
+ return;
+ }
+
+ HttpClientHandler handler = CreateHttpClientHandler();
+ handler.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
+ using (HttpClient client = CreateHttpClient(handler))
+ {
+ Assert.Contains(expectedContent, await client.GetStringAsync(uri));
+ }
+ }
+
+ [OuterLoop("Uses external servers")]
+ [Theory, MemberData(nameof(RemoteServersAndCompressionUris))]
+ [SkipOnPlatform(TestPlatforms.Browser, "AutomaticDecompression not supported on Browser")]
+ 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");
+ }
+ }
+
[OuterLoop("Uses external servers", typeof(PlatformDetection), nameof(PlatformDetection.LocalEchoServerIsNotAvailable))]
[Theory]
[MemberData(nameof(Http2Servers))]