diff options
author | Stephen Toub <stoub@microsoft.com> | 2017-10-23 22:32:19 +0300 |
---|---|---|
committer | Stephen Toub <stoub@microsoft.com> | 2017-10-25 20:40:03 +0300 |
commit | 5ecea8ff47c03a073a77916a9c7d1d806f8c7ce3 (patch) | |
tree | 92ef3d177468477114e3edf73c9c99d28341ba01 /src | |
parent | ddfab940fcc2d571c2da85250c13e457ab1933a2 (diff) |
Use the Host header for the SSL handshake
Diffstat (limited to 'src')
3 files changed, 83 insertions, 3 deletions
diff --git a/src/System.Net.Http/src/System/Net/Http/Managed/HttpConnectionHandler.cs b/src/System.Net.Http/src/System/Net/Http/Managed/HttpConnectionHandler.cs index c0635480de..6a5a0723cf 100644 --- a/src/System.Net.Http/src/System/Net/Http/Managed/HttpConnectionHandler.cs +++ b/src/System.Net.Http/src/System/Net/Http/Managed/HttpConnectionHandler.cs @@ -91,7 +91,42 @@ namespace System.Net.Http if (HttpUtilities.IsSupportedSecureScheme(uri.Scheme)) { - SslStream sslStream = await EstablishSslConnection(uri.IdnHost, request, stream).ConfigureAwait(false); + // Get the appropriate host name to use for the SSL connection, allowing a host header to override. + string host = request.Headers.Host; + if (host == null) + { + // No host header, use the host from the Uri. + host = uri.IdnHost; + } + else + { + // There is a host header. Use it, but first see if we need to trim off a port. + int colonPos = host.IndexOf(':'); + if (colonPos >= 0) + { + // There is colon, which could either be a port separator or a separator in + // an IPv6 address. See if this is an IPv6 address; if it's not, use everything + // before the colon as the host name, and if it is, use everything before the last + // colon iff the last colon is after the end of the IPv6 address (otherwise it's a + // part of the address). + int ipV6AddressEnd = host.IndexOf(']'); + if (ipV6AddressEnd == -1) + { + host = host.Substring(0, colonPos); + } + else + { + colonPos = host.LastIndexOf(':'); + if (colonPos > ipV6AddressEnd) + { + host = host.Substring(0, colonPos); + } + } + } + } + + // Establish the connection using the parsed host name. + SslStream sslStream = await EstablishSslConnection(host, request, stream).ConfigureAwait(false); stream = sslStream; transportContext = sslStream.TransportContext; } diff --git a/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.cs b/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.cs index 107918623f..3e3993ca53 100644 --- a/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.cs +++ b/src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.cs @@ -285,6 +285,49 @@ namespace System.Net.Http.Functional.Tests } } + [OuterLoop] // TODO: Issue #11345 + [Theory] + [InlineData(false)] + [InlineData(true)] + public async Task SendAsync_GetWithValidHostHeader_Success(bool withPort) + { + var m = new HttpRequestMessage(HttpMethod.Get, Configuration.Http.SecureRemoteEchoServer); + m.Headers.Host = withPort ? Configuration.Http.SecureHost + ":123" : Configuration.Http.SecureHost; + + using (HttpClient client = CreateHttpClient()) + using (HttpResponseMessage response = await client.SendAsync(m)) + { + string responseContent = await response.Content.ReadAsStringAsync(); + _output.WriteLine(responseContent); + TestHelper.VerifyResponseBody( + responseContent, + response.Content.Headers.ContentMD5, + false, + null); + } + } + + [OuterLoop] // TODO: Issue #11345 + [Fact] + public async Task SendAsync_GetWithInvalidHostHeader_ThrowsException() + { + if (PlatformDetection.IsNetCore && !UseManagedHandler) + { + // [ActiveIssue(24862)] + // WinHttpHandler and CurlHandler do not use the Host header to influence the SSL auth. + // .NET Framework and ManagedHandler do. + return; + } + + var m = new HttpRequestMessage(HttpMethod.Get, Configuration.Http.SecureRemoteEchoServer); + m.Headers.Host = "hostheaderthatdoesnotmatch"; + + using (HttpClient client = CreateHttpClient()) + { + await Assert.ThrowsAsync<HttpRequestException>(() => client.SendAsync(m)); + } + } + [ActiveIssue(22158, TargetFrameworkMonikers.Uap)] [OuterLoop] // TODO: Issue #11345 [Fact] diff --git a/src/System.Net.WebSockets.Client/tests/ConnectTest.cs b/src/System.Net.WebSockets.Client/tests/ConnectTest.cs index cde6c660c5..0c5645f000 100644 --- a/src/System.Net.WebSockets.Client/tests/ConnectTest.cs +++ b/src/System.Net.WebSockets.Client/tests/ConnectTest.cs @@ -86,9 +86,11 @@ namespace System.Net.WebSockets.Client.Tests [ActiveIssue(18784, TargetFrameworkMonikers.NetFramework)] [OuterLoop] - [ConditionalTheory(nameof(WebSocketsSupported)), MemberData(nameof(EchoHeadersServers))] - public async Task ConnectAsync_AddHostHeader_Success(Uri server) + [ConditionalTheory(nameof(WebSocketsSupported))] + public async Task ConnectAsync_AddHostHeader_Success() { + Uri server = System.Net.Test.Common.Configuration.WebSockets.RemoteEchoServer; + // Send via the physical address such as "corefx-net.cloudapp.net" // Set the Host header to logical address like "subdomain.corefx-net.cloudapp.net" // Verify the scenario works and the remote server received "Host: subdomain.corefx-net.cloudapp.net" |