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;
}
}
}
+ [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]
[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"