Skip to content

Commit 45b5e70

Browse files
author
oleksiys
committed
[1.9.x] + fix the issue #610
#610 "Backport #525 to Grizzly provider"
1 parent 02e7358 commit 45b5e70

File tree

5 files changed

+250
-77
lines changed

5 files changed

+250
-77
lines changed

src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java

Lines changed: 80 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,52 @@
1313

1414
package com.ning.http.client.providers.grizzly;
1515

16-
import static com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProviderConfig.Property.BUFFER_WEBSOCKET_FRAGMENTS;
17-
import static com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProviderConfig.Property.MAX_HTTP_PACKET_HEADER_SIZE;
18-
import static com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProviderConfig.Property.TRANSPORT_CUSTOMIZER;
16+
import com.ning.http.client.AsyncHandler;
17+
import com.ning.http.client.AsyncHandlerExtensions;
18+
import com.ning.http.client.AsyncHttpClient;
19+
import com.ning.http.client.AsyncHttpClientConfig;
20+
import com.ning.http.client.AsyncHttpProvider;
21+
import com.ning.http.client.AsyncHttpProviderConfig;
22+
import com.ning.http.client.Body;
23+
import com.ning.http.client.BodyGenerator;
24+
import com.ning.http.client.FluentCaseInsensitiveStringsMap;
25+
import com.ning.http.client.HttpResponseBodyPart;
26+
import com.ning.http.client.HttpResponseHeaders;
27+
import com.ning.http.client.HttpResponseStatus;
28+
import com.ning.http.client.ListenableFuture;
29+
import com.ning.http.client.MaxRedirectException;
30+
import com.ning.http.client.Param;
31+
import com.ning.http.client.Part;
32+
import com.ning.http.client.ProxyServer;
33+
import com.ning.http.client.Realm;
34+
import com.ning.http.client.Request;
35+
import com.ning.http.client.RequestBuilder;
36+
import com.ning.http.client.Response;
37+
import com.ning.http.client.UpgradeHandler;
38+
import com.ning.http.client.cookie.Cookie;
39+
import com.ning.http.client.cookie.CookieDecoder;
40+
import com.ning.http.client.filter.FilterContext;
41+
import com.ning.http.client.filter.ResponseFilter;
42+
import com.ning.http.client.listener.TransferCompletionHandler;
43+
import com.ning.http.client.ntlm.NTLMEngine;
44+
import com.ning.http.client.uri.UriComponents;
45+
import com.ning.http.client.websocket.WebSocket;
46+
import com.ning.http.client.websocket.WebSocketByteListener;
47+
import com.ning.http.client.websocket.WebSocketCloseCodeReasonListener;
48+
import com.ning.http.client.websocket.WebSocketListener;
49+
import com.ning.http.client.websocket.WebSocketPingListener;
50+
import com.ning.http.client.websocket.WebSocketPongListener;
51+
import com.ning.http.client.websocket.WebSocketTextListener;
52+
import com.ning.http.client.websocket.WebSocketUpgradeHandler;
53+
import com.ning.http.multipart.MultipartBody;
54+
import com.ning.http.multipart.MultipartRequestEntity;
55+
import com.ning.http.util.AsyncHttpProviderUtils;
1956
import static com.ning.http.util.AsyncHttpProviderUtils.getNonEmptyPath;
57+
import com.ning.http.util.AuthenticatorUtils;
2058
import static com.ning.http.util.MiscUtils.isNonEmpty;
2159

60+
import com.ning.http.util.ProxyUtils;
61+
import com.ning.http.util.SslUtils;
2262
import java.io.ByteArrayOutputStream;
2363
import java.io.File;
2464
import java.io.FileInputStream;
@@ -43,10 +83,12 @@
4383
import java.util.concurrent.TimeoutException;
4484
import java.util.concurrent.atomic.AtomicInteger;
4585
import java.util.concurrent.atomic.AtomicLong;
46-
86+
import javax.net.ssl.HostnameVerifier;
4787
import javax.net.ssl.SSLContext;
48-
4988
import org.glassfish.grizzly.Buffer;
89+
import org.glassfish.grizzly.CloseListener;
90+
import org.glassfish.grizzly.CloseType;
91+
import org.glassfish.grizzly.Closeable;
5092
import org.glassfish.grizzly.CompletionHandler;
5193
import org.glassfish.grizzly.Connection;
5294
import org.glassfish.grizzly.EmptyCompletionHandler;
@@ -103,53 +145,9 @@
103145
import org.slf4j.Logger;
104146
import org.slf4j.LoggerFactory;
105147

106-
import com.ning.http.client.AsyncHandler;
107-
import com.ning.http.client.AsyncHandlerExtensions;
108-
import com.ning.http.client.AsyncHttpClient;
109-
import com.ning.http.client.AsyncHttpClientConfig;
110-
import com.ning.http.client.AsyncHttpProvider;
111-
import com.ning.http.client.AsyncHttpProviderConfig;
112-
import com.ning.http.client.Body;
113-
import com.ning.http.client.BodyGenerator;
114-
import com.ning.http.client.FluentCaseInsensitiveStringsMap;
115-
import com.ning.http.client.HttpResponseBodyPart;
116-
import com.ning.http.client.HttpResponseHeaders;
117-
import com.ning.http.client.HttpResponseStatus;
118-
import com.ning.http.client.ListenableFuture;
119-
import com.ning.http.client.MaxRedirectException;
120-
import com.ning.http.client.Param;
121-
import com.ning.http.client.Part;
122-
import com.ning.http.client.ProxyServer;
123-
import com.ning.http.client.Realm;
124-
import com.ning.http.client.Request;
125-
import com.ning.http.client.RequestBuilder;
126-
import com.ning.http.client.Response;
127-
import com.ning.http.client.UpgradeHandler;
128-
import com.ning.http.client.cookie.Cookie;
129-
import com.ning.http.client.cookie.CookieDecoder;
130-
import com.ning.http.client.filter.FilterContext;
131-
import com.ning.http.client.filter.ResponseFilter;
132-
import com.ning.http.client.listener.TransferCompletionHandler;
133-
import com.ning.http.client.ntlm.NTLMEngine;
134-
import com.ning.http.client.uri.UriComponents;
135-
import com.ning.http.client.websocket.WebSocket;
136-
import com.ning.http.client.websocket.WebSocketByteListener;
137-
import com.ning.http.client.websocket.WebSocketCloseCodeReasonListener;
138-
import com.ning.http.client.websocket.WebSocketListener;
139-
import com.ning.http.client.websocket.WebSocketPingListener;
140-
import com.ning.http.client.websocket.WebSocketPongListener;
141-
import com.ning.http.client.websocket.WebSocketTextListener;
142-
import com.ning.http.client.websocket.WebSocketUpgradeHandler;
143-
import com.ning.http.multipart.MultipartBody;
144-
import com.ning.http.multipart.MultipartRequestEntity;
145-
import com.ning.http.util.AsyncHttpProviderUtils;
146-
import com.ning.http.util.AuthenticatorUtils;
147-
import com.ning.http.util.ProxyUtils;
148-
import com.ning.http.util.SslUtils;
149-
150-
import org.glassfish.grizzly.CloseListener;
151-
import org.glassfish.grizzly.CloseType;
152-
import org.glassfish.grizzly.Closeable;
148+
import static com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProviderConfig.Property.BUFFER_WEBSOCKET_FRAGMENTS;
149+
import static com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProviderConfig.Property.MAX_HTTP_PACKET_HEADER_SIZE;
150+
import static com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProviderConfig.Property.TRANSPORT_CUSTOMIZER;
153151

154152
/**
155153
* A Grizzly 2.0-based implementation of {@link AsyncHttpProvider}.
@@ -396,8 +394,13 @@ public void onTimeout(Connection connection) {
396394
true,
397395
false,
398396
false);
399-
final SwitchingSSLFilter filter = new SwitchingSSLFilter(configurator, defaultSecState);
400-
fcb.add(filter);
397+
final SwitchingSSLFilter sslFilter =
398+
new SwitchingSSLFilter(configurator, defaultSecState);
399+
if (clientConfig.getHostnameVerifier() != null) {
400+
sslFilter.addHandshakeListener(new HostnameVerifierListener());
401+
}
402+
fcb.add(sslFilter);
403+
401404
final AsyncHttpClientEventFilter eventFilter = new
402405
AsyncHttpClientEventFilter(this, (Integer) providerConfig.getProperty(MAX_HTTP_PACKET_HEADER_SIZE));
403406
final AsyncHttpClientFilter clientFilter =
@@ -2394,12 +2397,29 @@ void doAsyncConnect(final Request request,
23942397
final UriComponents uri = request.getURI();
23952398
String host = ((proxy != null) ? proxy.getHost() : uri.getHost());
23962399
int port = ((proxy != null) ? proxy.getPort() : uri.getPort());
2397-
if(request.getLocalAddress()!=null) {
2398-
connectionHandler.connect(new InetSocketAddress(host, getPort(uri, port)), new InetSocketAddress(request.getLocalAddress(), 0),
2399-
createConnectionCompletionHandler(request, requestFuture, connectHandler));
2400+
2401+
CompletionHandler<Connection> completionHandler =
2402+
createConnectionCompletionHandler(request, requestFuture,
2403+
connectHandler);
2404+
2405+
final HostnameVerifier verifier =
2406+
provider.clientConfig.getHostnameVerifier();
2407+
2408+
if (Utils.isSecure(uri) && verifier != null) {
2409+
completionHandler =
2410+
HostnameVerifierListener.wrapWithHostnameVerifierHandler(
2411+
completionHandler, verifier, uri.getHost());
2412+
}
2413+
2414+
if (request.getLocalAddress() != null) {
2415+
connectionHandler.connect(new InetSocketAddress(host,
2416+
getPort(uri, port)),
2417+
new InetSocketAddress(request.getLocalAddress(), 0),
2418+
completionHandler);
24002419
} else {
2401-
connectionHandler.connect(new InetSocketAddress(host, getPort(uri, port)),
2402-
createConnectionCompletionHandler(request, requestFuture, connectHandler));
2420+
connectionHandler.connect(new InetSocketAddress(host,
2421+
getPort(uri, port)),
2422+
completionHandler);
24032423
}
24042424

24052425
}
@@ -2452,7 +2472,7 @@ void destroy() {
24522472
pool.destroy();
24532473

24542474
}
2455-
2475+
24562476
CompletionHandler<Connection> createConnectionCompletionHandler(final Request request,
24572477
final GrizzlyResponseFuture future,
24582478
final CompletionHandler<Connection> wrappedHandler) {

src/main/java/com/ning/http/client/providers/grizzly/GrizzlyConnectionPool.java

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2012 Sonatype, Inc. All rights reserved.
2+
* Copyright (c) 2012-2014 Sonatype, Inc. All rights reserved.
33
*
44
* This program is licensed to you under the Apache License Version 2.0,
55
* and you may not use this file except in compliance with the Apache License Version 2.0.
@@ -14,6 +14,7 @@
1414
package com.ning.http.client.providers.grizzly;
1515

1616
import static com.ning.http.util.DateUtils.millisTime;
17+
import static com.ning.http.client.providers.grizzly.Utils.*;
1718

1819
import com.ning.http.client.AsyncHttpClientConfig;
1920

@@ -267,16 +268,6 @@ public void destroy() {
267268
}
268269

269270

270-
// --------------------------------------------------------- Private Methods
271-
272-
273-
private boolean isSecure(String uri) {
274-
275-
return (uri.startsWith("https") || uri.startsWith("wss"));
276-
277-
}
278-
279-
280271
// ---------------------------------------------------------- Nested Classes
281272

282273

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
/*
2+
* Copyright (c) 2014 Sonatype, Inc. 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 http://www.apache.org/licenses/LICENSE-2.0.
7+
*
8+
* Unless required by applicable law or agreed to in writing,
9+
* software distributed under the Apache License Version 2.0 is distributed on an
10+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
* See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
12+
*/
13+
14+
package com.ning.http.client.providers.grizzly;
15+
16+
import com.ning.http.util.Base64;
17+
import java.io.IOException;
18+
import java.net.ConnectException;
19+
import javax.net.ssl.HostnameVerifier;
20+
import javax.net.ssl.SSLSession;
21+
import org.glassfish.grizzly.CompletionHandler;
22+
import org.glassfish.grizzly.Connection;
23+
import org.glassfish.grizzly.Grizzly;
24+
import org.glassfish.grizzly.attributes.Attribute;
25+
import org.glassfish.grizzly.ssl.SSLBaseFilter;
26+
import org.glassfish.grizzly.ssl.SSLUtils;
27+
import org.slf4j.Logger;
28+
import org.slf4j.LoggerFactory;
29+
30+
/**
31+
* The SSL handshake listener, that checks the SSL session hostname after
32+
* handshake is completed.
33+
*
34+
* @author Grizzly Team
35+
*/
36+
class HostnameVerifierListener implements SSLBaseFilter.HandshakeListener {
37+
private final static Logger LOGGER = LoggerFactory.getLogger(HostnameVerifierListener.class);
38+
39+
private static final Attribute<HostnameVerifierTask> VERIFIER_TASK_ATTR =
40+
Grizzly.DEFAULT_ATTRIBUTE_BUILDER.createAttribute(
41+
HostnameVerifierTask.class.getName());
42+
43+
public HostnameVerifierListener() {
44+
}
45+
46+
@Override
47+
public void onStart(final Connection connection) {
48+
// do nothing
49+
LOGGER.debug("SSL Handshake onStart: ");
50+
}
51+
52+
@Override
53+
public void onComplete(final Connection connection) {
54+
final HostnameVerifierTask task = VERIFIER_TASK_ATTR.remove(connection);
55+
if (task != null) {
56+
task.verify();
57+
}
58+
}
59+
60+
static CompletionHandler<Connection> wrapWithHostnameVerifierHandler(
61+
final CompletionHandler<Connection> completionHandler,
62+
final HostnameVerifier verifier, final String host) {
63+
64+
return new CompletionHandler<Connection>() {
65+
66+
public void cancelled() {
67+
if (completionHandler != null) {
68+
completionHandler.cancelled();
69+
}
70+
}
71+
72+
public void failed(final Throwable throwable) {
73+
if (completionHandler != null) {
74+
completionHandler.failed(throwable);
75+
}
76+
}
77+
78+
public void completed(final Connection connection) {
79+
assignHostnameVerifyTask(connection, verifier, host,
80+
completionHandler);
81+
82+
if (completionHandler != null) {
83+
completionHandler.completed(connection);
84+
}
85+
}
86+
87+
public void updated(final Connection connection) {
88+
if (completionHandler != null) {
89+
completionHandler.updated(connection);
90+
}
91+
}
92+
};
93+
}
94+
95+
private static void assignHostnameVerifyTask(final Connection connection,
96+
final HostnameVerifier verifier, final String host,
97+
final CompletionHandler<Connection> delegate) {
98+
final HostnameVerifierTask task = new HostnameVerifierTask(
99+
verifier, connection, host, delegate);
100+
VERIFIER_TASK_ATTR.set(connection, task);
101+
}
102+
103+
private static class HostnameVerifierTask {
104+
private final HostnameVerifier verifier;
105+
private final Connection connection;
106+
private final String host;
107+
private final CompletionHandler<Connection> delegate;
108+
109+
public HostnameVerifierTask(final HostnameVerifier verifier,
110+
final Connection connection,
111+
final String host,
112+
final CompletionHandler<Connection> delegate) {
113+
this.verifier = verifier;
114+
this.connection = connection;
115+
this.host = host;
116+
this.delegate = delegate;
117+
}
118+
119+
public void verify() {
120+
final SSLSession session = SSLUtils.getSSLEngine(connection).getSession();
121+
if (LOGGER.isDebugEnabled()) {
122+
LOGGER.debug("SSL Handshake onComplete: session = {}, id = {}, isValid = {}, host = {}",
123+
session.toString(), Base64.encode(session.getId()), session.isValid(), host);
124+
}
125+
126+
if (!verifier.verify(host, session)) {
127+
connection.close(); // XXX what's the correct way to kill a connection?
128+
IOException e = new ConnectException("Host name verification failed for host " + host);
129+
delegate.failed(e);
130+
}
131+
}
132+
}
133+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
* Copyright (c) 2013-2014 Sonatype, Inc. 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 http://www.apache.org/licenses/LICENSE-2.0.
7+
*
8+
* Unless required by applicable law or agreed to in writing,
9+
* software distributed under the Apache License Version 2.0 is distributed on an
10+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
* See the Apache License Version 2.0 for the specific language governing permissions and limitations there under.
12+
*/
13+
14+
package com.ning.http.client.providers.grizzly;
15+
16+
import com.ning.http.client.uri.UriComponents;
17+
18+
public class Utils {
19+
// ------------------------------------------------------------ Constructors
20+
21+
private Utils() {
22+
}
23+
24+
// ---------------------------------------------------------- Public Methods
25+
26+
public static boolean isSecure(final String uri) {
27+
return (uri.startsWith("https") || uri.startsWith("wss"));
28+
}
29+
30+
public static boolean isSecure(final UriComponents uri) {
31+
final String scheme = uri.getScheme();
32+
return ("https".equals(scheme) || "wss".equals(scheme));
33+
}
34+
}

0 commit comments

Comments
 (0)