Skip to content

Commit b661e0e

Browse files
committed
Move to Netty SslContext API, close AsyncHttpClient#1023
1 parent 5c937e6 commit b661e0e

File tree

10 files changed

+203
-55
lines changed

10 files changed

+203
-55
lines changed

client/src/main/java/org/asynchttpclient/AsyncHttpClientConfig.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
import java.util.Map;
1212
import java.util.concurrent.ThreadFactory;
1313

14-
import org.asynchttpclient.channel.SSLEngineFactory;
1514
import org.asynchttpclient.channel.pool.KeepAliveStrategy;
1615
import org.asynchttpclient.filter.IOExceptionFilter;
1716
import org.asynchttpclient.filter.RequestFilter;
@@ -249,7 +248,7 @@ public interface AsyncHttpClientConfig {
249248

250249
int getHandshakeTimeout();
251250

252-
SSLEngineFactory getSslEngineFactory();
251+
SslEngineFactory getSslEngineFactory();
253252

254253
int getChunkedFileChunkSize();
255254

client/src/main/java/org/asynchttpclient/DefaultAsyncHttpClientConfig.java

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@
3131
import java.util.Properties;
3232
import java.util.concurrent.ThreadFactory;
3333

34-
import org.asynchttpclient.channel.SSLEngineFactory;
3534
import org.asynchttpclient.channel.pool.KeepAliveStrategy;
3635
import org.asynchttpclient.filter.IOExceptionFilter;
3736
import org.asynchttpclient.filter.RequestFilter;
@@ -100,7 +99,7 @@ public class DefaultAsyncHttpClientConfig implements AsyncHttpClientConfig {
10099
private final int sslSessionCacheSize;
101100
private final int sslSessionTimeout;
102101
private final SslContext sslContext;
103-
private final SSLEngineFactory sslEngineFactory;
102+
private final SslEngineFactory sslEngineFactory;
104103

105104
// filters
106105
private final List<RequestFilter> requestFilters;
@@ -163,7 +162,7 @@ private DefaultAsyncHttpClientConfig(//
163162
int sslSessionCacheSize,//
164163
int sslSessionTimeout,//
165164
SslContext sslContext,//
166-
SSLEngineFactory sslEngineFactory,//
165+
SslEngineFactory sslEngineFactory,//
167166

168167
// filters
169168
List<RequestFilter> requestFilters,//
@@ -416,7 +415,7 @@ public SslContext getSslContext() {
416415
}
417416

418417
@Override
419-
public SSLEngineFactory getSslEngineFactory() {
418+
public SslEngineFactory getSslEngineFactory() {
420419
return sslEngineFactory;
421420
}
422421

@@ -557,7 +556,7 @@ public static class Builder {
557556
private int sslSessionCacheSize = defaultSslSessionCacheSize();
558557
private int sslSessionTimeout = defaultSslSessionTimeout();
559558
private SslContext sslContext;
560-
private SSLEngineFactory sslEngineFactory;
559+
private SslEngineFactory sslEngineFactory;
561560

562561
// filters
563562
private final List<RequestFilter> requestFilters = new LinkedList<>();
@@ -831,7 +830,7 @@ public Builder setSslContext(final SslContext sslContext) {
831830
return this;
832831
}
833832

834-
public Builder setSslEngineFactory(SSLEngineFactory sslEngineFactory) {
833+
public Builder setSslEngineFactory(SslEngineFactory sslEngineFactory) {
835834
this.sslEngineFactory = sslEngineFactory;
836835
return this;
837836
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/*
2+
* Copyright (c) 2014 AsyncHttpClient Project. All rights reserved.
3+
*
4+
* This program is licensed to you under the Apache License Version 2.0,
5+
* and you may not use this file except in compliance with the Apache License Version 2.0.
6+
* You may obtain a copy of the Apache License Version 2.0 at
7+
* http://www.apache.org/licenses/LICENSE-2.0.
8+
*
9+
* Unless required by applicable law or agreed to in writing,
10+
* software distributed under the Apache License Version 2.0 is distributed on an
11+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
13+
*/
14+
package org.asynchttpclient;
15+
16+
import javax.net.ssl.SSLEngine;
17+
18+
public interface SslEngineFactory {
19+
20+
/**
21+
* Creates new {@link SSLEngine}.
22+
*
23+
* @param config the client config
24+
* @param peerHost the peer hostname
25+
* @param peerPort the peer port
26+
* @return new engine
27+
*/
28+
SSLEngine newSslEngine(AsyncHttpClientConfig config, String peerHost, int peerPort);
29+
}

client/src/main/java/org/asynchttpclient/netty/channel/ChannelManager.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@
4949

5050
import org.asynchttpclient.AsyncHandler;
5151
import org.asynchttpclient.AsyncHttpClientConfig;
52-
import org.asynchttpclient.channel.SSLEngineFactory;
52+
import org.asynchttpclient.SslEngineFactory;
5353
import org.asynchttpclient.channel.pool.ConnectionPoolPartitioning;
5454
import org.asynchttpclient.handler.AsyncHandlerExtensions;
5555
import org.asynchttpclient.netty.Callback;
@@ -61,6 +61,7 @@
6161
import org.asynchttpclient.netty.handler.Processor;
6262
import org.asynchttpclient.netty.handler.WebSocketProtocol;
6363
import org.asynchttpclient.netty.request.NettyRequestSender;
64+
import org.asynchttpclient.netty.ssl.DefaultSslEngineFactory;
6465
import org.asynchttpclient.proxy.ProxyServer;
6566
import org.asynchttpclient.uri.Uri;
6667
import org.slf4j.Logger;
@@ -81,7 +82,7 @@ public class ChannelManager {
8182
public static final String WS_ENCODER_HANDLER = "ws-encoder";
8283

8384
private final AsyncHttpClientConfig config;
84-
private final SSLEngineFactory sslEngineFactory;
85+
private final SslEngineFactory sslEngineFactory;
8586
private final EventLoopGroup eventLoopGroup;
8687
private final boolean allowReleaseEventLoopGroup;
8788
private final Class<? extends Channel> socketChannelClass;
@@ -107,7 +108,7 @@ public ChannelManager(final AsyncHttpClientConfig config, Timer nettyTimer) {
107108

108109
this.config = config;
109110
try {
110-
this.sslEngineFactory = config.getSslEngineFactory() != null ? config.getSslEngineFactory() : new SSLEngineFactory.DefaultSSLEngineFactory(config);
111+
this.sslEngineFactory = config.getSslEngineFactory() != null ? config.getSslEngineFactory() : new DefaultSslEngineFactory(config);
111112
} catch (SSLException e) {
112113
throw new ExceptionInInitializerError(e);
113114
}
@@ -392,7 +393,7 @@ private HttpClientCodec newHttpClientCodec() {
392393
}
393394

394395
private SslHandler createSslHandler(String peerHost, int peerPort) {
395-
SSLEngine sslEngine = sslEngineFactory.newSSLEngine(peerHost, peerPort);
396+
SSLEngine sslEngine = sslEngineFactory.newSslEngine(config, peerHost, peerPort);
396397
SslHandler sslHandler = new SslHandler(sslEngine);
397398
if (handshakeTimeout > 0)
398399
sslHandler.setHandshakeTimeoutMillis(handshakeTimeout);
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*
2+
* Copyright (c) 2015 AsyncHttpClient Project. All rights reserved.
3+
*
4+
* This program is licensed to you under the Apache License Version 2.0,
5+
* and you may not use this file except in compliance with the Apache License Version 2.0.
6+
* You may obtain a copy of the Apache License Version 2.0 at
7+
* http://www.apache.org/licenses/LICENSE-2.0.
8+
*
9+
* Unless required by applicable law or agreed to in writing,
10+
* software distributed under the Apache License Version 2.0 is distributed on an
11+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
13+
*/
14+
package org.asynchttpclient.netty.ssl;
15+
16+
import io.netty.buffer.ByteBufAllocator;
17+
import io.netty.handler.ssl.SslContext;
18+
import io.netty.handler.ssl.SslContextBuilder;
19+
import io.netty.handler.ssl.SslProvider;
20+
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
21+
22+
import javax.net.ssl.SSLEngine;
23+
import javax.net.ssl.SSLException;
24+
25+
import org.asynchttpclient.AsyncHttpClientConfig;
26+
27+
public class DefaultSslEngineFactory extends SslEngineFactoryBase {
28+
29+
private final SslContext sslContext;
30+
31+
public DefaultSslEngineFactory(AsyncHttpClientConfig config) throws SSLException {
32+
this.sslContext = getSslContext(config);
33+
}
34+
35+
private SslContext getSslContext(AsyncHttpClientConfig config) throws SSLException {
36+
if (config.getSslContext() != null)
37+
return config.getSslContext();
38+
39+
SslContextBuilder sslContextBuilder = SslContextBuilder.forClient()//
40+
.sslProvider(config.isUseOpenSsl() ? SslProvider.OPENSSL : SslProvider.JDK)//
41+
.sessionCacheSize(config.getSslSessionCacheSize())//
42+
.sessionTimeout(config.getSslSessionTimeout());
43+
44+
if (config.isAcceptAnyCertificate())
45+
sslContextBuilder.trustManager(InsecureTrustManagerFactory.INSTANCE);
46+
47+
return sslContextBuilder.build();
48+
}
49+
50+
@Override
51+
public SSLEngine newSslEngine(AsyncHttpClientConfig config, String peerHost, int peerPort) {
52+
// FIXME should be using ctx allocator
53+
SSLEngine sslEngine = sslContext.newEngine(ByteBufAllocator.DEFAULT, peerHost, peerPort);
54+
configureSslEngine(sslEngine, config);
55+
return sslEngine;
56+
}
57+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
* Copyright (c) 2015 AsyncHttpClient Project. All rights reserved.
3+
*
4+
* This program is licensed to you under the Apache License Version 2.0,
5+
* and you may not use this file except in compliance with the Apache License Version 2.0.
6+
* You may obtain a copy of the Apache License Version 2.0 at
7+
* http://www.apache.org/licenses/LICENSE-2.0.
8+
*
9+
* Unless required by applicable law or agreed to in writing,
10+
* software distributed under the Apache License Version 2.0 is distributed on an
11+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
13+
*/
14+
package org.asynchttpclient.netty.ssl;
15+
16+
import javax.net.ssl.SSLContext;
17+
import javax.net.ssl.SSLEngine;
18+
19+
import org.asynchttpclient.AsyncHttpClientConfig;
20+
21+
public class JsseSslEngineFactory extends SslEngineFactoryBase {
22+
23+
private final SSLContext sslContext;
24+
25+
public JsseSslEngineFactory(SSLContext sslContext) {
26+
this.sslContext = sslContext;
27+
}
28+
29+
@Override
30+
public SSLEngine newSslEngine(AsyncHttpClientConfig config, String peerHost, int peerPort) {
31+
SSLEngine sslEngine = sslContext.createSSLEngine(peerHost, peerPort);
32+
configureSslEngine(sslEngine, config);
33+
return sslEngine;
34+
}
35+
36+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
* Copyright (c) 2015 AsyncHttpClient Project. All rights reserved.
3+
*
4+
* This program is licensed to you under the Apache License Version 2.0,
5+
* and you may not use this file except in compliance with the Apache License Version 2.0.
6+
* You may obtain a copy of the Apache License Version 2.0 at
7+
* http://www.apache.org/licenses/LICENSE-2.0.
8+
*
9+
* Unless required by applicable law or agreed to in writing,
10+
* software distributed under the Apache License Version 2.0 is distributed on an
11+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
13+
*/
14+
package org.asynchttpclient.netty.ssl;
15+
16+
import static org.asynchttpclient.util.MiscUtils.isNonEmpty;
17+
18+
import javax.net.ssl.SSLEngine;
19+
import javax.net.ssl.SSLParameters;
20+
21+
import org.asynchttpclient.AsyncHttpClientConfig;
22+
import org.asynchttpclient.SslEngineFactory;
23+
24+
public abstract class SslEngineFactoryBase implements SslEngineFactory {
25+
26+
protected void configureSslEngine(SSLEngine sslEngine, AsyncHttpClientConfig config) {
27+
sslEngine.setUseClientMode(true);
28+
if (!config.isAcceptAnyCertificate()) {
29+
SSLParameters params = sslEngine.getSSLParameters();
30+
params.setEndpointIdentificationAlgorithm("HTTPS");
31+
sslEngine.setSSLParameters(params);
32+
}
33+
34+
if (isNonEmpty(config.getEnabledProtocols()))
35+
sslEngine.setEnabledProtocols(config.getEnabledProtocols());
36+
37+
if (isNonEmpty(config.getEnabledCipherSuites()))
38+
sslEngine.setEnabledCipherSuites(config.getEnabledCipherSuites());
39+
}
40+
}

client/src/test/java/org/asynchttpclient/BasicHttpsTest.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ protected String getTargetUrl() {
4242
@Test(groups = "standalone")
4343
public void zeroCopyPostTest() throws Exception {
4444

45-
try (AsyncHttpClient client = asyncHttpClient(config().setSslContext(createSslContext(new AtomicBoolean(true))))) {
45+
try (AsyncHttpClient client = asyncHttpClient(config().setSslEngineFactory(createSslEngineFactory(new AtomicBoolean(true))))) {
4646
Response resp = client.preparePost(getTargetUrl()).setBody(SIMPLE_TEXT_FILE).setHeader("Content-Type", "text/html").execute().get();
4747
assertNotNull(resp);
4848
assertEquals(resp.getStatusCode(), HttpServletResponse.SC_OK);
@@ -52,7 +52,7 @@ public void zeroCopyPostTest() throws Exception {
5252

5353
@Test(groups = "standalone")
5454
public void multipleSSLRequestsTest() throws Exception {
55-
try (AsyncHttpClient c = asyncHttpClient(config().setSslContext(createSslContext(new AtomicBoolean(true))))) {
55+
try (AsyncHttpClient c = asyncHttpClient(config().setSslEngineFactory(createSslEngineFactory(new AtomicBoolean(true))))) {
5656
String body = "hello there";
5757

5858
// once
@@ -78,7 +78,7 @@ public boolean keepAlive(Request ahcRequest, HttpRequest nettyRequest, HttpRespo
7878
}
7979
};
8080

81-
try (AsyncHttpClient c = asyncHttpClient(config().setSslContext(createSslContext(new AtomicBoolean(true))).setKeepAliveStrategy(keepAliveStrategy))) {
81+
try (AsyncHttpClient c = asyncHttpClient(config().setSslEngineFactory(createSslEngineFactory(new AtomicBoolean(true))).setKeepAliveStrategy(keepAliveStrategy))) {
8282
String body = "hello there";
8383
c.preparePost(getTargetUrl()).setBody(body).setHeader("Content-Type", "text/html").execute();
8484

@@ -94,7 +94,7 @@ public boolean keepAlive(Request ahcRequest, HttpRequest nettyRequest, HttpRespo
9494
public void reconnectsAfterFailedCertificationPath() throws Exception {
9595

9696
AtomicBoolean trust = new AtomicBoolean(false);
97-
try (AsyncHttpClient client = asyncHttpClient(config().setSslEngineFactory(createSSLEngineFactory(trust)))) {
97+
try (AsyncHttpClient client = asyncHttpClient(config().setSslEngineFactory(createSslEngineFactory(trust)))) {
9898
String body = "hello there";
9999

100100
// first request fails because server certificate is rejected
@@ -128,7 +128,7 @@ public void failInstantlyIfNotAllowedSelfSignedCertificate() throws Throwable {
128128

129129
@Test(groups = "standalone")
130130
public void testNormalEventsFired() throws Exception {
131-
try (AsyncHttpClient client = asyncHttpClient(config().setSslContext(createSslContext(new AtomicBoolean(true))))) {
131+
try (AsyncHttpClient client = asyncHttpClient(config().setSslEngineFactory(createSslEngineFactory(new AtomicBoolean(true))))) {
132132
EventCollectingHandler handler = new EventCollectingHandler();
133133
client.preparePost(getTargetUrl()).setBody("whatever").execute(handler).get(3, TimeUnit.SECONDS);
134134
handler.waitForCompletion(3, TimeUnit.SECONDS);

0 commit comments

Comments
 (0)