Skip to content

Commit

Permalink
Delegate name resolution to proxy in DefaultHttpClient (#6761)
Browse files Browse the repository at this point in the history
When using a proxy, the destination address should be passed to that proxy unresolved, letting the proxy decide how to resolve it. This can be relevant if, for example, DNS for the local host is restricted.
The normal netty resolver infrastructure has some benefits (e.g. it's asynchronous), but when proxies are used, we don't need those features, because we can forward the unresolved name anyway.
This patch does not have a config property to revert to the old behavior, because I can't think of a reasonable purpose in doing that.

There are two potential downsides to the new behavior:
- Someone might want to request from a host that resolves differently (or not at all) on the proxy she uses. I'd be very surprised if anyone does this.
- There is a potential privacy impact – the proxy can now see the hostname, not just the IP. However the hostname is almost always also available through other means (SNI, the Host header).

There are no tests in this patch. A test would require setting up a HTTP proxy.

Fixes #6617
  • Loading branch information
yawkat committed Jan 21, 2022
1 parent a4f34e5 commit 59c59d6
Showing 1 changed file with 12 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.handler.timeout.IdleStateHandler;
import io.netty.handler.timeout.ReadTimeoutHandler;
import io.netty.resolver.NoopAddressResolverGroup;
import io.netty.util.Attribute;
import io.netty.util.AttributeKey;
import io.netty.util.CharsetUtil;
Expand Down Expand Up @@ -382,6 +383,7 @@ public DefaultHttpClient(@Nullable LoadBalancer loadBalancer,
@Override
protected ChannelPool newPool(RequestKey key) {
Bootstrap newBootstrap = bootstrap.clone(group);
initBootstrapForProxy(newBootstrap, key.isSecure(), key.getHost(), key.getPort());
newBootstrap.remoteAddress(key.getRemoteAddress());

AbstractChannelPoolHandler channelPoolHandler = newPoolHandler(key);
Expand All @@ -403,6 +405,7 @@ protected ChannelPool newPool(RequestKey key) {
@Override
protected ChannelPool newPool(RequestKey key) {
Bootstrap newBootstrap = bootstrap.clone(group);
initBootstrapForProxy(newBootstrap, key.isSecure(), key.getHost(), key.getPort());
newBootstrap.remoteAddress(key.getRemoteAddress());

AbstractChannelPoolHandler channelPoolHandler = newPoolHandler(key);
Expand Down Expand Up @@ -885,6 +888,7 @@ private <T> Flux<T> connectWebSocket(URI uri, MutableHttpRequest<?> request, Cla
}

bootstrap.remoteAddress(requestKey.getHost(), requestKey.getPort());
initBootstrapForProxy(bootstrap, sslContext != null, requestKey.getHost(), requestKey.getPort());
bootstrap.handler(new HttpClientInitializer(
sslContext,
requestKey.getHost(),
Expand Down Expand Up @@ -1404,6 +1408,13 @@ protected Object getLoadBalancerDiscriminator() {
return null;
}

private void initBootstrapForProxy(Bootstrap bootstrap, boolean ssl, String host, int port) {
Proxy proxy = configuration.resolveProxy(ssl, host, port);
if (proxy.type() != Type.DIRECT) {
bootstrap.resolver(NoopAddressResolverGroup.INSTANCE);
}
}

/**
* Creates an initial connection to the given remote host.
*
Expand Down Expand Up @@ -1445,6 +1456,7 @@ protected ChannelFuture doConnect(
boolean isStream,
Consumer<ChannelHandlerContext> contextConsumer) {
Bootstrap localBootstrap = this.bootstrap.clone();
initBootstrapForProxy(localBootstrap, sslCtx != null, host, port);
String acceptHeader = request.getHeaders().get(io.micronaut.http.HttpHeaders.ACCEPT);
localBootstrap.handler(new HttpClientInitializer(
sslCtx,
Expand Down

0 comments on commit 59c59d6

Please sign in to comment.