Skip to content

Commit 1ab90ab

Browse files
committed
Honor VirtualHost when creating SSLEngines, close AsyncHttpClient#927
1 parent 5b4fc25 commit 1ab90ab

File tree

18 files changed

+188
-339
lines changed

18 files changed

+188
-339
lines changed

api/src/main/java/org/asynchttpclient/channel/pool/ConnectionPoolPartitioning.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,14 @@ public String toString() {
3636
}
3737
}
3838

39-
Object getPartitionKey(Uri uri, ProxyServer proxyServer);
39+
Object getPartitionKey(Uri uri, String virtualHost, ProxyServer proxyServer);
4040

4141
public enum PerHostConnectionPoolPartitioning implements ConnectionPoolPartitioning {
4242

4343
INSTANCE;
4444

45-
public Object getPartitionKey(Uri uri, ProxyServer proxyServer) {
46-
String targetHostBaseUrl = AsyncHttpProviderUtils.getBaseUrl(uri);
45+
public Object getPartitionKey(Uri uri, String virtualHost, ProxyServer proxyServer) {
46+
String targetHostBaseUrl = virtualHost != null ? virtualHost : AsyncHttpProviderUtils.getBaseUrl(uri);
4747
return proxyServer != null ? new ProxyPartitionKey(proxyServer.getUrl(), targetHostBaseUrl) : targetHostBaseUrl;
4848
}
4949
}

api/src/main/java/org/asynchttpclient/util/AsyncHttpProviderUtils.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,19 +47,19 @@ public final static String getBaseUrl(Uri uri) {
4747
}
4848

4949
public final static String getAuthority(Uri uri) {
50-
int port = uri.getPort() != -1 ? uri.getPort() : getDefaultPort(uri);
50+
int port = uri.getPort() != -1 ? uri.getPort() : getExplicitPort(uri);
5151
return uri.getHost() + ":" + port;
5252
}
5353

54-
public final static boolean isSameHostAndProtocol(Uri uri1, Uri uri2) {
55-
return uri1.getScheme().equals(uri2.getScheme()) && uri1.getHost().equals(uri2.getHost()) && getDefaultPort(uri1) == getDefaultPort(uri2);
54+
public final static boolean isSameBase(Uri uri1, Uri uri2) {
55+
return uri1.getScheme().equals(uri2.getScheme()) && uri1.getHost().equals(uri2.getHost()) && getExplicitPort(uri1) == getExplicitPort(uri2);
5656
}
5757

5858
public static final int getSchemeDefaultPort(String scheme) {
5959
return scheme.equals("http") || scheme.equals("ws") ? 80 : 443;
6060
}
6161

62-
public static final int getDefaultPort(Uri uri) {
62+
public static final int getExplicitPort(Uri uri) {
6363
int port = uri.getPort();
6464
if (port == -1)
6565
port = getSchemeDefaultPort(uri.getScheme());

providers/netty3/src/main/java/org/asynchttpclient/netty/NettyAsyncHttpProviderConfig.java

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -107,8 +107,6 @@ public Set<Map.Entry<String, Object>> propertiesSet() {
107107

108108
private AdditionalPipelineInitializer httpAdditionalPipelineInitializer;
109109
private AdditionalPipelineInitializer wsAdditionalPipelineInitializer;
110-
private AdditionalPipelineInitializer httpsAdditionalPipelineInitializer;
111-
private AdditionalPipelineInitializer wssAdditionalPipelineInitializer;
112110

113111
/**
114112
* Allow configuring the Netty's socket channel factory.
@@ -155,22 +153,6 @@ public void setWsAdditionalPipelineInitializer(AdditionalPipelineInitializer wsA
155153
this.wsAdditionalPipelineInitializer = wsAdditionalPipelineInitializer;
156154
}
157155

158-
public AdditionalPipelineInitializer getHttpsAdditionalPipelineInitializer() {
159-
return httpsAdditionalPipelineInitializer;
160-
}
161-
162-
public void setHttpsAdditionalPipelineInitializer(AdditionalPipelineInitializer httpsAdditionalPipelineInitializer) {
163-
this.httpsAdditionalPipelineInitializer = httpsAdditionalPipelineInitializer;
164-
}
165-
166-
public AdditionalPipelineInitializer getWssAdditionalPipelineInitializer() {
167-
return wssAdditionalPipelineInitializer;
168-
}
169-
170-
public void setWssAdditionalPipelineInitializer(AdditionalPipelineInitializer wssAdditionalPipelineInitializer) {
171-
this.wssAdditionalPipelineInitializer = wssAdditionalPipelineInitializer;
172-
}
173-
174156
public NioClientSocketChannelFactory getSocketChannelFactory() {
175157
return socketChannelFactory;
176158
}

providers/netty3/src/main/java/org/asynchttpclient/netty/NettyResponseFuture.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -419,7 +419,7 @@ public long getStart() {
419419
}
420420

421421
public Object getPartitionKey() {
422-
return connectionPoolPartitioning.getPartitionKey(getUri(), proxyServer);
422+
return connectionPoolPartitioning.getPartitionKey(request.getUri(), request.getVirtualHost(), proxyServer);
423423
}
424424

425425
@Override

providers/netty3/src/main/java/org/asynchttpclient/netty/channel/ChannelManager.java

Lines changed: 45 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
*/
1414
package org.asynchttpclient.netty.channel;
1515

16+
import static org.asynchttpclient.util.AsyncHttpProviderUtils.getExplicitPort;
17+
import static org.asynchttpclient.util.AsyncHttpProviderUtils.getSchemeDefaultPort;
1618
import static org.asynchttpclient.util.HttpUtils.WS;
1719
import static org.asynchttpclient.util.HttpUtils.isSecure;
1820
import static org.asynchttpclient.util.HttpUtils.isWebSocket;
@@ -102,10 +104,8 @@ public class ChannelManager {
102104

103105
private final ClientSocketChannelFactory socketChannelFactory;
104106
private final boolean allowReleaseSocketChannelFactory;
105-
private final ClientBootstrap plainBootstrap;
106-
private final ClientBootstrap secureBootstrap;
107-
private final ClientBootstrap webSocketBootstrap;
108-
private final ClientBootstrap secureWebSocketBootstrap;
107+
private final ClientBootstrap httpBootstrap;
108+
private final ClientBootstrap wsBootstrap;
109109
private final ConcurrentHashMapV8.Fun<Object, Semaphore> semaphoreComputer;
110110

111111
private Processor wsProcessor;
@@ -189,10 +189,8 @@ public Semaphore apply(Object partitionKey) {
189189
allowReleaseSocketChannelFactory = true;
190190
}
191191

192-
plainBootstrap = new ClientBootstrap(socketChannelFactory);
193-
secureBootstrap = new ClientBootstrap(socketChannelFactory);
194-
webSocketBootstrap = new ClientBootstrap(socketChannelFactory);
195-
secureWebSocketBootstrap = new ClientBootstrap(socketChannelFactory);
192+
httpBootstrap = new ClientBootstrap(socketChannelFactory);
193+
wsBootstrap = new ClientBootstrap(socketChannelFactory);
196194

197195
DefaultChannelFuture.setUseDeadLockChecker(nettyConfig.isUseDeadLockChecker());
198196

@@ -202,10 +200,8 @@ public Semaphore apply(Object partitionKey) {
202200
for (Entry<String, Object> entry : nettyConfig.propertiesSet()) {
203201
String key = entry.getKey();
204202
Object value = entry.getValue();
205-
plainBootstrap.setOption(key, value);
206-
webSocketBootstrap.setOption(key, value);
207-
secureBootstrap.setOption(key, value);
208-
secureWebSocketBootstrap.setOption(key, value);
203+
httpBootstrap.setOption(key, value);
204+
wsBootstrap.setOption(key, value);
209205
}
210206
}
211207

@@ -217,7 +213,7 @@ public void configureBootstraps(NettyRequestSender requestSender, AtomicBoolean
217213
Protocol wsProtocol = new WebSocketProtocol(this, config, nettyConfig, requestSender);
218214
wsProcessor = new Processor(config, this, requestSender, wsProtocol);
219215

220-
plainBootstrap.setPipelineFactory(new ChannelPipelineFactory() {
216+
httpBootstrap.setPipelineFactory(new ChannelPipelineFactory() {
221217

222218
public ChannelPipeline getPipeline() throws Exception {
223219
ChannelPipeline pipeline = pipeline();
@@ -233,7 +229,7 @@ public ChannelPipeline getPipeline() throws Exception {
233229
}
234230
});
235231

236-
webSocketBootstrap.setPipelineFactory(new ChannelPipelineFactory() {
232+
wsBootstrap.setPipelineFactory(new ChannelPipelineFactory() {
237233

238234
public ChannelPipeline getPipeline() throws Exception {
239235
ChannelPipeline pipeline = pipeline();
@@ -246,38 +242,6 @@ public ChannelPipeline getPipeline() throws Exception {
246242
return pipeline;
247243
}
248244
});
249-
250-
secureBootstrap.setPipelineFactory(new ChannelPipelineFactory() {
251-
252-
public ChannelPipeline getPipeline() throws Exception {
253-
ChannelPipeline pipeline = pipeline();
254-
pipeline.addLast(SSL_HANDLER, new SslInitializer(ChannelManager.this));
255-
pipeline.addLast(HTTP_HANDLER, newHttpClientCodec());
256-
pipeline.addLast(INFLATER_HANDLER, newHttpContentDecompressor());
257-
pipeline.addLast(CHUNKED_WRITER_HANDLER, new ChunkedWriteHandler());
258-
pipeline.addLast(HTTP_PROCESSOR, httpProcessor);
259-
260-
if (nettyConfig.getHttpsAdditionalPipelineInitializer() != null)
261-
nettyConfig.getHttpsAdditionalPipelineInitializer().initPipeline(pipeline);
262-
263-
return pipeline;
264-
}
265-
});
266-
267-
secureWebSocketBootstrap.setPipelineFactory(new ChannelPipelineFactory() {
268-
269-
public ChannelPipeline getPipeline() throws Exception {
270-
ChannelPipeline pipeline = pipeline();
271-
pipeline.addLast(SSL_HANDLER, new SslInitializer(ChannelManager.this));
272-
pipeline.addLast(HTTP_HANDLER, newHttpClientCodec());
273-
pipeline.addLast(WS_PROCESSOR, wsProcessor);
274-
275-
if (nettyConfig.getWssAdditionalPipelineInitializer() != null)
276-
nettyConfig.getWssAdditionalPipelineInitializer().initPipeline(pipeline);
277-
278-
return pipeline;
279-
}
280-
});
281245
}
282246

283247
private HttpContentDecompressor newHttpContentDecompressor() {
@@ -308,8 +272,8 @@ public final void tryToOfferChannelToPool(Channel channel, AsyncHandler<?> handl
308272
}
309273
}
310274

311-
public Channel poll(Uri uri, ProxyServer proxy, ConnectionPoolPartitioning connectionPoolPartitioning) {
312-
Object partitionKey = connectionPoolPartitioning.getPartitionKey(uri, proxy);
275+
public Channel poll(Uri uri, String virtualHost, ProxyServer proxy, ConnectionPoolPartitioning connectionPoolPartitioning) {
276+
Object partitionKey = connectionPoolPartitioning.getPartitionKey(uri, virtualHost, proxy);
313277
return channelPool.poll(partitionKey);
314278
}
315279

@@ -358,10 +322,8 @@ public void close() {
358322
config.executorService().shutdown();
359323
if (allowReleaseSocketChannelFactory) {
360324
socketChannelFactory.releaseExternalResources();
361-
plainBootstrap.releaseExternalResources();
362-
secureBootstrap.releaseExternalResources();
363-
webSocketBootstrap.releaseExternalResources();
364-
secureWebSocketBootstrap.releaseExternalResources();
325+
httpBootstrap.releaseExternalResources();
326+
wsBootstrap.releaseExternalResources();
365327
}
366328
}
367329

@@ -436,21 +398,45 @@ public void upgradeProtocol(ChannelPipeline pipeline, String scheme, String host
436398
}
437399
}
438400

439-
public void verifyChannelPipeline(ChannelPipeline pipeline, String scheme) throws IOException, GeneralSecurityException {
401+
public SslHandler addSslHandler(ChannelPipeline pipeline, Uri uri, String virtualHost) throws GeneralSecurityException, IOException {
402+
String peerHost;
403+
int peerPort;
404+
405+
if (virtualHost != null) {
406+
int i = virtualHost.indexOf(':');
407+
if (i == -1) {
408+
peerHost = virtualHost;
409+
peerPort = getSchemeDefaultPort(uri.getScheme());
410+
} else {
411+
peerHost = virtualHost.substring(0, i);
412+
peerPort = Integer.valueOf(virtualHost.substring(i + 1));
413+
}
414+
415+
} else {
416+
peerHost = uri.getHost();
417+
peerPort = getExplicitPort(uri);
418+
}
419+
420+
SslHandler sslHandler = createSslHandler(peerHost, peerPort);
421+
pipeline.addFirst(SSL_HANDLER, sslHandler);
422+
return sslHandler;
423+
}
424+
425+
public void verifyChannelPipeline(ChannelPipeline pipeline, Uri uri, String virtualHost) throws IOException, GeneralSecurityException {
440426

441427
boolean sslHandlerConfigured = isSslHandlerConfigured(pipeline);
442428

443-
if (isSecure(scheme)) {
444-
if (!sslHandlerConfigured)
445-
pipeline.addFirst(SSL_HANDLER, new SslInitializer(this));
429+
if (isSecure(uri.getScheme())) {
430+
if (!sslHandlerConfigured) {
431+
addSslHandler(pipeline, uri, virtualHost);
432+
}
446433

447434
} else if (sslHandlerConfigured)
448435
pipeline.remove(SSL_HANDLER);
449436
}
450437

451-
public ClientBootstrap getBootstrap(String scheme, boolean useProxy, boolean useSSl) {
452-
return scheme.startsWith(WS) && !useProxy ? (useSSl ? secureWebSocketBootstrap : webSocketBootstrap) : //
453-
(useSSl ? secureBootstrap : plainBootstrap);
438+
public ClientBootstrap getBootstrap(String scheme, boolean useProxy) {
439+
return scheme.startsWith(WS) && !useProxy ? wsBootstrap : httpBootstrap;
454440
}
455441

456442
public void upgradePipelineForWebSockets(ChannelPipeline pipeline) {

providers/netty3/src/main/java/org/asynchttpclient/netty/channel/NettyConnectListener.java

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,17 @@
1414
package org.asynchttpclient.netty.channel;
1515

1616
import static org.asynchttpclient.util.AsyncHttpProviderUtils.getBaseUrl;
17+
import static org.asynchttpclient.util.HttpUtils.isSecure;
1718

1819
import java.net.ConnectException;
1920

2021
import org.asynchttpclient.AsyncHandler;
22+
import org.asynchttpclient.Request;
2123
import org.asynchttpclient.handler.AsyncHandlerExtensions;
2224
import org.asynchttpclient.netty.NettyResponseFuture;
2325
import org.asynchttpclient.netty.future.StackTraceInspector;
2426
import org.asynchttpclient.netty.request.NettyRequestSender;
27+
import org.asynchttpclient.uri.Uri;
2528
import org.jboss.netty.channel.Channel;
2629
import org.jboss.netty.channel.ChannelFuture;
2730
import org.jboss.netty.channel.ChannelFutureListener;
@@ -84,10 +87,14 @@ private void writeRequest(Channel channel) {
8487
requestSender.writeRequest(future, channel);
8588
}
8689

87-
private void onFutureSuccess(final Channel channel) throws ConnectException {
88-
SslHandler sslHandler = channel.getPipeline().get(SslHandler.class);
90+
private void onFutureSuccess(final Channel channel) throws Exception {
8991

90-
if (sslHandler != null) {
92+
Request request = future.getRequest();
93+
Uri uri = request.getUri();
94+
95+
// in case of proxy tunneling, we'll add the SslHandler later, after the CONNECT request
96+
if (future.getProxyServer() == null && isSecure(uri)) {
97+
SslHandler sslHandler = channelManager.addSslHandler(channel.getPipeline(), uri, request.getVirtualHost());
9198
sslHandler.handshake().addListener(new ChannelFutureListener() {
9299

93100
@Override

providers/netty3/src/main/java/org/asynchttpclient/netty/channel/SslInitializer.java

Lines changed: 0 additions & 50 deletions
This file was deleted.

providers/netty3/src/main/java/org/asynchttpclient/netty/handler/HttpProtocol.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
package org.asynchttpclient.netty.handler;
1515

1616
import static org.asynchttpclient.ntlm.NtlmUtils.getNTLM;
17-
import static org.asynchttpclient.util.AsyncHttpProviderUtils.getDefaultPort;
17+
import static org.asynchttpclient.util.AsyncHttpProviderUtils.getExplicitPort;
1818
import static org.asynchttpclient.util.MiscUtils.isNonEmpty;
1919
import static org.jboss.netty.handler.codec.http.HttpResponseStatus.CONTINUE;
2020
import static org.jboss.netty.handler.codec.http.HttpResponseStatus.OK;
@@ -352,7 +352,7 @@ private boolean exitAfterHandlingConnect(//
352352
Uri requestUri = request.getUri();
353353
String scheme = requestUri.getScheme();
354354
String host = requestUri.getHost();
355-
int port = getDefaultPort(requestUri);
355+
int port = getExplicitPort(requestUri);
356356

357357
logger.debug("Connecting to proxy {} for scheme {}", proxyServer, scheme);
358358
channelManager.upgradeProtocol(channel.getPipeline(), scheme, host, port);

0 commit comments

Comments
 (0)