diff --git a/client/src/main/java/org/asynchttpclient/netty/channel/ChannelManager.java b/client/src/main/java/org/asynchttpclient/netty/channel/ChannelManager.java index 6a5ed05972..c1c6a883d1 100755 --- a/client/src/main/java/org/asynchttpclient/netty/channel/ChannelManager.java +++ b/client/src/main/java/org/asynchttpclient/netty/channel/ChannelManager.java @@ -33,6 +33,7 @@ import io.netty.handler.proxy.Socks5ProxyHandler; import io.netty.handler.ssl.SslHandler; import io.netty.handler.stream.ChunkedWriteHandler; +import io.netty.resolver.AddressResolverGroup; import io.netty.resolver.NameResolver; import io.netty.util.Timer; import io.netty.util.concurrent.*; @@ -392,55 +393,79 @@ public Future getBootstrap(Uri uri, NameResolver nameRes final Promise promise = ImmediateEventExecutor.INSTANCE.newPromise(); - if (uri.isWebSocket() && proxy == null) { - return promise.setSuccess(wsBootstrap); - - } else if (proxy != null && proxy.getProxyType().isSocks()) { - Bootstrap socksBootstrap = httpBootstrap.clone(); - ChannelHandler httpBootstrapHandler = socksBootstrap.config().handler(); - - nameResolver.resolve(proxy.getHost()).addListener((Future whenProxyAddress) -> { - if (whenProxyAddress.isSuccess()) { - socksBootstrap.handler(new ChannelInitializer() { - @Override - public void handlerAdded(ChannelHandlerContext ctx) throws Exception { - httpBootstrapHandler.handlerAdded(ctx); - super.handlerAdded(ctx); - } - - @Override - protected void initChannel(Channel channel) throws Exception { - InetSocketAddress proxyAddress = new InetSocketAddress(whenProxyAddress.get(), proxy.getPort()); - Realm realm = proxy.getRealm(); - String username = realm != null ? realm.getPrincipal() : null; - String password = realm != null ? realm.getPassword() : null; - ProxyHandler socksProxyHandler; - switch (proxy.getProxyType()) { - case SOCKS_V4: - socksProxyHandler = new Socks4ProxyHandler(proxyAddress, username); - break; - - case SOCKS_V5: - socksProxyHandler = new Socks5ProxyHandler(proxyAddress, username, password); - break; - - default: - throw new IllegalArgumentException("Only SOCKS4 and SOCKS5 supported at the moment."); - } - channel.pipeline().addFirst(SOCKS_HANDLER, socksProxyHandler); - } - }); - promise.setSuccess(socksBootstrap); - - } else { - promise.setFailure(whenProxyAddress.cause()); - } - }); + // direct connect + if (proxy == null) { + if (uri.isWebSocket()) { + promise.setSuccess(wsBootstrap); + } else { + promise.setSuccess(httpBootstrap); + } + return promise; + } - } else { + // http proxy + if (proxy.getProxyType().isHttp()) { promise.setSuccess(httpBootstrap); + return promise; } + // socks proxy + Bootstrap bs; + ChannelHandler handler; + if (uri.isWebSocket()) { + bs = wsBootstrap; + handler = wsBootstrap.config().handler(); + } else { + bs = httpBootstrap; + handler = httpBootstrap.config().handler(); + } + + final Bootstrap wrapFinalBs = bs; + final ChannelHandler wrapFinalHandler = handler; + + nameResolver.resolve(proxy.getHost()).addListener((Future whenProxyAddress) -> { + if (!whenProxyAddress.isSuccess()) { + promise.setFailure(whenProxyAddress.cause()); + return; + } + wrapFinalBs.handler(new ChannelInitializer() { + @Override + public void handlerAdded(ChannelHandlerContext ctx) throws Exception { + wrapFinalHandler.handlerAdded(ctx); + super.handlerAdded(ctx); + } + + @Override + protected void initChannel(Channel channel) throws Exception { + InetSocketAddress proxyAddress = new InetSocketAddress(whenProxyAddress.get(), proxy.getPort()); + Realm realm = proxy.getRealm(); + String username = realm != null ? realm.getPrincipal() : null; + String password = realm != null ? realm.getPassword() : null; + ProxyHandler socksProxyHandler; + switch (proxy.getProxyType()) { + case SOCKS_V4: + socksProxyHandler = new Socks4ProxyHandler(proxyAddress, username); + break; + + case SOCKS_V5: + socksProxyHandler = new Socks5ProxyHandler(proxyAddress, username, password); + break; + + default: + throw new IllegalArgumentException("Only SOCKS4 and SOCKS5 supported at the moment."); + } + channel.pipeline().addFirst(SOCKS_HANDLER, socksProxyHandler); + } + }); + if (proxy.getProxyType().isSocks()) { + AddressResolverGroup addressResolverGroup = proxy.getAddressResolverGroup(); + if (addressResolverGroup != null) { + wrapFinalBs.resolver(addressResolverGroup); + } + } + promise.setSuccess(wrapFinalBs); + }); + return promise; } diff --git a/client/src/main/java/org/asynchttpclient/netty/request/NettyRequestSender.java b/client/src/main/java/org/asynchttpclient/netty/request/NettyRequestSender.java index 03255731f7..5e2bf8495a 100755 --- a/client/src/main/java/org/asynchttpclient/netty/request/NettyRequestSender.java +++ b/client/src/main/java/org/asynchttpclient/netty/request/NettyRequestSender.java @@ -37,6 +37,7 @@ import org.asynchttpclient.netty.channel.*; import org.asynchttpclient.netty.timeout.TimeoutsHolder; import org.asynchttpclient.proxy.ProxyServer; +import org.asynchttpclient.proxy.ProxyType; import org.asynchttpclient.resolver.RequestHostnameResolver; import org.asynchttpclient.uri.Uri; import org.asynchttpclient.ws.WebSocketUpgradeHandler; @@ -46,6 +47,7 @@ import java.io.IOException; import java.net.InetSocketAddress; import java.net.SocketAddress; +import java.util.ArrayList; import java.util.List; import static io.netty.handler.codec.http.HttpHeaderNames.EXPECT; @@ -342,7 +344,16 @@ private Future> resolveAddresses(Request request, InetSocketAddress unresolvedRemoteAddress = InetSocketAddress.createUnresolved(proxy.getHost(), port); scheduleRequestTimeout(future, unresolvedRemoteAddress); return RequestHostnameResolver.INSTANCE.resolve(request.getNameResolver(), unresolvedRemoteAddress, asyncHandler); - + } else if (proxy != null && proxy.isResolveDomain() && proxy.getProxyType().isSocks()) { + // resolve domain in socks 5 server + int port = uri.getExplicitPort(); + InetSocketAddress unresolvedRemoteAddress = InetSocketAddress.createUnresolved(uri.getHost(), port); + final Promise> unResolvedPromise = ImmediateEventExecutor.INSTANCE.newPromise(); + List unresolvedLiWrapper = new ArrayList<>(1); + unresolvedLiWrapper.add(unresolvedRemoteAddress); + scheduleRequestTimeout(future, unresolvedRemoteAddress); + unResolvedPromise.trySuccess(unresolvedLiWrapper); + return unResolvedPromise; } else { int port = uri.getExplicitPort(); diff --git a/client/src/main/java/org/asynchttpclient/proxy/ProxyServer.java b/client/src/main/java/org/asynchttpclient/proxy/ProxyServer.java index 13c33590be..3fc38096f7 100644 --- a/client/src/main/java/org/asynchttpclient/proxy/ProxyServer.java +++ b/client/src/main/java/org/asynchttpclient/proxy/ProxyServer.java @@ -16,6 +16,7 @@ */ package org.asynchttpclient.proxy; +import io.netty.resolver.AddressResolverGroup; import org.asynchttpclient.Realm; import java.util.ArrayList; @@ -36,6 +37,8 @@ public class ProxyServer { private final Realm realm; private final List nonProxyHosts; private final ProxyType proxyType; + private AddressResolverGroup addressResolverGroup; + // server can resolve domain in socks 5 public ProxyServer(String host, int port, int securedPort, Realm realm, List nonProxyHosts, ProxyType proxyType) { @@ -47,6 +50,12 @@ public ProxyServer(String host, int port, int securedPort, Realm realm, List nonProxyHosts, + ProxyType proxyType, AddressResolverGroup addressResolverGroup) { + this(host, port, securedPort, realm, nonProxyHosts, proxyType); + this.addressResolverGroup = addressResolverGroup; + } + public String getHost() { return host; } @@ -71,6 +80,14 @@ public ProxyType getProxyType() { return proxyType; } + public AddressResolverGroup getAddressResolverGroup() { + return addressResolverGroup; + } + + public boolean isResolveDomain() { + return addressResolverGroup != null; + } + /** * Checks whether proxy should be used according to nonProxyHosts settings of * it, or we want to go directly to target host. If null proxy is @@ -118,6 +135,7 @@ public static class Builder { private Realm realm; private List nonProxyHosts; private ProxyType proxyType; + private AddressResolverGroup addressResolverGroup; public Builder(String host, int port) { this.host = host; @@ -157,11 +175,16 @@ public Builder setProxyType(ProxyType proxyType) { return this; } + public Builder setAddressResolverGroup(AddressResolverGroup addressResolverGroup) { + this.addressResolverGroup = addressResolverGroup; + return this; + } + public ProxyServer build() { List nonProxyHosts = this.nonProxyHosts != null ? Collections.unmodifiableList(this.nonProxyHosts) : Collections.emptyList(); ProxyType proxyType = this.proxyType != null ? this.proxyType : ProxyType.HTTP; - return new ProxyServer(host, port, securedPort, realm, nonProxyHosts, proxyType); + return new ProxyServer(host, port, securedPort, realm, nonProxyHosts, proxyType, this.addressResolverGroup); } } }