Skip to content
This repository has been archived by the owner on Jan 23, 2023. It is now read-only.
/ corefx Public archive

Commit

Permalink
Fix proxied ipv6 address request formatting and fix port handling for…
Browse files Browse the repository at this point in the history
… proxied IP address on SocketsHttpHandler (#28740)

* fix proxied ipv6 address request format and fix port handling for ip address

* address feedback

* change naming for test data
  • Loading branch information
Caesar1995 authored Apr 5, 2018
1 parent 72e8ae3 commit 18d685f
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,18 @@ public async Task<HttpResponseMessage> SendAsyncCore(HttpRequestMessage request,
// Proxied requests contain full URL
Debug.Assert(request.RequestUri.Scheme == Uri.UriSchemeHttp);
await WriteBytesAsync(s_httpSchemeAndDelimiter).ConfigureAwait(false);
await WriteAsciiStringAsync(request.RequestUri.IdnHost).ConfigureAwait(false);

// If the hostname is an IPv6 address, uri.IdnHost will return the address without enclosing [].
// In this case, use uri.Host instead, which will correctly enclose with [].
// Note we don't need punycode encoding if it's an IP address, so using uri.Host is fine.
await WriteAsciiStringAsync(request.RequestUri.HostNameType == UriHostNameType.IPv6 ?
request.RequestUri.Host : request.RequestUri.IdnHost).ConfigureAwait(false);

if (!request.RequestUri.IsDefaultPort)
{
await WriteByteAsync((byte)':').ConfigureAwait(false);
await WriteDecimalInt32Async(request.RequestUri.Port).ConfigureAwait(false);
}
}
await WriteStringAsync(request.RequestUri.GetComponents(UriComponents.PathAndQuery | UriComponents.Fragment, UriFormat.UriEscaped)).ConfigureAwait(false);
}
Expand Down
91 changes: 91 additions & 0 deletions src/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ public abstract class HttpClientHandlerTest : HttpClientTestBase
private const string ExpectedContent = "Test content";
private const string Username = "testuser";
private const string Password = "password";
private const string HttpDefaultPort = "80";

private readonly NetworkCredential _credential = new NetworkCredential(Username, Password);

Expand Down Expand Up @@ -498,6 +499,96 @@ await LoopbackServer.CreateClientAndServerAsync(async proxyUri =>
Assert.True(connectionAccepted);
}

[Theory]
[InlineData("1.2.3.4")]
[InlineData("1.2.3.4:8080")]
[InlineData("[::1234]")]
[InlineData("[::1234]:8080")]
public async Task ProxiedIPAddressRequest_NotDefaultPort_CorrectlyFormatted(string host)
{
string uri = "http://" + host;
bool connectionAccepted = false;

await LoopbackServer.CreateClientAndServerAsync(async proxyUri =>
{
using (HttpClientHandler handler = CreateHttpClientHandler())
using (var client = new HttpClient(handler))
{
handler.Proxy = new WebProxy(proxyUri);
try { await client.GetAsync(uri); } catch { }
}
}, server => server.AcceptConnectionAsync(async connection =>
{
connectionAccepted = true;
List<string> headers = await connection.ReadRequestHeaderAndSendResponseAsync();
Assert.Contains($"GET {uri}/ HTTP/1.1", headers);
}));

Assert.True(connectionAccepted);
}

public static IEnumerable<object[]> DestinationHost_MemberData()
{
yield return new object[] { Configuration.Http.Host };
yield return new object[] { "1.2.3.4" };
yield return new object[] { "[::1234]" };
}

[Theory]
[OuterLoop] // Test uses azure endpoint.
[MemberData(nameof(DestinationHost_MemberData))]
public async Task ProxiedRequest_DefaultPort_PortStrippedOffInUri(string host)
{
string addressUri = $"http://{host}:{HttpDefaultPort}/";
string expectedAddressUri = $"http://{host}/";
bool connectionAccepted = false;

await LoopbackServer.CreateClientAndServerAsync(async proxyUri =>
{
using (HttpClientHandler handler = CreateHttpClientHandler())
using (var client = new HttpClient(handler))
{
handler.Proxy = new WebProxy(proxyUri);
try { await client.GetAsync(addressUri); } catch { }
}
}, server => server.AcceptConnectionAsync(async connection =>
{
connectionAccepted = true;
List<string> headers = await connection.ReadRequestHeaderAndSendResponseAsync();
Assert.Contains($"GET {expectedAddressUri} HTTP/1.1", headers);
}));

Assert.True(connectionAccepted);
}

[Fact]
[OuterLoop] // Test uses azure endpoint.
public async Task ProxyTunnelRequest_PortSpecified_NotStrippedOffInUri()
{
// Https proxy request will use CONNECT tunnel, even the default 443 port is specified, it will not be stripped off.
string requestTarget = $"{Configuration.Http.SecureHost}:443";
string addressUri = $"https://{requestTarget}/";
bool connectionAccepted = false;

await LoopbackServer.CreateClientAndServerAsync(async proxyUri =>
{
using (HttpClientHandler handler = CreateHttpClientHandler())
using (var client = new HttpClient(handler))
{
handler.Proxy = new WebProxy(proxyUri);
handler.ServerCertificateCustomValidationCallback = TestHelper.AllowAllCertificates;
try { await client.GetAsync(addressUri); } catch { }
}
}, server => server.AcceptConnectionAsync(async connection =>
{
connectionAccepted = true;
List<string> headers = await connection.ReadRequestHeaderAndSendResponseAsync();
Assert.Contains($"CONNECT {requestTarget} HTTP/1.1", headers);
}));

Assert.True(connectionAccepted);
}

public static IEnumerable<object[]> SecureAndNonSecure_IPBasedUri_MemberData() =>
from address in new[] { IPAddress.Loopback, IPAddress.IPv6Loopback }
from useSsl in new[] { true, false }
Expand Down

0 comments on commit 18d685f

Please sign in to comment.