From a63b1c71ce384913f555649e53548d649c4d4e73 Mon Sep 17 00:00:00 2001 From: Ryan Lubke Date: Mon, 27 Aug 2012 13:37:32 -0500 Subject: [PATCH 001/264] Port changes from master. - improve proxy tunneling test - Fix proxy tunneling in grizzly provider - add WS tunneling support. --- pom.xml | 2 +- .../grizzly/GrizzlyAsyncHttpProvider.java | 106 ++++++++++++------ .../client/async/ProxyyTunnellingTest.java | 6 +- 3 files changed, 78 insertions(+), 36 deletions(-) diff --git a/pom.xml b/pom.xml index 045026284d..6e4545bdc8 100644 --- a/pom.xml +++ b/pom.xml @@ -528,7 +528,7 @@ org.glassfish.grizzly grizzly-websockets - 2.2.10 + 2.2.16 true diff --git a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java index 3cfa92c9e3..a29bfea4b7 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java @@ -101,6 +101,7 @@ import org.glassfish.grizzly.websockets.DataFrame; import org.glassfish.grizzly.websockets.DefaultWebSocket; import org.glassfish.grizzly.websockets.HandShake; +import org.glassfish.grizzly.websockets.HandshakeException; import org.glassfish.grizzly.websockets.ProtocolHandler; import org.glassfish.grizzly.websockets.Version; import org.glassfish.grizzly.websockets.WebSocketEngine; @@ -147,7 +148,7 @@ public class GrizzlyAsyncHttpProvider implements AsyncHttpProvider { private final static Logger LOGGER = LoggerFactory.getLogger(GrizzlyAsyncHttpProvider.class); private static final boolean SEND_FILE_SUPPORT; static { - SEND_FILE_SUPPORT = configSendFileSupport(); + SEND_FILE_SUPPORT = /*configSendFileSupport()*/ false; } private final Attribute REQUEST_STATE_ATTR = Grizzly.DEFAULT_ATTRIBUTE_BUILDER.createAttribute(HttpTransactionContext.class.getName()); @@ -619,6 +620,7 @@ final class HttpTransactionContext { HandShake handshake; ProtocolHandler protocolHandler; WebSocket webSocket; + boolean establishingTunnel; // -------------------------------------------------------- Constructors @@ -677,6 +679,15 @@ void result(Object result) { } } + boolean isTunnelEstablished(final Connection c) { + return c.getAttributes().getAttribute("tunnel-established") != null; + } + + + void tunnelEstablished(final Connection c) { + c.getAttributes().setAttribute("tunnel-established", Boolean.TRUE); + } + } // END HttpTransactionContext @@ -844,7 +855,9 @@ private boolean sendAsGrizzlyRequest(final Request request, final ProxyServer proxy = getProxyServer(request); final boolean useProxy = (proxy != null); if (useProxy) { - if (secure) { + if ((secure || httpCtx.isWSRequest) && !httpCtx.isTunnelEstablished(ctx.getConnection())) { + secure = false; + httpCtx.establishingTunnel = true; builder.method(Method.CONNECT); builder.uri(AsyncHttpProviderUtils.getAuthority(uri)); } else { @@ -864,7 +877,7 @@ private boolean sendAsGrizzlyRequest(final Request request, } HttpRequestPacket requestPacket; - if (httpCtx.isWSRequest) { + if (httpCtx.isWSRequest && !httpCtx.establishingTunnel) { try { final URI wsURI = new URI(httpCtx.wsRequestURI); httpCtx.protocolHandler = Version.DRAFT17.createHandler(true); @@ -877,7 +890,10 @@ private boolean sendAsGrizzlyRequest(final Request request, } else { requestPacket = builder.build(); } - requestPacket.setSecure(true); + requestPacket.setSecure(secure); + if (secure) { + ctx.notifyDownstream(new SwitchingSSLFilter.SSLSwitchingEvent(true, ctx.getConnection())); + } if (!useProxy && !httpCtx.isWSRequest) { addQueryString(request, requestPacket); } @@ -1139,14 +1155,19 @@ protected void onInitialLineParsed(HttpHeader httpHeader, if (httpHeader.isSkipRemainder()) { return; } + final Connection connection = ctx.getConnection(); final HttpTransactionContext context = - provider.getHttpTransactionContext(ctx.getConnection()); + provider.getHttpTransactionContext(connection); final int status = ((HttpResponsePacket) httpHeader).getStatus(); + if (context.establishingTunnel && HttpStatus.OK_200.statusMatches(status)) { + return; + } if (HttpStatus.CONINTUE_100.statusMatches(status)) { ctx.notifyUpstream(new ContinueEvent(context)); return; } + if (context.statusHandler != null && !context.statusHandler.handlesStatus(status)) { context.statusHandler = null; context.invocationStatus = StatusHandler.InvocationStatus.CONTINUE; @@ -1180,9 +1201,9 @@ protected void onInitialLineParsed(HttpHeader httpHeader, } } final GrizzlyResponseStatus responseStatus = - new GrizzlyResponseStatus((HttpResponsePacket) httpHeader, - getURI(context.requestUrl), - provider); + new GrizzlyResponseStatus((HttpResponsePacket) httpHeader, + getURI(context.requestUrl), + provider); context.responseStatus = responseStatus; if (context.statusHandler != null) { return; @@ -1193,6 +1214,10 @@ protected void onInitialLineParsed(HttpHeader httpHeader, final AsyncHandler handler = context.handler; if (handler != null) { context.currentState = handler.onStatusReceived(responseStatus); + if (context.isWSRequest && context.currentState == AsyncHandler.STATE.ABORT) { + httpHeader.setSkipRemainder(true); + context.abort(new HandshakeException("Upgrade failed")); + } } } catch (Exception e) { httpHeader.setSkipRemainder(true); @@ -1221,24 +1246,23 @@ protected void onHttpHeadersParsed(HttpHeader httpHeader, FilterChainContext ctx) { super.onHttpHeadersParsed(httpHeader, ctx); - if (LOGGER.isDebugEnabled()) { - LOGGER.debug("RESPONSE: " + httpHeader.toString()); - } + LOGGER.debug("RESPONSE: {}", httpHeader); if (httpHeader.containsHeader(Header.Connection)) { if ("close".equals(httpHeader.getHeader(Header.Connection))) { ConnectionManager.markConnectionAsDoNotCache(ctx.getConnection()); } } - if (httpHeader.isSkipRemainder()) { - return; - } final HttpTransactionContext context = provider.getHttpTransactionContext(ctx.getConnection()); + if (httpHeader.isSkipRemainder() || context.establishingTunnel) { + return; + } + final AsyncHandler handler = context.handler; final List filters = context.provider.clientConfig.getResponseFilters(); final GrizzlyResponseHeaders responseHeaders = new GrizzlyResponseHeaders((HttpResponsePacket) httpHeader, - null, - provider); + null, + provider); if (!filters.isEmpty()) { FilterContext fc = new FilterContext.FilterContextBuilder() .asyncHandler(handler).request(context.request) @@ -1260,16 +1284,16 @@ protected void onHttpHeadersParsed(HttpHeader httpHeader, context.provider.connectionManager; final Connection c = m.obtainConnection(newRequest, - context.future); + context.future); final HttpTransactionContext newContext = context.copy(); context.future = null; provider.setHttpTransactionContext(c, newContext); try { context.provider.execute(c, - newRequest, - newHandler, - context.future); + newRequest, + newHandler, + context.future); } catch (IOException ioe) { newContext.abort(ioe); } @@ -1281,8 +1305,8 @@ protected void onHttpHeadersParsed(HttpHeader httpHeader, } if (context.statusHandler != null && context.invocationStatus == StatusHandler.InvocationStatus.CONTINUE) { final boolean result = context.statusHandler.handleStatus(((HttpResponsePacket) httpHeader), - context, - ctx); + context, + ctx); if (!result) { httpHeader.setSkipRemainder(true); return; @@ -1347,20 +1371,38 @@ protected boolean onHttpPacketParsed(HttpHeader httpHeader, FilterChainContext c result = super.onHttpPacketParsed(httpHeader, ctx); - final HttpTransactionContext context = cleanup(ctx, provider); - - final AsyncHandler handler = context.handler; - if (handler != null) { + final HttpTransactionContext context = provider.getHttpTransactionContext(ctx.getConnection()); + if (context.establishingTunnel + && HttpStatus.OK_200.statusMatches( + ((HttpResponsePacket) httpHeader).getStatus())) { + context.establishingTunnel = false; + final Connection c = ctx.getConnection(); + context.tunnelEstablished(c); try { - context.result(handler.onCompleted()); - } catch (Exception e) { + context.provider.execute(c, + context.request, + context.handler, + context.future); + return result; + } catch (IOException e) { context.abort(e); + return result; } } else { - context.done(null); - } + cleanup(ctx, provider); + final AsyncHandler handler = context.handler; + if (handler != null) { + try { + context.result(handler.onCompleted()); + } catch (Exception e) { + context.abort(e); + } + } else { + context.done(null); + } - return result; + return result; + } } @@ -1389,7 +1431,7 @@ private static HttpTransactionContext cleanup(final FilterChainContext ctx, context.abort(new IOException("Maximum pooled connections exceeded")); } else { if (!context.provider.connectionManager.returnConnection(context.requestUrl, c)) { - ctx.getConnection().close().markForRecycle(true); + ctx.getConnection().close(); } } diff --git a/src/test/java/com/ning/http/client/async/ProxyyTunnellingTest.java b/src/test/java/com/ning/http/client/async/ProxyyTunnellingTest.java index f1dd8a631b..08d596ae0c 100644 --- a/src/test/java/com/ning/http/client/async/ProxyyTunnellingTest.java +++ b/src/test/java/com/ning/http/client/async/ProxyyTunnellingTest.java @@ -111,7 +111,7 @@ public Response onCompleted(Response response) throws Exception { }); Response r = responseFuture.get(); assertEquals(r.getStatusCode(), 200); - assertEquals(r.getHeader("server"), "Jetty(8.1.1.v20120215)"); + assertEquals(r.getHeader("X-Proxy-Connection"), "keep-alive"); asyncHttpClient.close(); } @@ -142,7 +142,7 @@ public Response onCompleted(Response response) throws Exception { }); Response r = responseFuture.get(); assertEquals(r.getStatusCode(), 200); - assertEquals(r.getHeader("server"), "Jetty(8.1.1.v20120215)"); + assertEquals(r.getHeader("X-Proxy-Connection"), "keep-alive"); asyncHttpClient.close(); } @@ -162,7 +162,7 @@ public void testSimpleAHCConfigProxy() throws IOException, InterruptedException, Response r = client.get().get(); assertEquals(r.getStatusCode(), 200); - assertEquals(r.getHeader("server"), "Jetty(8.1.1.v20120215)"); + assertEquals(r.getHeader("X-Proxy-Connection"), "keep-alive"); client.close(); } From 723dd7e376f8b15ae95e4e5b0f3455cd578ba4dd Mon Sep 17 00:00:00 2001 From: Ryan Lubke Date: Mon, 27 Aug 2012 14:58:09 -0500 Subject: [PATCH 002/264] [maven-release-plugin] prepare release async-http-client-1.7.6 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 6e4545bdc8..c8b6426e19 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.7.6-SNAPSHOT + 1.7.6 jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From 92dc79aab87f2be982bd1d3a883bf60d301a09cc Mon Sep 17 00:00:00 2001 From: Ryan Lubke Date: Mon, 27 Aug 2012 14:58:20 -0500 Subject: [PATCH 003/264] [maven-release-plugin] prepare for next development iteration --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index c8b6426e19..4790825469 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.7.6 + 1.7.7-SNAPSHOT jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From d4f8943837c54dbfd252fa617e50a591638305b5 Mon Sep 17 00:00:00 2001 From: jfarcand Date: Fri, 2 Nov 2012 10:43:38 -0400 Subject: [PATCH 004/264] Apply pull 158 to the proper branch --- .../netty/NettyAsyncHttpProvider.java | 71 +++++++++++++++---- .../netty/NettyAsyncHttpProviderConfig.java | 30 +++++++- 2 files changed, 86 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java index da017b1679..699e195315 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java @@ -151,6 +151,12 @@ public class NettyAsyncHttpProvider extends SimpleChannelUpstreamHandler impleme private final AsyncHttpClientConfig config; private final AtomicBoolean isClose = new AtomicBoolean(false); private final ClientSocketChannelFactory socketChannelFactory; + private int httpClientCodecMaxInitialLineLength = 4096; + private int httpClientCodecMaxHeaderSize = 8192; + private int httpClientCodecMaxChunkSize = 8192; + private int httpsClientCodecMaxInitialLineLength = 4096; + private int httpsClientCodecMaxHeaderSize = 8192; + private int httpsClientCodecMaxChunkSize = 8192; private final ChannelGroup openChannels = new CleanupChannelGroup("asyncHttpClient") { @@ -238,6 +244,8 @@ void configureNetty() { for (Entry entry : asyncHttpProviderConfig.propertiesSet()) { plainBootstrap.setOption(entry.getKey(), entry.getValue()); } + configureHttpClientCodec(); + configureHttpsClientCodec(); } plainBootstrap.setPipelineFactory(new ChannelPipelineFactory() { @@ -246,7 +254,7 @@ void configureNetty() { public ChannelPipeline getPipeline() throws Exception { ChannelPipeline pipeline = pipeline(); - pipeline.addLast(HTTP_HANDLER, new HttpClientCodec()); + pipeline.addLast(HTTP_HANDLER, createHttpClientCodec()); if (config.getRequestCompressionLevel() > 0) { pipeline.addLast("deflater", new HttpContentCompressor(config.getRequestCompressionLevel())); @@ -284,6 +292,42 @@ public ChannelPipeline getPipeline() throws Exception { }); } + protected void configureHttpClientCodec() { + httpClientCodecMaxInitialLineLength = asyncHttpProviderConfig.getProperty( + NettyAsyncHttpProviderConfig.HTTP_CLIENT_CODEC_MAX_INITIAL_LINE_LENGTH, + Integer.class, + httpClientCodecMaxInitialLineLength + ); + httpClientCodecMaxHeaderSize = asyncHttpProviderConfig.getProperty( + NettyAsyncHttpProviderConfig.HTTP_CLIENT_CODEC_MAX_HEADER_SIZE, + Integer.class, + httpClientCodecMaxHeaderSize + ); + httpClientCodecMaxChunkSize = asyncHttpProviderConfig.getProperty( + NettyAsyncHttpProviderConfig.HTTP_CLIENT_CODEC_MAX_CHUNK_SIZE, + Integer.class, + httpClientCodecMaxChunkSize + ); + } + + protected void configureHttpsClientCodec() { + httpsClientCodecMaxInitialLineLength = asyncHttpProviderConfig.getProperty( + NettyAsyncHttpProviderConfig.HTTPS_CLIENT_CODEC_MAX_INITIAL_LINE_LENGTH, + Integer.class, + httpsClientCodecMaxInitialLineLength + ); + httpsClientCodecMaxHeaderSize = asyncHttpProviderConfig.getProperty( + NettyAsyncHttpProviderConfig.HTTPS_CLIENT_CODEC_MAX_HEADER_SIZE, + Integer.class, + httpsClientCodecMaxHeaderSize + ); + httpsClientCodecMaxChunkSize = asyncHttpProviderConfig.getProperty( + NettyAsyncHttpProviderConfig.HTTPS_CLIENT_CODEC_MAX_CHUNK_SIZE, + Integer.class, + httpsClientCodecMaxChunkSize + ); + } + void constructSSLPipeline(final NettyConnectListener cl) { secureBootstrap.setPipelineFactory(new ChannelPipelineFactory() { @@ -298,7 +342,7 @@ public ChannelPipeline getPipeline() throws Exception { abort(cl.future(), ex); } - pipeline.addLast(HTTP_HANDLER, new HttpClientCodec()); + pipeline.addLast(HTTP_HANDLER, createHttpsClientCodec()); if (config.isCompressionEnabled()) { pipeline.addLast("inflater", new HttpContentDecompressor()); @@ -363,6 +407,14 @@ private SSLEngine createSSLEngine() throws IOException, GeneralSecurityException return sslEngine; } + private HttpClientCodec createHttpClientCodec() { + return new HttpClientCodec(httpClientCodecMaxInitialLineLength, httpClientCodecMaxHeaderSize, httpClientCodecMaxChunkSize); + } + + private HttpClientCodec createHttpsClientCodec() { + return new HttpClientCodec(httpsClientCodecMaxInitialLineLength, httpsClientCodecMaxHeaderSize, httpsClientCodecMaxChunkSize); + } + private Channel verifyChannelPipeline(Channel channel, String scheme) throws IOException, GeneralSecurityException { if (channel.getPipeline().get(SSL_HANDLER) != null && HTTP.equalsIgnoreCase(scheme)) { @@ -547,7 +599,6 @@ private static HttpRequest construct(AsyncHttpClientConfig config, ChannelBuffer buffer) throws IOException { String host = AsyncHttpProviderUtils.getHost(uri); - boolean webSocket = isWebSocket(uri); if (request.getVirtualHost() != null) { host = request.getVirtualHost(); @@ -568,12 +619,11 @@ private static HttpRequest construct(AsyncHttpClientConfig config, } nettyRequest = new DefaultHttpRequest(HttpVersion.HTTP_1_1, m, path.toString()); } - + boolean webSocket = isWebSocket(uri); if (webSocket) { nettyRequest.addHeader(HttpHeaders.Names.UPGRADE, HttpHeaders.Values.WEBSOCKET); nettyRequest.addHeader(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.UPGRADE); - nettyRequest.addHeader("Origin", "http://" + uri.getHost() + ":" - + (uri.getPort() == -1 ? isSecure(uri.getScheme()) ? 443 : 80 : uri.getPort())); + nettyRequest.addHeader("Origin", "http://" + uri.getHost() + ":" + uri.getPort()); nettyRequest.addHeader(WEBSOCKET_KEY, WebSocketUtil.getKey()); nettyRequest.addHeader("Sec-WebSocket-Version", "13"); } @@ -2346,13 +2396,7 @@ public void handle(ChannelHandlerContext ctx, MessageEvent e) throws Exception { s = new ResponseStatus(future.getURI(), response, NettyAsyncHttpProvider.this); final boolean statusReceived = h.onStatusReceived(s) == STATE.UPGRADE; - if (!statusReceived) { - h.onClose(new NettyWebSocket(ctx.getChannel()), 1002, "Bad response status " + response.getStatus().getCode()); - future.done(null); - return; - } - - if (!validStatus || !validUpgrade || !validConnection) { + if (!validStatus || !validUpgrade || !validConnection || !statusReceived) { throw new IOException("Invalid handshake response"); } @@ -2463,4 +2507,3 @@ private static boolean isSecure(URI uri) { return isSecure(uri.getScheme()); } } - diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProviderConfig.java b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProviderConfig.java index 7c976149e6..c471faa4f8 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProviderConfig.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProviderConfig.java @@ -57,6 +57,20 @@ public class NettyAsyncHttpProviderConfig implements AsyncHttpProviderConfig properties = new ConcurrentHashMap(); public NettyAsyncHttpProviderConfig() { @@ -85,6 +99,20 @@ public Object getProperty(String name) { return properties.get(name); } + /** + * Return the value associated with the property's name + * + * @param name + * @return this instance of AsyncHttpProviderConfig + */ + public T getProperty(String name, Class type, T defaultValue) { + Object value = properties.get(name); + if (value != null && type.isAssignableFrom(value.getClass())) { + return type.cast(value); + } + return defaultValue; + } + /** * Remove the value associated with the property's name * @@ -103,4 +131,4 @@ public Object removeProperty(String name) { public Set> propertiesSet() { return properties.entrySet(); } -} +} \ No newline at end of file From 4cd825805189e38c5a0d45f7acc34e4c585ac0e5 Mon Sep 17 00:00:00 2001 From: jfarcand Date: Fri, 2 Nov 2012 10:46:07 -0400 Subject: [PATCH 005/264] Allow customization of the WebSocketUpgradeHandler --- .../websocket/WebSocketUpgradeHandler.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/ning/http/client/websocket/WebSocketUpgradeHandler.java b/src/main/java/com/ning/http/client/websocket/WebSocketUpgradeHandler.java index 5483720913..64bf8b32e1 100644 --- a/src/main/java/com/ning/http/client/websocket/WebSocketUpgradeHandler.java +++ b/src/main/java/com/ning/http/client/websocket/WebSocketUpgradeHandler.java @@ -33,7 +33,7 @@ public class WebSocketUpgradeHandler implements UpgradeHandler, Async private final long maxTextSize; private final AtomicBoolean ok = new AtomicBoolean(false); - private WebSocketUpgradeHandler(Builder b) { + protected WebSocketUpgradeHandler(Builder b) { l = b.l; protocol = b.protocol; maxByteSize = b.maxByteSize; @@ -44,7 +44,7 @@ private WebSocketUpgradeHandler(Builder b) { * {@inheritDoc} */ @Override - public final void onThrowable(Throwable t) { + public void onThrowable(Throwable t) { onFailure(t); } @@ -52,7 +52,7 @@ public final void onThrowable(Throwable t) { * {@inheritDoc} */ @Override - public final STATE onBodyPartReceived(HttpResponseBodyPart bodyPart) throws Exception { + public STATE onBodyPartReceived(HttpResponseBodyPart bodyPart) throws Exception { return STATE.CONTINUE; } @@ -60,7 +60,7 @@ public final STATE onBodyPartReceived(HttpResponseBodyPart bodyPart) throws Exce * {@inheritDoc} */ @Override - public final STATE onStatusReceived(HttpResponseStatus responseStatus) throws Exception { + public STATE onStatusReceived(HttpResponseStatus responseStatus) throws Exception { if (responseStatus.getStatusCode() == 101) { return STATE.UPGRADE; } else { @@ -72,7 +72,7 @@ public final STATE onStatusReceived(HttpResponseStatus responseStatus) throws Ex * {@inheritDoc} */ @Override - public final STATE onHeadersReceived(HttpResponseHeaders headers) throws Exception { + public STATE onHeadersReceived(HttpResponseHeaders headers) throws Exception { return STATE.CONTINUE; } @@ -80,7 +80,7 @@ public final STATE onHeadersReceived(HttpResponseHeaders headers) throws Excepti * {@inheritDoc} */ @Override - public final WebSocket onCompleted() throws Exception { + public WebSocket onCompleted() throws Exception { if (webSocket == null) { throw new IllegalStateException("WebSocket is null"); } @@ -91,7 +91,7 @@ public final WebSocket onCompleted() throws Exception { * {@inheritDoc} */ @Override - public final void onSuccess(WebSocket webSocket) { + public void onSuccess(WebSocket webSocket) { this.webSocket = webSocket; for (WebSocketListener w : l) { webSocket.addWebSocketListener(w); @@ -104,7 +104,7 @@ public final void onSuccess(WebSocket webSocket) { * {@inheritDoc} */ @Override - public final void onFailure(Throwable t) { + public void onFailure(Throwable t) { for (WebSocketListener w : l) { if (!ok.get() && webSocket != null) { webSocket.addWebSocketListener(w); @@ -113,7 +113,7 @@ public final void onFailure(Throwable t) { } } - public final void onClose(WebSocket webSocket, int status, String reasonPhrase) { + public void onClose(WebSocket webSocket, int status, String reasonPhrase) { // Connect failure if (this.webSocket == null) this.webSocket = webSocket; From 7840539f8211fee80bce657c6c972f434e362477 Mon Sep 17 00:00:00 2001 From: jfarcand Date: Fri, 2 Nov 2012 10:47:16 -0400 Subject: [PATCH 006/264] New workspace location --- pom.xml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pom.xml b/pom.xml index 4790825469..00bef2ff94 100644 --- a/pom.xml +++ b/pom.xml @@ -15,11 +15,11 @@ Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and asynchronously process the HTTP responses. - http://github.com/sonatype/async-http-client + http://github.com/AsyncHttpClientasync-http-client - scm:git:git@github.com:sonatype/async-http-client.git - https://github.com/sonatype/async-http-client - scm:git:git@github.com:sonatype/async-http-client.git + scm:git:git@github.com:AsyncHttpClientasync-http-client.git + https://github.com/AsyncHttpClientasync-http-client + scm:git:git@github.com:AsyncHttpClientasync-http-client.git jira @@ -609,7 +609,7 @@ github - gitsite:git@github.com/sonatype/async-http-client.git + gitsite:git@github.com/AsyncHttpClientasync-http-client.git From eed0f1b8d5a7857660f4e4b1280071fb46c30b82 Mon Sep 17 00:00:00 2001 From: jfarcand Date: Fri, 2 Nov 2012 15:28:43 -0400 Subject: [PATCH 007/264] Do not assume headers have been received when reading status --- .../http/client/providers/netty/NettyAsyncHttpProvider.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java index 699e195315..5451baff1c 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java @@ -2277,7 +2277,7 @@ public Object call() throws Exception { if (!future.getAndSetStatusReceived(true) && updateStatusAndInterrupt(handler, status)) { finishUpdate(future, ctx, response.isChunked()); return; - } else if (updateHeadersAndInterrupt(handler, responseHeaders)) { + } else if (response.getHeaders().size() > 0 && updateHeadersAndInterrupt(handler, responseHeaders)) { finishUpdate(future, ctx, response.isChunked()); return; } else if (!response.isChunked()) { From 2fc485d085a6fb1eb0980f4d55f6bd475638e051 Mon Sep 17 00:00:00 2001 From: jfarcand Date: Mon, 5 Nov 2012 08:20:51 -0500 Subject: [PATCH 008/264] Fix pom.mxl thanks to Stephane Landelle --- pom.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index 00bef2ff94..481621757c 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ 4.0.0 com.ning - async-http-client + async-http-client cd Asynchronous Http Client 1.7.7-SNAPSHOT jar @@ -17,9 +17,9 @@ http://github.com/AsyncHttpClientasync-http-client - scm:git:git@github.com:AsyncHttpClientasync-http-client.git - https://github.com/AsyncHttpClientasync-http-client - scm:git:git@github.com:AsyncHttpClientasync-http-client.git + scm:git:git@github.com:AsyncHttpClient/async-http-client.git + https://github.com/AsyncHttpClient/async-http-client + scm:git:git@github.com:AsyncHttpClient/async-http-client.git jira From e27c23ba3a64b914d65b05b0c5e9ed8b38c100c5 Mon Sep 17 00:00:00 2001 From: jfarcand Date: Mon, 5 Nov 2012 09:12:04 -0500 Subject: [PATCH 009/264] Fix pom --- pom.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index 481621757c..19a12c9e76 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ 4.0.0 com.ning - async-http-client cd + async-http-client Asynchronous Http Client 1.7.7-SNAPSHOT jar @@ -15,7 +15,7 @@ Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and asynchronously process the HTTP responses. - http://github.com/AsyncHttpClientasync-http-client + http://github.com/AsyncHttpClient/async-http-client scm:git:git@github.com:AsyncHttpClient/async-http-client.git https://github.com/AsyncHttpClient/async-http-client @@ -609,7 +609,7 @@ github - gitsite:git@github.com/AsyncHttpClientasync-http-client.git + gitsite:git@github.com/AsyncHttpClient/async-http-client.git From 76a150c996d6649f1a69e3c7d6750514b0bcc974 Mon Sep 17 00:00:00 2001 From: jfarcand Date: Mon, 5 Nov 2012 09:27:07 -0500 Subject: [PATCH 010/264] Fix for #160 --- .../http/client/providers/netty/NettyAsyncHttpProvider.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java index 5451baff1c..4b4c739f15 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java @@ -2397,7 +2397,8 @@ public void handle(ChannelHandlerContext ctx, MessageEvent e) throws Exception { final boolean statusReceived = h.onStatusReceived(s) == STATE.UPGRADE; if (!validStatus || !validUpgrade || !validConnection || !statusReceived) { - throw new IOException("Invalid handshake response"); + abort(future, new IOException("Invalid handshake response")); + return; } String accept = response.getHeader("Sec-WebSocket-Accept"); From 4669c7debbcf973c7bb8879252dd3c2409c22893 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20R=C3=A9mond?= Date: Thu, 2 Aug 2012 11:39:06 +0200 Subject: [PATCH 011/264] call getUrl() only once --- src/main/java/com/ning/http/client/RequestBuilderBase.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/ning/http/client/RequestBuilderBase.java b/src/main/java/com/ning/http/client/RequestBuilderBase.java index 9cc5ec40e0..c8411e0683 100644 --- a/src/main/java/com/ning/http/client/RequestBuilderBase.java +++ b/src/main/java/com/ning/http/client/RequestBuilderBase.java @@ -75,8 +75,9 @@ public RequestImpl(boolean useRawUrl) { public RequestImpl(Request prototype) { if (prototype != null) { this.method = prototype.getMethod(); - int pos = prototype.getUrl().indexOf("?"); - this.url = pos > 0 ? prototype.getUrl().substring(0, pos) : prototype.getUrl(); + String prototypeUrl = prototype.getUrl(); + int pos = prototypeUrl.indexOf("?"); + this.url = pos > 0 ? prototypeUrl.substring(0, pos) : prototypeUrl; this.address = prototype.getInetAddress(); this.localAddress = prototype.getLocalAddress(); this.headers = new FluentCaseInsensitiveStringsMap(prototype.getHeaders()); From b80589e80f36a248c8952760058b4de024c136d3 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 21 Aug 2012 08:12:55 +0200 Subject: [PATCH 012/264] Minor changes to AsyncHttpProviderUtils.convertExpireField * Make public so it can be used to parse Expires headers * compute trimmed unquoted String only once --- .../java/com/ning/http/util/AsyncHttpProviderUtils.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java index 5395998df8..30c30493d7 100644 --- a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java +++ b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java @@ -500,12 +500,14 @@ public static Cookie parseCookie(String value) { return new Cookie(domain, cookieName, cookieValue, path, maxAge, secure); } - private static int convertExpireField(String timestring) throws Exception { + public static int convertExpireField(String timestring) throws Exception { Exception exception = null; + String trimmedTimeString = removeQuote(timestring.trim()); + long now = System.currentTimeMillis(); for (SimpleDateFormat sdf : simpleDateFormat.get()) { try { - long expire = sdf.parse(removeQuote(timestring.trim())).getTime(); - return (int) ((expire - System.currentTimeMillis()) / 1000); + long expire = sdf.parse(trimmedTimeString).getTime(); + return (int) ((expire - now) / 1000); } catch (ParseException e) { exception = e; } catch (NumberFormatException e) { From 5785dfab357e5ab8632a8df6d4fd6a6d89ef9a89 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 10 Oct 2012 10:58:28 +0200 Subject: [PATCH 013/264] Make RequestImpl.toString also print params --- .../java/com/ning/http/client/RequestBuilderBase.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/main/java/com/ning/http/client/RequestBuilderBase.java b/src/main/java/com/ning/http/client/RequestBuilderBase.java index c8411e0683..b7470f0da6 100644 --- a/src/main/java/com/ning/http/client/RequestBuilderBase.java +++ b/src/main/java/com/ning/http/client/RequestBuilderBase.java @@ -293,12 +293,20 @@ public String toString() { sb.append("\t"); sb.append(method); + sb.append("\theaders:" for (String name : headers.keySet()) { sb.append("\t"); sb.append(name); sb.append(":"); sb.append(headers.getJoinedValue(name, ", ")); } + sb.append("\tparams:" + for (String name : params.keySet()) { + sb.append("\t"); + sb.append(name); + sb.append(":"); + sb.append(params.getJoinedValue(name, ", ")); + } return sb.toString(); } From 42b080579e546ebfc42473134c250c874b50386d Mon Sep 17 00:00:00 2001 From: Matthias Wessendorf Date: Thu, 11 Oct 2012 18:01:12 +0200 Subject: [PATCH 014/264] fixing compile error from 900a8da82475a2cd90f6a2443268d7dc935a61c1 --- src/main/java/com/ning/http/client/RequestBuilderBase.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/ning/http/client/RequestBuilderBase.java b/src/main/java/com/ning/http/client/RequestBuilderBase.java index b7470f0da6..60df9cec33 100644 --- a/src/main/java/com/ning/http/client/RequestBuilderBase.java +++ b/src/main/java/com/ning/http/client/RequestBuilderBase.java @@ -293,14 +293,14 @@ public String toString() { sb.append("\t"); sb.append(method); - sb.append("\theaders:" + sb.append("\theaders:"); for (String name : headers.keySet()) { sb.append("\t"); sb.append(name); sb.append(":"); sb.append(headers.getJoinedValue(name, ", ")); } - sb.append("\tparams:" + sb.append("\tparams:"); for (String name : params.keySet()) { sb.append("\t"); sb.append(name); From 4e3b5178241c7c170db252595e23838841452406 Mon Sep 17 00:00:00 2001 From: jfarcand Date: Mon, 5 Nov 2012 16:57:03 -0500 Subject: [PATCH 015/264] Port some fixes --- .../ning/http/client/RequestBuilderBase.java | 38 ++++++++++--------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/src/main/java/com/ning/http/client/RequestBuilderBase.java b/src/main/java/com/ning/http/client/RequestBuilderBase.java index 60df9cec33..7d4f843890 100644 --- a/src/main/java/com/ning/http/client/RequestBuilderBase.java +++ b/src/main/java/com/ning/http/client/RequestBuilderBase.java @@ -95,7 +95,7 @@ public RequestImpl(Request prototype) { this.proxyServer = prototype.getProxyServer(); this.realm = prototype.getRealm(); this.file = prototype.getFile(); - this.followRedirects = prototype.isRedirectOverrideSet()? prototype.isRedirectEnabled() : null; + this.followRedirects = prototype.isRedirectOverrideSet() ? prototype.isRedirectEnabled() : null; this.perRequestConfig = prototype.getPerRequestConfig(); this.rangeOffset = prototype.getRangeOffset(); this.charset = prototype.getBodyEncoding(); @@ -126,7 +126,7 @@ public InetAddress getInetAddress() { public InetAddress getLocalAddress() { return localAddress; } - + private String toUrl(boolean encode) { if (url == null) { @@ -271,7 +271,7 @@ public boolean isRedirectEnabled() { return (followRedirects != null && followRedirects); } - public boolean isRedirectOverrideSet(){ + public boolean isRedirectOverrideSet() { return followRedirects != null; } @@ -294,18 +294,22 @@ public String toString() { sb.append("\t"); sb.append(method); sb.append("\theaders:"); - for (String name : headers.keySet()) { - sb.append("\t"); - sb.append(name); - sb.append(":"); - sb.append(headers.getJoinedValue(name, ", ")); + if (headers != null && !headers.isEmpty()) { + for (String name : headers.keySet()) { + sb.append("\t"); + sb.append(name); + sb.append(":"); + sb.append(headers.getJoinedValue(name, ", ")); + } } - sb.append("\tparams:"); - for (String name : params.keySet()) { - sb.append("\t"); - sb.append(name); - sb.append(":"); - sb.append(params.getJoinedValue(name, ", ")); + if (params != null && !params.isEmpty()) { + sb.append("\tparams:"); + for (String name : params.keySet()) { + sb.append("\t"); + sb.append(name); + sb.append(":"); + sb.append(params.getJoinedValue(name, ", ")); + } } return sb.toString(); @@ -339,10 +343,10 @@ public T setUrl(String url) { } public T setInetAddress(InetAddress address) { - request.address = address; - return derived.cast(this); + request.address = address; + return derived.cast(this); } - + public T setLocalInetAddress(InetAddress address) { request.localAddress = address; return derived.cast(this); From 0000eb19bc86eac644175f8df131563aec2e19fa Mon Sep 17 00:00:00 2001 From: jfarcand Date: Fri, 9 Nov 2012 15:25:19 -0500 Subject: [PATCH 016/264] [maven-release-plugin] prepare release async-http-client-1.7.7 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 19a12c9e76..c56ade5b73 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.7.7-SNAPSHOT + 1.7.7 jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From e9e4df9a06f47dfc79a95811c94c78b656fb744d Mon Sep 17 00:00:00 2001 From: jfarcand Date: Fri, 9 Nov 2012 15:25:24 -0500 Subject: [PATCH 017/264] [maven-release-plugin] prepare for next development iteration --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index c56ade5b73..2940b903b9 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.7.7 + 1.7.8-SNAPSHOT jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From 0ab1e7d12fd0a3914ec9b21d135501dd88bac036 Mon Sep 17 00:00:00 2001 From: Brice Dutheil Date: Wed, 21 Nov 2012 20:21:13 +0100 Subject: [PATCH 018/264] Offer a way to configure the max header size in Grizzly --- .../grizzly/GrizzlyAsyncHttpProvider.java | 20 ++++++++++--------- .../GrizzlyAsyncHttpProviderConfig.java | 13 +++++++++++- 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java index a29bfea4b7..6924a5aa96 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java @@ -51,7 +51,6 @@ import com.ning.http.util.AuthenticatorUtils; import com.ning.http.util.ProxyUtils; import com.ning.http.util.SslUtils; - import org.glassfish.grizzly.Buffer; import org.glassfish.grizzly.CompletionHandler; import org.glassfish.grizzly.Connection; @@ -77,13 +76,12 @@ import org.glassfish.grizzly.http.HttpResponsePacket; import org.glassfish.grizzly.http.Method; import org.glassfish.grizzly.http.Protocol; -import org.glassfish.grizzly.impl.FutureImpl; -import org.glassfish.grizzly.utils.Charsets; import org.glassfish.grizzly.http.util.CookieSerializerUtils; import org.glassfish.grizzly.http.util.DataChunk; import org.glassfish.grizzly.http.util.Header; import org.glassfish.grizzly.http.util.HttpStatus; import org.glassfish.grizzly.http.util.MimeHeaders; +import org.glassfish.grizzly.impl.FutureImpl; import org.glassfish.grizzly.impl.SafeFutureImpl; import org.glassfish.grizzly.memory.Buffers; import org.glassfish.grizzly.memory.MemoryManager; @@ -95,6 +93,7 @@ import org.glassfish.grizzly.strategies.SameThreadIOStrategy; import org.glassfish.grizzly.strategies.WorkerThreadIOStrategy; import org.glassfish.grizzly.utils.BufferOutputStream; +import org.glassfish.grizzly.utils.Charsets; import org.glassfish.grizzly.utils.DelayedExecutor; import org.glassfish.grizzly.utils.Futures; import org.glassfish.grizzly.utils.IdleTimeoutFilter; @@ -135,6 +134,7 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; +import static com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProviderConfig.Property.MAX_HTTP_PACKET_HEADER_SIZE; import static com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProviderConfig.Property.TRANSPORT_CUSTOMIZER; /** @@ -370,8 +370,12 @@ public void onTimeout(Connection connection) { false); final SwitchingSSLFilter filter = new SwitchingSSLFilter(configurator, defaultSecState); fcb.add(filter); + final GrizzlyAsyncHttpProviderConfig providerConfig = + clientConfig.getAsyncHttpProviderConfig() instanceof GrizzlyAsyncHttpProviderConfig ? + (GrizzlyAsyncHttpProviderConfig) clientConfig.getAsyncHttpProviderConfig() + : new GrizzlyAsyncHttpProviderConfig(); final AsyncHttpClientEventFilter eventFilter = new - AsyncHttpClientEventFilter(this); + AsyncHttpClientEventFilter(this, (Integer) providerConfig.getProperty(MAX_HTTP_PACKET_HEADER_SIZE)); final AsyncHttpClientFilter clientFilter = new AsyncHttpClientFilter(clientConfig); ContentEncoding[] encodings = eventFilter.getContentEncodings(); @@ -389,8 +393,6 @@ public void onTimeout(Connection connection) { fcb.add(eventFilter); fcb.add(clientFilter); - GrizzlyAsyncHttpProviderConfig providerConfig = - (GrizzlyAsyncHttpProviderConfig) clientConfig.getAsyncHttpProviderConfig(); if (providerConfig != null) { final TransportCustomizer customizer = (TransportCustomizer) providerConfig.getProperty(TRANSPORT_CUSTOMIZER); @@ -1069,15 +1071,15 @@ private static final class AsyncHttpClientEventFilter extends HttpClientFilter { private final GrizzlyAsyncHttpProvider provider; - // -------------------------------------------------------- Constructors - AsyncHttpClientEventFilter(final GrizzlyAsyncHttpProvider provider) { + AsyncHttpClientEventFilter(final GrizzlyAsyncHttpProvider provider, int maxHerdersSizeProperty) { + super(maxHerdersSizeProperty); this.provider = provider; HANDLER_MAP.put(HttpStatus.UNAUTHORIZED_401.getStatusCode(), - AuthorizationHandler.INSTANCE); + AuthorizationHandler.INSTANCE); HANDLER_MAP.put(HttpStatus.MOVED_PERMANENTLY_301.getStatusCode(), RedirectHandler.INSTANCE); HANDLER_MAP.put(HttpStatus.FOUND_302.getStatusCode(), diff --git a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProviderConfig.java b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProviderConfig.java index 70b7425391..8751195bbd 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProviderConfig.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProviderConfig.java @@ -14,6 +14,7 @@ package com.ning.http.client.providers.grizzly; import com.ning.http.client.AsyncHttpProviderConfig; +import org.glassfish.grizzly.http.HttpCodecFilter; import org.glassfish.grizzly.nio.transport.TCPNIOTransport; import java.util.HashMap; @@ -49,7 +50,17 @@ public static enum Property { * * @see TransportCustomizer */ - TRANSPORT_CUSTOMIZER(TransportCustomizer.class); + TRANSPORT_CUSTOMIZER(TransportCustomizer.class), + + + /** + * Defines the maximum HTTP packet header size. + */ + MAX_HTTP_PACKET_HEADER_SIZE(Integer.class, HttpCodecFilter.DEFAULT_MAX_HTTP_PACKET_HEADER_SIZE), + + + + ; final Object defaultValue; From debbfd5008bd3b63586b01da6fb26fc7c1ffc5f7 Mon Sep 17 00:00:00 2001 From: James Roper Date: Tue, 27 Nov 2012 11:26:07 +1100 Subject: [PATCH 019/264] Fixed nonProxyHosts handling for SSL hosts --- .../grizzly/GrizzlyAsyncHttpProvider.java | 18 ++++++++---------- .../netty/NettyAsyncHttpProvider.java | 18 ++++++++++++++---- .../client/async/ProxyyTunnellingTest.java | 17 +++++++++++++++++ 3 files changed, 39 insertions(+), 14 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java index 6924a5aa96..a4ee140e75 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java @@ -855,7 +855,8 @@ private boolean sendAsGrizzlyRequest(final Request request, } } final ProxyServer proxy = getProxyServer(request); - final boolean useProxy = (proxy != null); + boolean avoidProxy = ProxyUtils.avoidProxy(proxy, request); + final boolean useProxy = !(avoidProxy || proxy == null); if (useProxy) { if ((secure || httpCtx.isWSRequest) && !httpCtx.isTunnelEstablished(ctx.getConnection())) { secure = false; @@ -903,16 +904,13 @@ private boolean sendAsGrizzlyRequest(final Request request, addCookies(request, requestPacket); if (useProxy) { - boolean avoidProxy = ProxyUtils.avoidProxy(proxy, request); - if (!avoidProxy) { - if (!requestPacket.getHeaders().contains(Header.ProxyConnection)) { - requestPacket.setHeader(Header.ProxyConnection, "keep-alive"); - } + if (!requestPacket.getHeaders().contains(Header.ProxyConnection)) { + requestPacket.setHeader(Header.ProxyConnection, "keep-alive"); + } - if (proxy.getPrincipal() != null) { - requestPacket.setHeader(Header.ProxyAuthorization, - AuthenticatorUtils.computeBasicAuthentication(proxy)); - } + if (proxy.getPrincipal() != null) { + requestPacket.setHeader(Header.ProxyAuthorization, + AuthenticatorUtils.computeBasicAuthentication(proxy)); } } final AsyncHandler h = httpCtx.handler; diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java index 4b4c739f15..a7595dbb17 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java @@ -578,7 +578,15 @@ public void operationComplete(ChannelFuture cf) { } private static boolean isProxyServer(AsyncHttpClientConfig config, Request request) { - return request.getProxyServer() != null || config.getProxyServer() != null; + ProxyServer proxyServer = request.getProxyServer(); + if (proxyServer == null) { + proxyServer = config.getProxyServer(); + } + if (proxyServer == null) { + return false; + } else { + return !ProxyUtils.avoidProxy(proxyServer, request); + } } protected final static HttpRequest buildRequest(AsyncHttpClientConfig config, Request request, URI uri, @@ -951,7 +959,10 @@ private ListenableFuture doConnect(final Request request, final AsyncHand bufferedBytes = f.getNettyRequest().getContent(); } - boolean useSSl = isSecure(uri) && proxyServer == null; + boolean avoidProxy = ProxyUtils.avoidProxy(proxyServer, uri.getHost()); + boolean useProxy = !(avoidProxy || proxyServer == null); + + boolean useSSl = isSecure(uri) && !useProxy; if (channel != null && channel.isOpen() && channel.isConnected()) { HttpRequest nettyRequest = buildRequest(config, request, uri, f == null ? false : f.isConnectAllowed(), bufferedBytes); @@ -1018,7 +1029,6 @@ private ListenableFuture doConnect(final Request request, final AsyncHand } NettyConnectListener c = new NettyConnectListener.Builder(config, request, asyncHandler, f, this, bufferedBytes).build(uri); - boolean avoidProxy = ProxyUtils.avoidProxy(proxyServer, uri.getHost()); if (useSSl) { constructSSLPipeline(c); @@ -1037,7 +1047,7 @@ private ListenableFuture doConnect(final Request request, final AsyncHand InetSocketAddress remoteAddress; if (request.getInetAddress() != null) { remoteAddress = new InetSocketAddress(request.getInetAddress(), AsyncHttpProviderUtils.getPort(uri)); - } else if (proxyServer == null || avoidProxy) { + } else if (!useProxy) { remoteAddress = new InetSocketAddress(AsyncHttpProviderUtils.getHost(uri), AsyncHttpProviderUtils.getPort(uri)); } else { remoteAddress = new InetSocketAddress(proxyServer.getHost(), proxyServer.getPort()); diff --git a/src/test/java/com/ning/http/client/async/ProxyyTunnellingTest.java b/src/test/java/com/ning/http/client/async/ProxyyTunnellingTest.java index 08d596ae0c..9d5bb3ed28 100644 --- a/src/test/java/com/ning/http/client/async/ProxyyTunnellingTest.java +++ b/src/test/java/com/ning/http/client/async/ProxyyTunnellingTest.java @@ -28,11 +28,13 @@ import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; +import javax.servlet.http.HttpServletResponse; import java.io.File; import java.io.IOException; import java.net.URL; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import static org.testng.Assert.assertEquals; @@ -166,5 +168,20 @@ public void testSimpleAHCConfigProxy() throws IOException, InterruptedException, client.close(); } + + @Test(groups = { "standalone", "default_provider" }) + public void testNonProxyHostsSsl() throws IOException, ExecutionException, TimeoutException, InterruptedException { + AsyncHttpClient client = getAsyncHttpClient(null); + + Response resp = client.prepareGet(getTargetUrl2()).setProxyServer(new ProxyServer("127.0.0.1", port1 - 1) + .addNonProxyHost("127.0.0.1")) + .execute().get(3, TimeUnit.SECONDS); + + assertNotNull(resp); + assertEquals(resp.getStatusCode(), HttpServletResponse.SC_OK); + assertEquals(resp.getHeader("X-pathInfo"), "/foo/test"); + + client.close(); + } } From e48bf0ba9a7839c5f765f31702ac05f45b259219 Mon Sep 17 00:00:00 2001 From: jfarcand Date: Thu, 29 Nov 2012 17:25:25 -0500 Subject: [PATCH 020/264] Port for for #138 --- src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java index 30c30493d7..718dee9f35 100644 --- a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java +++ b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java @@ -448,7 +448,7 @@ public static String parseCharset(String contentType) { public static Cookie parseCookie(String value) { String[] fields = value.split(";\\s*"); - String[] cookie = fields[0].split("="); + String[] cookie = fields[0].split("=", 2); String cookieName = cookie[0]; String cookieValue = (cookie.length == 1) ? null : cookie[1]; From dd798e0aa284202a347b70a67067ba51a710dcc4 Mon Sep 17 00:00:00 2001 From: jfarcand Date: Thu, 29 Nov 2012 17:26:12 -0500 Subject: [PATCH 021/264] [maven-release-plugin] prepare release async-http-client-1.7.8 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 2940b903b9..cd16ba5aaf 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.7.8-SNAPSHOT + 1.7.8 jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From 0f7611c0a548e1c2f3899d421b24879ab501215f Mon Sep 17 00:00:00 2001 From: jfarcand Date: Thu, 29 Nov 2012 17:26:17 -0500 Subject: [PATCH 022/264] [maven-release-plugin] prepare for next development iteration --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index cd16ba5aaf..c1e7f6f280 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.7.8 + 1.7.9-SNAPSHOT jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From 96193043b6d5256494f4084b6b87fbde8c32d33c Mon Sep 17 00:00:00 2001 From: Ross Mellgren Date: Mon, 3 Dec 2012 17:01:27 -0500 Subject: [PATCH 023/264] fix #173 by returning -1 on EOF, not 0 --- .../java/com/ning/http/multipart/MultipartBody.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/ning/http/multipart/MultipartBody.java b/src/main/java/com/ning/http/multipart/MultipartBody.java index 88ee5da2ea..c3004e469f 100644 --- a/src/main/java/com/ning/http/multipart/MultipartBody.java +++ b/src/main/java/com/ning/http/multipart/MultipartBody.java @@ -80,7 +80,7 @@ public long read(ByteBuffer buffer) throws IOException { int maxLength = buffer.capacity(); if (startPart == parts.size() && endWritten) { - return overallLength; + return -1; } boolean full = false; @@ -437,9 +437,9 @@ private ByteArrayOutputStream generateFileStart(FilePart filePart) private long handleFilePart(WritableByteChannel target, FilePart filePart) throws IOException { FilePartStallHandler handler = new FilePartStallHandler( filePart.getStalledTime(), filePart); - + handler.start(); - + if (FilePartSource.class.isAssignableFrom(filePart.getSource().getClass())) { int length = 0; @@ -464,7 +464,7 @@ private long handleFilePart(WritableByteChannel target, FilePart filePart) throw } try { nWrite = fc.transferTo(fileLength, l, target); - + if (nWrite == 0) { logger.info("Waiting for writing..."); try { @@ -496,7 +496,7 @@ private long handleFilePart(WritableByteChannel target, FilePart filePart) throw } } handler.completed(); - + fc.close(); length += handleFileEnd(target, filePart); @@ -556,7 +556,7 @@ private long handleMultiPart(WritableByteChannel target, Part currentPart) throw return handleStringPart(target, (StringPart) currentPart); } else if (currentPart.getClass().equals(FilePart.class)) { FilePart filePart = (FilePart) currentPart; - + return handleFilePart(target, filePart); } return 0; From 4beb34d2602e980917c4ef8e1becdf8229ba2867 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 18 Dec 2012 00:07:29 +0100 Subject: [PATCH 024/264] Fix proposal for #182 against 1.7.x --- .../providers/apache/ApacheResponse.java | 23 ++++--------------- .../client/providers/jdk/JDKResponse.java | 23 ++++--------------- .../client/providers/netty/NettyResponse.java | 23 ++++--------------- 3 files changed, 15 insertions(+), 54 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/apache/ApacheResponse.java b/src/main/java/com/ning/http/client/providers/apache/ApacheResponse.java index 9516f89ee4..3fe9cd81b3 100644 --- a/src/main/java/com/ning/http/client/providers/apache/ApacheResponse.java +++ b/src/main/java/com/ning/http/client/providers/apache/ApacheResponse.java @@ -35,7 +35,6 @@ public class ApacheResponse implements Response { private final static String DEFAULT_CHARSET = "ISO-8859-1"; - private final static String HEADERS_NOT_COMPUTED = "Response's headers hasn't been computed by your AsyncHandler."; private final URI uri; private final Collection bodyParts; @@ -129,37 +128,25 @@ public URI getUri() throws MalformedURLException { /* @Override */ public String getContentType() { - if (headers == null) { - throw new IllegalStateException(HEADERS_NOT_COMPUTED); - } - return headers.getHeaders().getFirstValue("Content-Type"); + return headers != null? headers.getHeaders().getFirstValue("Content-Type"): null; } /* @Override */ public String getHeader(String name) { - if (headers == null) { - throw new IllegalStateException(); - } - return headers.getHeaders().getFirstValue(name); + return headers != null? headers.getHeaders().getFirstValue(name): null; } /* @Override */ public List getHeaders(String name) { - if (headers == null) { - throw new IllegalStateException(HEADERS_NOT_COMPUTED); - } - return headers.getHeaders().get(name); + return headers != null? headers.getHeaders().get(name): Collections. emptyList(); } /* @Override */ public FluentCaseInsensitiveStringsMap getHeaders() { - if (headers == null) { - throw new IllegalStateException(HEADERS_NOT_COMPUTED); - } - return headers.getHeaders(); + return headers != null? headers.getHeaders(): new FluentCaseInsensitiveStringsMap(); } /* @Override */ @@ -172,7 +159,7 @@ public boolean isRedirected() { public List getCookies() { if (headers == null) { - throw new IllegalStateException(HEADERS_NOT_COMPUTED); + return Collections.emptyList(); } if (cookies.isEmpty()) { for (Map.Entry> header : headers.getHeaders().entrySet()) { diff --git a/src/main/java/com/ning/http/client/providers/jdk/JDKResponse.java b/src/main/java/com/ning/http/client/providers/jdk/JDKResponse.java index f1fd4d2ce1..392b99a44e 100644 --- a/src/main/java/com/ning/http/client/providers/jdk/JDKResponse.java +++ b/src/main/java/com/ning/http/client/providers/jdk/JDKResponse.java @@ -36,7 +36,6 @@ public class JDKResponse implements Response { private final static String DEFAULT_CHARSET = "ISO-8859-1"; - private final static String HEADERS_NOT_COMPUTED = "Response's headers hasn't been computed by your AsyncHandler."; private final URI uri; private final Collection bodyParts; @@ -141,37 +140,25 @@ public URI getUri() throws MalformedURLException { /* @Override */ public String getContentType() { - if (headers == null) { - throw new IllegalStateException(HEADERS_NOT_COMPUTED); - } - return headers.getHeaders().getFirstValue("Content-Type"); + return headers != null? headers.getHeaders().getFirstValue("Content-Type"): null; } /* @Override */ public String getHeader(String name) { - if (headers == null) { - throw new IllegalStateException(); - } - return headers.getHeaders().getFirstValue(name); + return headers != null? headers.getHeaders().getFirstValue(name): null; } /* @Override */ public List getHeaders(String name) { - if (headers == null) { - throw new IllegalStateException(HEADERS_NOT_COMPUTED); - } - return headers.getHeaders().get(name); + return headers != null? headers.getHeaders().get(name): Collections. emptyList(); } /* @Override */ public FluentCaseInsensitiveStringsMap getHeaders() { - if (headers == null) { - throw new IllegalStateException(HEADERS_NOT_COMPUTED); - } - return headers.getHeaders(); + return headers != null? headers.getHeaders(): new FluentCaseInsensitiveStringsMap(); } /* @Override */ @@ -184,7 +171,7 @@ public boolean isRedirected() { public List getCookies() { if (headers == null) { - throw new IllegalStateException(HEADERS_NOT_COMPUTED); + return Collections.emptyList(); } if (cookies.isEmpty()) { for (Map.Entry> header : headers.getHeaders().entrySet()) { diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyResponse.java b/src/main/java/com/ning/http/client/providers/netty/NettyResponse.java index 5af231d626..12d41f9993 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyResponse.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyResponse.java @@ -41,7 +41,6 @@ */ public class NettyResponse implements Response { private final static String DEFAULT_CHARSET = "ISO-8859-1"; - private final static String HEADERS_NOT_COMPUTED = "Response's headers hasn't been computed by your AsyncHandler."; private final URI uri; private final Collection bodyParts; @@ -138,37 +137,25 @@ public URI getUri() throws MalformedURLException { /* @Override */ public String getContentType() { - if (headers == null) { - throw new IllegalStateException(HEADERS_NOT_COMPUTED); - } - return headers.getHeaders().getFirstValue("Content-Type"); + return headers != null? headers.getHeaders().getFirstValue("Content-Type"): null; } /* @Override */ public String getHeader(String name) { - if (headers == null) { - throw new IllegalStateException(); - } - return headers.getHeaders().getFirstValue(name); + return headers != null? headers.getHeaders().getFirstValue(name): null; } /* @Override */ public List getHeaders(String name) { - if (headers == null) { - throw new IllegalStateException(HEADERS_NOT_COMPUTED); - } - return headers.getHeaders().get(name); + return headers != null? headers.getHeaders().get(name): Collections. emptyList(); } /* @Override */ public FluentCaseInsensitiveStringsMap getHeaders() { - if (headers == null) { - throw new IllegalStateException(HEADERS_NOT_COMPUTED); - } - return headers.getHeaders(); + return headers != null? headers.getHeaders(): new FluentCaseInsensitiveStringsMap(); } /* @Override */ @@ -181,7 +168,7 @@ public boolean isRedirected() { public List getCookies() { if (headers == null) { - throw new IllegalStateException(HEADERS_NOT_COMPUTED); + return Collections.emptyList(); } if (cookies.isEmpty()) { for (Map.Entry> header : headers.getHeaders().entrySet()) { From c1c4bd130e837c820fc2df0b44f1e95b9fb772e2 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 18 Dec 2012 00:18:22 +0100 Subject: [PATCH 025/264] Minor clean up --- .../providers/apache/ApacheResponse.java | 24 ++++++------ .../providers/grizzly/GrizzlyResponse.java | 2 +- .../client/providers/jdk/JDKResponse.java | 29 ++++++++------- .../client/providers/netty/NettyResponse.java | 37 ++++++++----------- 4 files changed, 45 insertions(+), 47 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/apache/ApacheResponse.java b/src/main/java/com/ning/http/client/providers/apache/ApacheResponse.java index 3fe9cd81b3..b5d31083f8 100644 --- a/src/main/java/com/ning/http/client/providers/apache/ApacheResponse.java +++ b/src/main/java/com/ning/http/client/providers/apache/ApacheResponse.java @@ -76,16 +76,18 @@ public String getResponseBody() throws IOException { } public String getResponseBody(String charset) throws IOException { - String contentType = getContentType(); - if (contentType != null && charset == null) { - charset = AsyncHttpProviderUtils.parseCharset(contentType); - } - + return AsyncHttpProviderUtils.contentToString(bodyParts, computeCharset(charset)); + } + + private String computeCharset(String charset) { + String contentType = getContentType(); if (charset == null) { - charset = DEFAULT_CHARSET; + if (contentType != null) + charset = AsyncHttpProviderUtils.parseCharset(contentType); + else + charset = DEFAULT_CHARSET; } - - return AsyncHttpProviderUtils.contentToString(bodyParts, charset); + return charset; } /* @Override */ @@ -181,7 +183,7 @@ public List getCookies() { */ /* @Override */ public boolean hasResponseStatus() { - return (bodyParts != null ? true : false); + return bodyParts != null; } /** @@ -189,7 +191,7 @@ public boolean hasResponseStatus() { */ /* @Override */ public boolean hasResponseHeaders() { - return (headers != null ? true : false); + return headers != null; } /** @@ -197,6 +199,6 @@ public boolean hasResponseHeaders() { */ /* @Override */ public boolean hasResponseBody() { - return (bodyParts != null && bodyParts.size() > 0 ? true : false); + return bodyParts != null && bodyParts.size() > 0; } } diff --git a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponse.java b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponse.java index 52f3fece36..1f0b52784d 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponse.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponse.java @@ -257,7 +257,7 @@ public List getCookies() { cookies = convertCookies(builder.build()); } else { - cookies = Collections.unmodifiableList(Collections.emptyList()); + cookies = Collections.emptyList(); } } return cookies; diff --git a/src/main/java/com/ning/http/client/providers/jdk/JDKResponse.java b/src/main/java/com/ning/http/client/providers/jdk/JDKResponse.java index 392b99a44e..5854a12126 100644 --- a/src/main/java/com/ning/http/client/providers/jdk/JDKResponse.java +++ b/src/main/java/com/ning/http/client/providers/jdk/JDKResponse.java @@ -80,20 +80,23 @@ public byte[] getResponseBodyAsBytes() throws IOException { } public String getResponseBody(String charset) throws IOException { - String contentType = getContentType(); - if (contentType != null && charset == null) { - charset = AsyncHttpProviderUtils.parseCharset(contentType); - } - - if (charset == null) { - charset = DEFAULT_CHARSET; - } - if (!contentComputed.get()) { - content = AsyncHttpProviderUtils.contentToString(bodyParts, charset); + if (!contentComputed.get()) { + content = AsyncHttpProviderUtils.contentToString(bodyParts, computeCharset(charset)); } return content; } + + private String computeCharset(String charset) { + String contentType = getContentType(); + if (charset == null) { + if (contentType != null) + charset = AsyncHttpProviderUtils.parseCharset(contentType); + else + charset = DEFAULT_CHARSET; + } + return charset; + } /* @Override */ public InputStream getResponseBodyAsStream() throws IOException { @@ -193,7 +196,7 @@ public List getCookies() { */ /* @Override */ public boolean hasResponseStatus() { - return (bodyParts != null ? true : false); + return bodyParts != null; } /** @@ -201,7 +204,7 @@ public boolean hasResponseStatus() { */ /* @Override */ public boolean hasResponseHeaders() { - return (headers != null ? true : false); + return headers != null; } /** @@ -209,6 +212,6 @@ public boolean hasResponseHeaders() { */ /* @Override */ public boolean hasResponseBody() { - return (bodyParts != null && bodyParts.size() > 0 ? true : false); + return bodyParts != null && bodyParts.size() > 0; } } diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyResponse.java b/src/main/java/com/ning/http/client/providers/netty/NettyResponse.java index 12d41f9993..28f9eab2b6 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyResponse.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyResponse.java @@ -81,16 +81,7 @@ public String getResponseBody() throws IOException { } public String getResponseBody(String charset) throws IOException { - String contentType = getContentType(); - if (contentType != null && charset == null) { - charset = AsyncHttpProviderUtils.parseCharset(contentType); - } - - if (charset == null) { - charset = DEFAULT_CHARSET; - } - - return AsyncHttpProviderUtils.contentToString(bodyParts, charset); + return AsyncHttpProviderUtils.contentToString(bodyParts, computeCharset(charset)); } /* @Override */ @@ -115,17 +106,19 @@ public String getResponseBodyExcerpt(int maxLength) throws IOException { } public String getResponseBodyExcerpt(int maxLength, String charset) throws IOException { - String contentType = getContentType(); - if (contentType != null && charset == null) { - charset = AsyncHttpProviderUtils.parseCharset(contentType); - } - + String response = AsyncHttpProviderUtils.contentToString(bodyParts, computeCharset(charset)); + return response.length() <= maxLength ? response : response.substring(0, maxLength); + } + + private String computeCharset(String charset) { + String contentType = getContentType(); if (charset == null) { - charset = DEFAULT_CHARSET; + if (contentType != null) + charset = AsyncHttpProviderUtils.parseCharset(contentType); + else + charset = DEFAULT_CHARSET; } - - String response = AsyncHttpProviderUtils.contentToString(bodyParts, charset); - return response.length() <= maxLength ? response : response.substring(0, maxLength); + return charset; } /* @Override */ @@ -190,7 +183,7 @@ public List getCookies() { */ /* @Override */ public boolean hasResponseStatus() { - return (status != null ? true : false); + return status != null; } /** @@ -198,7 +191,7 @@ public boolean hasResponseStatus() { */ /* @Override */ public boolean hasResponseHeaders() { - return (headers != null ? true : false); + return headers != null; } /** @@ -206,7 +199,7 @@ public boolean hasResponseHeaders() { */ /* @Override */ public boolean hasResponseBody() { - return (bodyParts != null && bodyParts.size() > 0 ? true : false); + return bodyParts != null && bodyParts.size() > 0; } } From 39cb971635c02473662373ece9cb4a85343f01ba Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 18 Dec 2012 01:02:18 +0100 Subject: [PATCH 026/264] Minor clean up --- .../providers/apache/ApacheResponse.java | 47 +++++++++---------- .../client/providers/jdk/JDKResponse.java | 45 ++++++++---------- .../client/providers/netty/NettyResponse.java | 14 +++--- 3 files changed, 49 insertions(+), 57 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/apache/ApacheResponse.java b/src/main/java/com/ning/http/client/providers/apache/ApacheResponse.java index b5d31083f8..2cdf19f629 100644 --- a/src/main/java/com/ning/http/client/providers/apache/ApacheResponse.java +++ b/src/main/java/com/ning/http/client/providers/apache/ApacheResponse.java @@ -40,7 +40,7 @@ public class ApacheResponse implements Response { private final Collection bodyParts; private final HttpResponseHeaders headers; private final HttpResponseStatus status; - private final List cookies = new ArrayList(); + private List cookies; public ApacheResponse(HttpResponseStatus status, HttpResponseHeaders headers, @@ -79,20 +79,9 @@ public String getResponseBody(String charset) throws IOException { return AsyncHttpProviderUtils.contentToString(bodyParts, computeCharset(charset)); } - private String computeCharset(String charset) { - String contentType = getContentType(); - if (charset == null) { - if (contentType != null) - charset = AsyncHttpProviderUtils.parseCharset(contentType); - else - charset = DEFAULT_CHARSET; - } - return charset; - } - /* @Override */ public InputStream getResponseBodyAsStream() throws IOException { - if (bodyParts.size() > 0) { + if (!bodyParts.isEmpty()) { return new HttpResponseBodyPartsInputStream(bodyParts.toArray(new HttpResponseBodyPart[bodyParts.size()])); } else { return new ByteArrayInputStream("".getBytes()); @@ -108,18 +97,22 @@ public String getResponseBodyExcerpt(int maxLength) throws IOException { /* @Override */ public String getResponseBodyExcerpt(int maxLength, String charset) throws IOException { - String contentType = getContentType(); - if (contentType != null && charset == null) { - charset = AsyncHttpProviderUtils.parseCharset(contentType); - } - - if (charset == null) { - charset = DEFAULT_CHARSET; - } + charset = computeCharset(charset); String response = AsyncHttpProviderUtils.contentToString(bodyParts, charset); return response.length() <= maxLength ? response : response.substring(0, maxLength); } + + private String computeCharset(String charset) { + String contentType = getContentType(); + if (charset == null) { + if (contentType != null) + charset = AsyncHttpProviderUtils.parseCharset(contentType); + else + charset = DEFAULT_CHARSET; + } + return charset; + } /* @Override */ @@ -130,7 +123,7 @@ public URI getUri() throws MalformedURLException { /* @Override */ public String getContentType() { - return headers != null? headers.getHeaders().getFirstValue("Content-Type"): null; + return getHeader("Content-Type"); } /* @Override */ @@ -163,19 +156,21 @@ public List getCookies() { if (headers == null) { return Collections.emptyList(); } - if (cookies.isEmpty()) { + if (cookies == null) { + List localCookies = new ArrayList(); for (Map.Entry> header : headers.getHeaders().entrySet()) { if (header.getKey().equalsIgnoreCase("Set-Cookie")) { // TODO: ask for parsed header List v = header.getValue(); for (String value : v) { Cookie cookie = AsyncHttpProviderUtils.parseCookie(value); - cookies.add(cookie); + localCookies.add(cookie); } } } + cookies = Collections.unmodifiableList(localCookies); } - return Collections.unmodifiableList(cookies); + return cookies; } /** @@ -199,6 +194,6 @@ public boolean hasResponseHeaders() { */ /* @Override */ public boolean hasResponseBody() { - return bodyParts != null && bodyParts.size() > 0; + return bodyParts != null && !bodyParts.isEmpty(); } } diff --git a/src/main/java/com/ning/http/client/providers/jdk/JDKResponse.java b/src/main/java/com/ning/http/client/providers/jdk/JDKResponse.java index 5854a12126..36700fde8d 100644 --- a/src/main/java/com/ning/http/client/providers/jdk/JDKResponse.java +++ b/src/main/java/com/ning/http/client/providers/jdk/JDKResponse.java @@ -41,7 +41,7 @@ public class JDKResponse implements Response { private final Collection bodyParts; private final HttpResponseHeaders headers; private final HttpResponseStatus status; - private final List cookies = new ArrayList(); + private List cookies; private AtomicBoolean contentComputed = new AtomicBoolean(false); private String content; @@ -87,24 +87,13 @@ public String getResponseBody(String charset) throws IOException { return content; } - private String computeCharset(String charset) { - String contentType = getContentType(); - if (charset == null) { - if (contentType != null) - charset = AsyncHttpProviderUtils.parseCharset(contentType); - else - charset = DEFAULT_CHARSET; - } - return charset; - } - /* @Override */ public InputStream getResponseBodyAsStream() throws IOException { if (contentComputed.get()) { return new ByteArrayInputStream(content.getBytes(DEFAULT_CHARSET)); } - if (bodyParts.size() > 0) { + if (!bodyParts.isEmpty()) { return new HttpResponseBodyPartsInputStream(bodyParts.toArray(new HttpResponseBodyPart[bodyParts.size()])); } else { return new ByteArrayInputStream("".getBytes()); @@ -118,14 +107,7 @@ public String getResponseBodyExcerpt(int maxLength) throws IOException { } public String getResponseBodyExcerpt(int maxLength, String charset) throws IOException { - String contentType = getContentType(); - if (contentType != null && charset == null) { - charset = AsyncHttpProviderUtils.parseCharset(contentType); - } - - if (charset == null) { - charset = DEFAULT_CHARSET; - } + charset = computeCharset(charset); if (!contentComputed.get()) { content = AsyncHttpProviderUtils.contentToString(bodyParts, charset == null ? DEFAULT_CHARSET : charset); @@ -133,6 +115,17 @@ public String getResponseBodyExcerpt(int maxLength, String charset) throws IOExc return content.length() <= maxLength ? content : content.substring(0, maxLength); } + + private String computeCharset(String charset) { + String contentType = getContentType(); + if (charset == null) { + if (contentType != null) + charset = AsyncHttpProviderUtils.parseCharset(contentType); + else + charset = DEFAULT_CHARSET; + } + return charset; + } /* @Override */ @@ -143,7 +136,7 @@ public URI getUri() throws MalformedURLException { /* @Override */ public String getContentType() { - return headers != null? headers.getHeaders().getFirstValue("Content-Type"): null; + return getHeader("Content-Type"); } /* @Override */ @@ -177,18 +170,20 @@ public List getCookies() { return Collections.emptyList(); } if (cookies.isEmpty()) { + List localCookies = new ArrayList(); for (Map.Entry> header : headers.getHeaders().entrySet()) { if (header.getKey().equalsIgnoreCase("Set-Cookie")) { // TODO: ask for parsed header List v = header.getValue(); for (String value : v) { Cookie cookie = AsyncHttpProviderUtils.parseCookie(value); - cookies.add(cookie); + localCookies.add(cookie); } } } + cookies = Collections.unmodifiableList(localCookies); } - return Collections.unmodifiableList(cookies); + return cookies; } /** @@ -212,6 +207,6 @@ public boolean hasResponseHeaders() { */ /* @Override */ public boolean hasResponseBody() { - return bodyParts != null && bodyParts.size() > 0; + return bodyParts != null && !bodyParts.isEmpty(); } } diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyResponse.java b/src/main/java/com/ning/http/client/providers/netty/NettyResponse.java index 28f9eab2b6..01c61d0165 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyResponse.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyResponse.java @@ -46,7 +46,7 @@ public class NettyResponse implements Response { private final Collection bodyParts; private final HttpResponseHeaders headers; private final HttpResponseStatus status; - private final List cookies = new ArrayList(); + private List cookies; public NettyResponse(HttpResponseStatus status, HttpResponseHeaders headers, @@ -130,7 +130,7 @@ public URI getUri() throws MalformedURLException { /* @Override */ public String getContentType() { - return headers != null? headers.getHeaders().getFirstValue("Content-Type"): null; + return getHeader("Content-Type"); } /* @Override */ @@ -163,19 +163,21 @@ public List getCookies() { if (headers == null) { return Collections.emptyList(); } - if (cookies.isEmpty()) { + if (cookies == null) { + List localCookies = new ArrayList(); for (Map.Entry> header : headers.getHeaders().entrySet()) { if (header.getKey().equalsIgnoreCase("Set-Cookie")) { // TODO: ask for parsed header List v = header.getValue(); for (String value : v) { Cookie cookie = AsyncHttpProviderUtils.parseCookie(value); - cookies.add(cookie); + localCookies.add(cookie); } } } + cookies = Collections.unmodifiableList(localCookies); } - return Collections.unmodifiableList(cookies); + return cookies; } /** @@ -199,7 +201,7 @@ public boolean hasResponseHeaders() { */ /* @Override */ public boolean hasResponseBody() { - return bodyParts != null && bodyParts.size() > 0; + return bodyParts != null && !bodyParts.isEmpty(); } } From 27e60537d8b08fc3f18ef8c446fbf3c1ffb0793b Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 18 Dec 2012 10:58:40 +0100 Subject: [PATCH 027/264] Fix charset computation when it's not specified in contentType --- .../ning/http/client/providers/apache/ApacheResponse.java | 8 +++----- .../com/ning/http/client/providers/jdk/JDKResponse.java | 8 +++----- .../ning/http/client/providers/netty/NettyResponse.java | 8 +++----- 3 files changed, 9 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/apache/ApacheResponse.java b/src/main/java/com/ning/http/client/providers/apache/ApacheResponse.java index 2cdf19f629..955121fc3d 100644 --- a/src/main/java/com/ning/http/client/providers/apache/ApacheResponse.java +++ b/src/main/java/com/ning/http/client/providers/apache/ApacheResponse.java @@ -104,14 +104,12 @@ public String getResponseBodyExcerpt(int maxLength, String charset) throws IOExc } private String computeCharset(String charset) { - String contentType = getContentType(); if (charset == null) { + String contentType = getContentType(); if (contentType != null) - charset = AsyncHttpProviderUtils.parseCharset(contentType); - else - charset = DEFAULT_CHARSET; + charset = AsyncHttpProviderUtils.parseCharset(contentType); // parseCharset can return null } - return charset; + return charset != null? charset: DEFAULT_CHARSET; } /* @Override */ diff --git a/src/main/java/com/ning/http/client/providers/jdk/JDKResponse.java b/src/main/java/com/ning/http/client/providers/jdk/JDKResponse.java index 36700fde8d..8b71f315f3 100644 --- a/src/main/java/com/ning/http/client/providers/jdk/JDKResponse.java +++ b/src/main/java/com/ning/http/client/providers/jdk/JDKResponse.java @@ -117,14 +117,12 @@ public String getResponseBodyExcerpt(int maxLength, String charset) throws IOExc } private String computeCharset(String charset) { - String contentType = getContentType(); if (charset == null) { + String contentType = getContentType(); if (contentType != null) - charset = AsyncHttpProviderUtils.parseCharset(contentType); - else - charset = DEFAULT_CHARSET; + charset = AsyncHttpProviderUtils.parseCharset(contentType); // parseCharset can return null } - return charset; + return charset != null? charset: DEFAULT_CHARSET; } /* @Override */ diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyResponse.java b/src/main/java/com/ning/http/client/providers/netty/NettyResponse.java index 01c61d0165..2562b9907a 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyResponse.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyResponse.java @@ -111,14 +111,12 @@ public String getResponseBodyExcerpt(int maxLength, String charset) throws IOExc } private String computeCharset(String charset) { - String contentType = getContentType(); if (charset == null) { + String contentType = getContentType(); if (contentType != null) - charset = AsyncHttpProviderUtils.parseCharset(contentType); - else - charset = DEFAULT_CHARSET; + charset = AsyncHttpProviderUtils.parseCharset(contentType); // parseCharset can return null } - return charset; + return charset != null? charset: DEFAULT_CHARSET; } /* @Override */ From 434462bf99ce75314fdb9c17216e32278d257c1f Mon Sep 17 00:00:00 2001 From: jfarcand Date: Tue, 18 Dec 2012 21:22:05 -0500 Subject: [PATCH 028/264] [maven-release-plugin] prepare release async-http-client-1.7.9 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index c1e7f6f280..57c37bd05d 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.7.9-SNAPSHOT + 1.7.9 jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From ed3078cfdfa133dfa84f55dd4602a3bc053707b7 Mon Sep 17 00:00:00 2001 From: jfarcand Date: Tue, 18 Dec 2012 21:22:10 -0500 Subject: [PATCH 029/264] [maven-release-plugin] prepare for next development iteration --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 57c37bd05d..513f0692bd 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.7.9 + 1.7.10-SNAPSHOT jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From a703e2b51e6339a5a1f626fd8d8d1316a0997b8f Mon Sep 17 00:00:00 2001 From: mashlah Date: Wed, 19 Dec 2012 16:52:50 +0100 Subject: [PATCH 030/264] -fix: Change the delay of the reaperFuture to be the minimum of the requestTimeout and requestIdleTimeout --- .../http/client/providers/netty/NettyAsyncHttpProvider.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java index a7595dbb17..b750fc9e54 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java @@ -564,7 +564,7 @@ public void operationComplete(ChannelFuture cf) { try { future.touch(); - int delay = requestTimeout(config, future.getRequest().getPerRequestConfig()); + int delay = Math.min(config.getIdleConnectionTimeoutInMs(), requestTimeout(config, future.getRequest().getPerRequestConfig())); if (delay != -1 && !future.isDone() && !future.isCancelled()) { ReaperFuture reaperFuture = new ReaperFuture(future); Future scheduledFuture = config.reaper().scheduleAtFixedRate(reaperFuture, 0, delay, TimeUnit.MILLISECONDS); From ab58fb5cd86302e62a8e8c2a563cb6e956fd16b2 Mon Sep 17 00:00:00 2001 From: losar Date: Fri, 18 Jan 2013 19:25:27 +0100 Subject: [PATCH 031/264] Fix high latency of multipart requests Multipart requests have high latency if socket send buffer fills up due to slow consumer. Producer should perform socket readiness check to detect that situation instead of using a fixed wait time. --- .../ning/http/multipart/MultipartBody.java | 53 ++++++++++++++----- 1 file changed, 39 insertions(+), 14 deletions(-) diff --git a/src/main/java/com/ning/http/multipart/MultipartBody.java b/src/main/java/com/ning/http/multipart/MultipartBody.java index c3004e469f..d12a5f0cf2 100644 --- a/src/main/java/com/ning/http/multipart/MultipartBody.java +++ b/src/main/java/com/ning/http/multipart/MultipartBody.java @@ -25,10 +25,10 @@ import java.io.InputStream; import java.io.RandomAccessFile; import java.nio.ByteBuffer; -import java.nio.channels.FileChannel; -import java.nio.channels.WritableByteChannel; +import java.nio.channels.*; import java.util.ArrayList; import java.util.List; +import java.util.Set; public class MultipartBody implements RandomAccessBody { @@ -569,21 +569,46 @@ private long writeToTarget(WritableByteChannel target, ByteArrayOutputStream byt int maxSpin = 0; synchronized (byteWriter) { ByteBuffer message = ByteBuffer.wrap(byteWriter.toByteArray()); - while ((target.isOpen()) && (written < byteWriter.size())) { - long nWrite = target.write(message); - written += nWrite; - if (nWrite == 0 && maxSpin++ < 10) { - logger.info("Waiting for writing..."); - try { - byteWriter.wait(1000); - } catch (InterruptedException e) { - logger.trace(e.getMessage(), e); + + if (target instanceof SocketChannel) { + final Selector selector = Selector.open(); + try { + final SocketChannel channel = (SocketChannel) target; + channel.register(selector, SelectionKey.OP_WRITE); + + while (written < byteWriter.size() && selector.select() != 0) { + final Set selectedKeys = selector.selectedKeys(); + + for (SelectionKey key : selectedKeys) { + if (key.isWritable()) { + written += target.write(message); + } + } } - } else { - if (maxSpin >= 10) { + + if (written < byteWriter.size()) { throw new IOException("Unable to write on channel " + target); } - maxSpin = 0; + } finally { + selector.close(); + } + } else { + while ((target.isOpen()) && (written < byteWriter.size())) { + long nWrite = target.write(message); + written += nWrite; + if (nWrite == 0 && maxSpin++ < 10) { + logger.info("Waiting for writing..."); + try { + byteWriter.wait(1000); + } catch (InterruptedException e) { + logger.trace(e.getMessage(), e); + } + } else { + if (maxSpin >= 10) { + throw new IOException("Unable to write on channel " + target); + } + maxSpin = 0; + } } } } From 00888a9f3b66e9c38531fa2468e2309b6bea278c Mon Sep 17 00:00:00 2001 From: jfarcand Date: Wed, 23 Jan 2013 21:46:05 -0500 Subject: [PATCH 032/264] [maven-release-plugin] prepare release async-http-client-1.7.10 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 513f0692bd..f75254cfb0 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.7.10-SNAPSHOT + 1.7.10 jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From ff105672f51355f24851dc59cd0ca31913b423cb Mon Sep 17 00:00:00 2001 From: jfarcand Date: Wed, 23 Jan 2013 21:46:10 -0500 Subject: [PATCH 033/264] [maven-release-plugin] prepare for next development iteration --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index f75254cfb0..7fe9780eb8 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.7.10 + 1.7.11-SNAPSHOT jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From dcd546b5f204f0b5e89518ec217fe29d4ee98961 Mon Sep 17 00:00:00 2001 From: Nolan Darilek Date: Mon, 28 Jan 2013 10:34:42 -0600 Subject: [PATCH 034/264] Lazily initialize SPNegoEngine, may help with use on Android where these classes aren't present. Conflicts: src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java --- .../providers/netty/NettyAsyncHttpProvider.java | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java index b750fc9e54..6752ebac32 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java @@ -177,7 +177,7 @@ public boolean remove(Object o) { private final boolean trackConnections; private final boolean useRawUrl; private final static NTLMEngine ntlmEngine = new NTLMEngine(); - private final static SpnegoEngine spnegoEngine = new SpnegoEngine(); + private static SpnegoEngine spnegoEngine = null; private final Protocol httpProtocol = new HttpProtocol(); private final Protocol webSocketProtocol = new WebSocketProtocol(); @@ -599,6 +599,12 @@ protected final static HttpRequest buildRequest(AsyncHttpClientConfig config, Re return construct(config, request, new HttpMethod(method), uri, buffer); } + private static SpnegoEngine getSpnegoEngine() { + if(spnegoEngine == null) + spnegoEngine = new SpnegoEngine(); + return spnegoEngine; + } + @SuppressWarnings("deprecation") private static HttpRequest construct(AsyncHttpClientConfig config, Request request, @@ -714,7 +720,7 @@ private static HttpRequest construct(AsyncHttpClientConfig config, String challengeHeader = null; String server = proxyServer == null ? host : proxyServer.getHost(); try { - challengeHeader = spnegoEngine.generateToken(server); + challengeHeader = getSpnegoEngine().generateToken(server); } catch (Throwable e) { IOException ie = new IOException(); ie.initCause(e); @@ -1199,7 +1205,7 @@ private Realm kerberosChallenge(List proxyAuth, String host = request.getVirtualHost() == null ? AsyncHttpProviderUtils.getHost(uri) : request.getVirtualHost(); String server = proxyServer == null ? host : proxyServer.getHost(); try { - String challengeHeader = spnegoEngine.generateToken(server); + String challengeHeader = getSpnegoEngine().generateToken(server); headers.remove(HttpHeaders.Names.AUTHORIZATION); headers.add(HttpHeaders.Names.AUTHORIZATION, "Negotiate " + challengeHeader); From 966b0dc1737116d9a21753c0ba06dc43ba509caa Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 11 Feb 2013 11:04:10 +0100 Subject: [PATCH 035/264] Backport ConnectionPoolKeyStrategy for 1.7.x branch --- .../client/ConnectionPoolKeyStrategy.java | 23 +++++++++++++++ .../client/DefaultConnectionPoolStrategy.java | 29 +++++++++++++++++++ .../java/com/ning/http/client/Request.java | 1 + .../ning/http/client/RequestBuilderBase.java | 11 +++++++ .../netty/NettyAsyncHttpProvider.java | 16 +++++----- .../providers/netty/NettyResponseFuture.java | 10 ++++++- 6 files changed, 82 insertions(+), 8 deletions(-) create mode 100644 src/main/java/com/ning/http/client/ConnectionPoolKeyStrategy.java create mode 100644 src/main/java/com/ning/http/client/DefaultConnectionPoolStrategy.java diff --git a/src/main/java/com/ning/http/client/ConnectionPoolKeyStrategy.java b/src/main/java/com/ning/http/client/ConnectionPoolKeyStrategy.java new file mode 100644 index 0000000000..d0e6643db1 --- /dev/null +++ b/src/main/java/com/ning/http/client/ConnectionPoolKeyStrategy.java @@ -0,0 +1,23 @@ +/* + * Copyright 2010 Ning, Inc. + * + * Ning licenses this file to you under the Apache License, version 2.0 + * (the "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package com.ning.http.client; + +import java.net.URI; + +public interface ConnectionPoolKeyStrategy { + + String getKey(URI uri); +} \ No newline at end of file diff --git a/src/main/java/com/ning/http/client/DefaultConnectionPoolStrategy.java b/src/main/java/com/ning/http/client/DefaultConnectionPoolStrategy.java new file mode 100644 index 0000000000..3d248e869f --- /dev/null +++ b/src/main/java/com/ning/http/client/DefaultConnectionPoolStrategy.java @@ -0,0 +1,29 @@ +/* + * Copyright 2010 Ning, Inc. + * + * Ning licenses this file to you under the Apache License, version 2.0 + * (the "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package com.ning.http.client; + +import java.net.URI; + +import com.ning.http.util.AsyncHttpProviderUtils; + +public enum DefaultConnectionPoolStrategy implements ConnectionPoolKeyStrategy { + + INSTANCE; + + public String getKey(URI uri) { + return AsyncHttpProviderUtils.getBaseUrl(uri); + } +} \ No newline at end of file diff --git a/src/main/java/com/ning/http/client/Request.java b/src/main/java/com/ning/http/client/Request.java index 10576405bb..eb31a23fba 100644 --- a/src/main/java/com/ning/http/client/Request.java +++ b/src/main/java/com/ning/http/client/Request.java @@ -232,4 +232,5 @@ public static interface EntityWriter { public boolean isUseRawUrl(); + ConnectionPoolKeyStrategy getConnectionPoolKeyStrategy(); } diff --git a/src/main/java/com/ning/http/client/RequestBuilderBase.java b/src/main/java/com/ning/http/client/RequestBuilderBase.java index 7d4f843890..29b65f3ab8 100644 --- a/src/main/java/com/ning/http/client/RequestBuilderBase.java +++ b/src/main/java/com/ning/http/client/RequestBuilderBase.java @@ -67,6 +67,7 @@ private static final class RequestImpl implements Request { private long rangeOffset = 0; public String charset; private boolean useRawUrl = false; + private ConnectionPoolKeyStrategy connectionPoolKeyStrategy = DefaultConnectionPoolStrategy.INSTANCE; public RequestImpl(boolean useRawUrl) { this.useRawUrl = useRawUrl; @@ -100,6 +101,7 @@ public RequestImpl(Request prototype) { this.rangeOffset = prototype.getRangeOffset(); this.charset = prototype.getBodyEncoding(); this.useRawUrl = prototype.isUseRawUrl(); + this.connectionPoolKeyStrategy = prototype.getConnectionPoolKeyStrategy(); } } @@ -287,6 +289,10 @@ public String getBodyEncoding() { return charset; } + public ConnectionPoolKeyStrategy getConnectionPoolKeyStrategy() { + return connectionPoolKeyStrategy; + } + @Override public String toString() { StringBuilder sb = new StringBuilder(url); @@ -603,6 +609,11 @@ public T setBodyEncoding(String charset) { return derived.cast(this); } + public T setConnectionPoolKeyStrategy(ConnectionPoolKeyStrategy connectionPoolKeyStrategy) { + request.connectionPoolKeyStrategy = connectionPoolKeyStrategy; + return derived.cast(this); + } + public Request build() { if ((request.length < 0) && (request.streamData == null) && allowBody(request.getMethod())) { // can't concatenate content-length diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java index 6752ebac32..7e447bb4e9 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java @@ -21,6 +21,7 @@ import com.ning.http.client.AsyncHttpProvider; import com.ning.http.client.Body; import com.ning.http.client.BodyGenerator; +import com.ning.http.client.ConnectionPoolKeyStrategy; import com.ning.http.client.ConnectionsPool; import com.ning.http.client.Cookie; import com.ning.http.client.FluentCaseInsensitiveStringsMap; @@ -381,8 +382,8 @@ public ChannelPipeline getPipeline() throws Exception { } } - private Channel lookupInCache(URI uri) { - final Channel channel = connectionsPool.poll(AsyncHttpProviderUtils.getBaseUrl(uri)); + private Channel lookupInCache(URI uri, ConnectionPoolKeyStrategy connectionPoolKeyStrategy) { + final Channel channel = connectionsPool.poll(connectionPoolKeyStrategy.getKey(uri)); if (channel != null) { log.debug("Using cached Channel {}\n for uri {}\n", channel, uri); @@ -955,7 +956,7 @@ private ListenableFuture doConnect(final Request request, final AsyncHand if (f != null && f.reuseChannel() && f.channel() != null) { channel = f.channel(); } else { - channel = lookupInCache(uri); + channel = lookupInCache(uri, request.getConnectionPoolKeyStrategy()); } } @@ -1318,7 +1319,7 @@ private Realm ntlmProxyChallenge(List wwwAuth, private void drainChannel(final ChannelHandlerContext ctx, final NettyResponseFuture future, final boolean keepAlive, final URI uri) { ctx.setAttachment(new AsyncCallable(future) { public Object call() throws Exception { - if (keepAlive && ctx.getChannel().isReadable() && connectionsPool.offer(AsyncHttpProviderUtils.getBaseUrl(uri), ctx.getChannel())) { + if (keepAlive && ctx.getChannel().isReadable() && connectionsPool.offer(future.getConnectionPoolKeyStrategy().getKey(uri), ctx.getChannel())) { return null; } @@ -1514,7 +1515,7 @@ private void finishUpdate(final NettyResponseFuture future, final ChannelHand drainChannel(ctx, future, future.getKeepAlive(), future.getURI()); } else { if (future.getKeepAlive() && ctx.getChannel().isReadable() && - connectionsPool.offer(AsyncHttpProviderUtils.getBaseUrl(future.getURI()), ctx.getChannel())) { + connectionsPool.offer(future.getConnectionPoolKeyStrategy().getKey(future.getURI()), ctx.getChannel())) { markAsDone(future, ctx); return; } @@ -1715,7 +1716,7 @@ public static NettyResponseFuture newFuture(URI uri, NettyAsyncHttpProvider provider) { NettyResponseFuture f = new NettyResponseFuture(uri, request, asyncHandler, nettyRequest, - requestTimeout(config, request.getPerRequestConfig()), config.getIdleConnectionTimeoutInMs(), provider); + requestTimeout(config, request.getPerRequestConfig()), config.getIdleConnectionTimeoutInMs(), provider, request.getConnectionPoolKeyStrategy()); if (request.getHeaders().getFirstValue("Expect") != null && request.getHeaders().getFirstValue("Expect").equalsIgnoreCase("100-Continue")) { @@ -2085,10 +2086,11 @@ private boolean redirect(Request request, nBuilder.addOrReplaceCookie(c); } + final String connectionPoolKey = future.getConnectionPoolKeyStrategy().getKey(initialConnectionUri); AsyncCallable ac = new AsyncCallable(future) { public Object call() throws Exception { if (initialConnectionKeepAlive && ctx.getChannel().isReadable() && - connectionsPool.offer(AsyncHttpProviderUtils.getBaseUrl(initialConnectionUri), ctx.getChannel())) { + connectionsPool.offer(connectionPoolKey, ctx.getChannel())) { return null; } finishChannel(ctx); diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyResponseFuture.java b/src/main/java/com/ning/http/client/providers/netty/NettyResponseFuture.java index bb58421dcb..631b8c59ef 100755 --- a/src/main/java/com/ning/http/client/providers/netty/NettyResponseFuture.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyResponseFuture.java @@ -16,6 +16,7 @@ package com.ning.http.client.providers.netty; import com.ning.http.client.AsyncHandler; +import com.ning.http.client.ConnectionPoolKeyStrategy; import com.ning.http.client.Request; import com.ning.http.client.listenable.AbstractListenableFuture; import org.jboss.netty.channel.Channel; @@ -85,6 +86,7 @@ enum STATE { private boolean writeBody; private final AtomicBoolean throwableCalled = new AtomicBoolean(false); private boolean allowConnect = false; + private final ConnectionPoolKeyStrategy connectionPoolKeyStrategy; public NettyResponseFuture(URI uri, Request request, @@ -92,7 +94,8 @@ public NettyResponseFuture(URI uri, HttpRequest nettyRequest, int responseTimeoutInMs, int idleConnectionTimeoutInMs, - NettyAsyncHttpProvider asyncHttpProvider) { + NettyAsyncHttpProvider asyncHttpProvider, + ConnectionPoolKeyStrategy connectionPoolKeyStrategy) { this.asyncHandler = asyncHandler; this.responseTimeoutInMs = responseTimeoutInMs; @@ -101,6 +104,7 @@ public NettyResponseFuture(URI uri, this.nettyRequest = nettyRequest; this.uri = uri; this.asyncHttpProvider = asyncHttpProvider; + this.connectionPoolKeyStrategy = connectionPoolKeyStrategy; if (System.getProperty(MAX_RETRY) != null) { maxRetry = Integer.valueOf(System.getProperty(MAX_RETRY)); @@ -119,6 +123,10 @@ protected void setURI(URI uri) { this.uri = uri; } + public ConnectionPoolKeyStrategy getConnectionPoolKeyStrategy() { + return connectionPoolKeyStrategy; + } + /** * {@inheritDoc} */ From 196eff1b1fa53201ebb2f94a27d0ce82e0db1e75 Mon Sep 17 00:00:00 2001 From: andekaputra Date: Tue, 19 Feb 2013 00:20:51 +0700 Subject: [PATCH 036/264] Allows to configure Netty NioClientSocketChannelFactory --- .../netty/NettyAsyncHttpProvider.java | 40 +++++++++++++------ .../netty/NettyAsyncHttpProviderConfig.java | 5 +++ 2 files changed, 32 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java index 7e447bb4e9..c450122c1e 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java @@ -152,6 +152,7 @@ public class NettyAsyncHttpProvider extends SimpleChannelUpstreamHandler impleme private final AsyncHttpClientConfig config; private final AtomicBoolean isClose = new AtomicBoolean(false); private final ClientSocketChannelFactory socketChannelFactory; + private final boolean allowReleaseSocketChannelFactory; private int httpClientCodecMaxInitialLineLength = 4096; private int httpClientCodecMaxHeaderSize = 8192; private int httpClientCodecMaxChunkSize = 8192; @@ -193,17 +194,28 @@ public NettyAsyncHttpProvider(AsyncHttpClientConfig config) { if (asyncHttpProviderConfig.getProperty(NettyAsyncHttpProviderConfig.USE_BLOCKING_IO) != null) { socketChannelFactory = new OioClientSocketChannelFactory(config.executorService()); + this.allowReleaseSocketChannelFactory = true; } else { - ExecutorService e; - Object o = asyncHttpProviderConfig.getProperty(NettyAsyncHttpProviderConfig.BOSS_EXECUTOR_SERVICE); - if (o != null && ExecutorService.class.isAssignableFrom(o.getClass())) { - e = ExecutorService.class.cast(o); + // check if external NioClientSocketChannelFactory is defined + Object oo = asyncHttpProviderConfig.getProperty(NettyAsyncHttpProviderConfig.SOCKET_CHANNEL_FACTORY); + if (oo != null && NioClientSocketChannelFactory.class.isAssignableFrom(oo.getClass())) { + this.socketChannelFactory = NioClientSocketChannelFactory.class.cast(oo); + + // cannot allow releasing shared channel factory + this.allowReleaseSocketChannelFactory = false; } else { - e = Executors.newCachedThreadPool(); + ExecutorService e; + Object o = asyncHttpProviderConfig.getProperty(NettyAsyncHttpProviderConfig.BOSS_EXECUTOR_SERVICE); + if (o != null && ExecutorService.class.isAssignableFrom(o.getClass())) { + e = ExecutorService.class.cast(o); + } else { + e = Executors.newCachedThreadPool(); + } + int numWorkers = config.getIoThreadMultiplier() * Runtime.getRuntime().availableProcessors(); + log.debug("Number of application's worker threads is {}", numWorkers); + socketChannelFactory = new NioClientSocketChannelFactory(e, config.executorService(), numWorkers); + this.allowReleaseSocketChannelFactory = true; } - int numWorkers = config.getIoThreadMultiplier() * Runtime.getRuntime().availableProcessors(); - log.debug("Number of application's worker threads is {}", numWorkers); - socketChannelFactory = new NioClientSocketChannelFactory(e, config.executorService(), numWorkers); } plainBootstrap = new ClientBootstrap(socketChannelFactory); secureBootstrap = new ClientBootstrap(socketChannelFactory); @@ -899,11 +911,13 @@ public void close() { config.executorService().shutdown(); config.reaper().shutdown(); - socketChannelFactory.releaseExternalResources(); - plainBootstrap.releaseExternalResources(); - secureBootstrap.releaseExternalResources(); - webSocketBootstrap.releaseExternalResources(); - secureWebSocketBootstrap.releaseExternalResources(); + if (this.allowReleaseSocketChannelFactory) { + socketChannelFactory.releaseExternalResources(); + plainBootstrap.releaseExternalResources(); + secureBootstrap.releaseExternalResources(); + webSocketBootstrap.releaseExternalResources(); + secureWebSocketBootstrap.releaseExternalResources(); + } } catch (Throwable t) { log.warn("Unexpected error on close", t); } diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProviderConfig.java b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProviderConfig.java index c471faa4f8..79bd0741b7 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProviderConfig.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProviderConfig.java @@ -71,6 +71,11 @@ public class NettyAsyncHttpProviderConfig implements AsyncHttpProviderConfig properties = new ConcurrentHashMap(); public NettyAsyncHttpProviderConfig() { From c9de43dfe5dfb65e69b5dc0aab1b59ca690d7a0d Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 19 Feb 2013 10:34:55 +0100 Subject: [PATCH 037/264] Make NettyConnectionsPool properly trace open channels, fix #222 in 1.7.x --- .../client/providers/netty/NettyConnectionsPool.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyConnectionsPool.java b/src/main/java/com/ning/http/client/providers/netty/NettyConnectionsPool.java index 18e582774a..ca8dc9bc74 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyConnectionsPool.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyConnectionsPool.java @@ -126,8 +126,15 @@ public void run() { } } - log.trace(String.format("%d channel open, %d idle channels closed (times: 1st-loop=%d, 2nd-loop=%d).\n", - connectionsPool.size(), channelsInTimeout.size(), endConcurrentLoop - currentTime, System.currentTimeMillis() - endConcurrentLoop)); + if (log.isTraceEnabled()) { + int openChannels = 0; + for (ConcurrentLinkedQueue hostChannels: connectionsPool.values()) { + openChannels += hostChannels.size(); + } + log.trace(String.format("%d channel open, %d idle channels closed (times: 1st-loop=%d, 2nd-loop=%d).\n", + openChannels, channelsInTimeout.size(), endConcurrentLoop - currentTime, System.currentTimeMillis() - endConcurrentLoop)); + } + } catch (Throwable t) { log.error("uncaught exception!", t); } From 1a83eb4556c0750822d95a75d466bc2e4f60010d Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 20 Feb 2013 14:14:48 +0100 Subject: [PATCH 038/264] BodyParts is a List, not a Collection, fix #225 --- .../ning/http/client/AsyncHttpProvider.java | 4 ++-- .../HttpResponseBodyPartsInputStream.java | 13 ++++++------ .../java/com/ning/http/client/Response.java | 4 ++-- .../apache/ApacheAsyncHttpProvider.java | 4 +--- .../providers/apache/ApacheResponse.java | 13 +++--------- .../grizzly/GrizzlyAsyncHttpProvider.java | 2 +- .../providers/grizzly/GrizzlyResponse.java | 14 ++++++------- .../providers/jdk/JDKAsyncHttpProvider.java | 3 +-- .../client/providers/jdk/JDKResponse.java | 12 +++-------- .../netty/NettyAsyncHttpProvider.java | 3 +-- .../client/providers/netty/NettyResponse.java | 20 +++---------------- .../webdav/WebDavCompletionHandlerBase.java | 6 +++--- .../http/util/AsyncHttpProviderUtils.java | 14 ++++++++++--- 13 files changed, 44 insertions(+), 68 deletions(-) diff --git a/src/main/java/com/ning/http/client/AsyncHttpProvider.java b/src/main/java/com/ning/http/client/AsyncHttpProvider.java index 1689bc137e..1dfdb0474c 100644 --- a/src/main/java/com/ning/http/client/AsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/AsyncHttpProvider.java @@ -16,7 +16,7 @@ package com.ning.http.client; import java.io.IOException; -import java.util.Collection; +import java.util.List; /** * Interface to be used when implementing custom asynchronous I/O HTTP client. @@ -48,6 +48,6 @@ public interface AsyncHttpProvider { */ public Response prepareResponse(HttpResponseStatus status, HttpResponseHeaders headers, - Collection bodyParts); + List bodyParts); } diff --git a/src/main/java/com/ning/http/client/HttpResponseBodyPartsInputStream.java b/src/main/java/com/ning/http/client/HttpResponseBodyPartsInputStream.java index 1f6667cd2b..7b0f76db5b 100644 --- a/src/main/java/com/ning/http/client/HttpResponseBodyPartsInputStream.java +++ b/src/main/java/com/ning/http/client/HttpResponseBodyPartsInputStream.java @@ -14,26 +14,27 @@ import java.io.IOException; import java.io.InputStream; +import java.util.List; /** * An {@link InputStream} that reads all the elements in an array of {@link HttpResponseBodyPart}s. */ public class HttpResponseBodyPartsInputStream extends InputStream { - private final HttpResponseBodyPart[] parts; + private final List parts; private int currentPos = 0; private int bytePos = -1; private byte[] active; private int available = 0; - public HttpResponseBodyPartsInputStream(HttpResponseBodyPart[] parts) { + public HttpResponseBodyPartsInputStream(List parts) { this.parts = parts; - active = parts[0].getBodyPartBytes(); + active = parts.get(0).getBodyPartBytes(); computeLength(parts); } - private void computeLength(HttpResponseBodyPart[] parts) { + private void computeLength(List parts) { if (available == 0) { for (HttpResponseBodyPart p : parts) { available += p.getBodyPartBytes().length; @@ -50,12 +51,12 @@ public int available() throws IOException { public int read() throws IOException { if (++bytePos >= active.length) { // No more bytes, so step to the next array. - if (++currentPos >= parts.length) { + if (++currentPos >= parts.size()) { return -1; } bytePos = 0; - active = parts[currentPos].getBodyPartBytes(); + active = parts.get(currentPos).getBodyPartBytes(); } return active[bytePos] & 0xFF; diff --git a/src/main/java/com/ning/http/client/Response.java b/src/main/java/com/ning/http/client/Response.java index 17da422110..54ddddf6bc 100644 --- a/src/main/java/com/ning/http/client/Response.java +++ b/src/main/java/com/ning/http/client/Response.java @@ -178,8 +178,8 @@ public interface Response { public static class ResponseBuilder { - private final Collection bodies = - Collections.synchronizedCollection(new ArrayList()); + private final List bodies = + Collections.synchronizedList(new ArrayList()); private HttpResponseStatus status; private HttpResponseHeaders headers; diff --git a/src/main/java/com/ning/http/client/providers/apache/ApacheAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/apache/ApacheAsyncHttpProvider.java index 78abf16415..ac1531bef5 100644 --- a/src/main/java/com/ning/http/client/providers/apache/ApacheAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/apache/ApacheAsyncHttpProvider.java @@ -47,7 +47,6 @@ import org.apache.commons.httpclient.Credentials; import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler; import org.apache.commons.httpclient.Header; -import org.apache.commons.httpclient.HostConfiguration; import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.HttpMethodBase; import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager; @@ -102,7 +101,6 @@ import java.security.SecureRandom; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; -import java.util.Collection; import java.util.List; import java.util.Map; import java.util.concurrent.Callable; @@ -224,7 +222,7 @@ public void close() { } } - public Response prepareResponse(HttpResponseStatus status, HttpResponseHeaders headers, Collection bodyParts) { + public Response prepareResponse(HttpResponseStatus status, HttpResponseHeaders headers, List bodyParts) { return new ApacheResponse(status, headers, bodyParts); } diff --git a/src/main/java/com/ning/http/client/providers/apache/ApacheResponse.java b/src/main/java/com/ning/http/client/providers/apache/ApacheResponse.java index 955121fc3d..3d8ec79800 100644 --- a/src/main/java/com/ning/http/client/providers/apache/ApacheResponse.java +++ b/src/main/java/com/ning/http/client/providers/apache/ApacheResponse.java @@ -15,19 +15,16 @@ import com.ning.http.client.Cookie; import com.ning.http.client.FluentCaseInsensitiveStringsMap; import com.ning.http.client.HttpResponseBodyPart; -import com.ning.http.client.HttpResponseBodyPartsInputStream; import com.ning.http.client.HttpResponseHeaders; import com.ning.http.client.HttpResponseStatus; import com.ning.http.client.Response; import com.ning.http.util.AsyncHttpProviderUtils; -import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URI; import java.util.ArrayList; -import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; @@ -37,14 +34,14 @@ public class ApacheResponse implements Response { private final static String DEFAULT_CHARSET = "ISO-8859-1"; private final URI uri; - private final Collection bodyParts; + private final List bodyParts; private final HttpResponseHeaders headers; private final HttpResponseStatus status; private List cookies; public ApacheResponse(HttpResponseStatus status, HttpResponseHeaders headers, - Collection bodyParts) { + List bodyParts) { this.bodyParts = bodyParts; this.headers = headers; @@ -81,11 +78,7 @@ public String getResponseBody(String charset) throws IOException { /* @Override */ public InputStream getResponseBodyAsStream() throws IOException { - if (!bodyParts.isEmpty()) { - return new HttpResponseBodyPartsInputStream(bodyParts.toArray(new HttpResponseBodyPart[bodyParts.size()])); - } else { - return new ByteArrayInputStream("".getBytes()); - } + return AsyncHttpProviderUtils.contentToInputStream(bodyParts); } /* @Override */ diff --git a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java index a4ee140e75..cce8481020 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java @@ -271,7 +271,7 @@ public void close() { */ public Response prepareResponse(HttpResponseStatus status, HttpResponseHeaders headers, - Collection bodyParts) { + List bodyParts) { return new GrizzlyResponse(status, headers, bodyParts); diff --git a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponse.java b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponse.java index 1f0b52784d..1119e00f88 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponse.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponse.java @@ -61,26 +61,24 @@ public class GrizzlyResponse implements Response { public GrizzlyResponse(final HttpResponseStatus status, final HttpResponseHeaders headers, - final Collection bodyParts) { + final List bodyParts) { this.status = status; this.headers = headers; this.bodyParts = bodyParts; if (bodyParts != null && !bodyParts.isEmpty()) { - HttpResponseBodyPart[] parts = - bodyParts.toArray(new HttpResponseBodyPart[bodyParts.size()]); - if (parts.length == 1) { - responseBody = ((GrizzlyResponseBodyPart) parts[0]).getBodyBuffer(); + if (bodyParts.size() == 1) { + responseBody = ((GrizzlyResponseBodyPart) bodyParts.get(0)).getBodyBuffer(); } else { - final Buffer firstBuffer = ((GrizzlyResponseBodyPart) parts[0]).getBodyBuffer(); + final Buffer firstBuffer = ((GrizzlyResponseBodyPart) bodyParts.get(0)).getBodyBuffer(); final MemoryManager mm = MemoryManager.DEFAULT_MEMORY_MANAGER; Buffer constructedBodyBuffer = firstBuffer; - for (int i = 1, len = parts.length; i < len; i++) { + for (int i = 1, len = bodyParts.size(); i < len; i++) { constructedBodyBuffer = Buffers.appendBuffers(mm, constructedBodyBuffer, - ((GrizzlyResponseBodyPart) parts[i]).getBodyBuffer()); + ((GrizzlyResponseBodyPart) bodyParts.get(i)).getBodyBuffer()); } responseBody = constructedBodyBuffer; } diff --git a/src/main/java/com/ning/http/client/providers/jdk/JDKAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/jdk/JDKAsyncHttpProvider.java index 37c8af7748..5e3eb656c3 100644 --- a/src/main/java/com/ning/http/client/providers/jdk/JDKAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/jdk/JDKAsyncHttpProvider.java @@ -68,7 +68,6 @@ import java.nio.ByteBuffer; import java.security.GeneralSecurityException; import java.security.NoSuchAlgorithmException; -import java.util.Collection; import java.util.List; import java.util.Map; import java.util.concurrent.Callable; @@ -205,7 +204,7 @@ public void close() { isClose.set(true); } - public Response prepareResponse(HttpResponseStatus status, HttpResponseHeaders headers, Collection bodyParts) { + public Response prepareResponse(HttpResponseStatus status, HttpResponseHeaders headers, List bodyParts) { return new JDKResponse(status, headers, bodyParts); } diff --git a/src/main/java/com/ning/http/client/providers/jdk/JDKResponse.java b/src/main/java/com/ning/http/client/providers/jdk/JDKResponse.java index 8b71f315f3..f7fd04603e 100644 --- a/src/main/java/com/ning/http/client/providers/jdk/JDKResponse.java +++ b/src/main/java/com/ning/http/client/providers/jdk/JDKResponse.java @@ -15,7 +15,6 @@ import com.ning.http.client.Cookie; import com.ning.http.client.FluentCaseInsensitiveStringsMap; import com.ning.http.client.HttpResponseBodyPart; -import com.ning.http.client.HttpResponseBodyPartsInputStream; import com.ning.http.client.HttpResponseHeaders; import com.ning.http.client.HttpResponseStatus; import com.ning.http.client.Response; @@ -27,7 +26,6 @@ import java.net.MalformedURLException; import java.net.URI; import java.util.ArrayList; -import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; @@ -38,7 +36,7 @@ public class JDKResponse implements Response { private final static String DEFAULT_CHARSET = "ISO-8859-1"; private final URI uri; - private final Collection bodyParts; + private final List bodyParts; private final HttpResponseHeaders headers; private final HttpResponseStatus status; private List cookies; @@ -47,7 +45,7 @@ public class JDKResponse implements Response { public JDKResponse(HttpResponseStatus status, HttpResponseHeaders headers, - Collection bodyParts) { + List bodyParts) { this.bodyParts = bodyParts; this.headers = headers; @@ -93,11 +91,7 @@ public InputStream getResponseBodyAsStream() throws IOException { return new ByteArrayInputStream(content.getBytes(DEFAULT_CHARSET)); } - if (!bodyParts.isEmpty()) { - return new HttpResponseBodyPartsInputStream(bodyParts.toArray(new HttpResponseBodyPart[bodyParts.size()])); - } else { - return new ByteArrayInputStream("".getBytes()); - } + return AsyncHttpProviderUtils.contentToInputStream(bodyParts); } /* @Override */ diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java index c450122c1e..c30b2cd8ab 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java @@ -117,7 +117,6 @@ import java.security.GeneralSecurityException; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; -import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.Map.Entry; @@ -927,7 +926,7 @@ public void close() { public Response prepareResponse(final HttpResponseStatus status, final HttpResponseHeaders headers, - final Collection bodyParts) { + final List bodyParts) { return new NettyResponse(status, headers, bodyParts); } diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyResponse.java b/src/main/java/com/ning/http/client/providers/netty/NettyResponse.java index 2562b9907a..a0a243a907 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyResponse.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyResponse.java @@ -22,16 +22,12 @@ import com.ning.http.client.HttpResponseStatus; import com.ning.http.client.Response; import com.ning.http.util.AsyncHttpProviderUtils; -import org.jboss.netty.buffer.ChannelBuffer; -import org.jboss.netty.buffer.ChannelBufferInputStream; -import org.jboss.netty.buffer.ChannelBuffers; import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URI; import java.util.ArrayList; -import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; @@ -43,14 +39,14 @@ public class NettyResponse implements Response { private final static String DEFAULT_CHARSET = "ISO-8859-1"; private final URI uri; - private final Collection bodyParts; + private final List bodyParts; private final HttpResponseHeaders headers; private final HttpResponseStatus status; private List cookies; public NettyResponse(HttpResponseStatus status, HttpResponseHeaders headers, - Collection bodyParts) { + List bodyParts) { this.status = status; this.headers = headers; @@ -86,17 +82,7 @@ public String getResponseBody(String charset) throws IOException { /* @Override */ public InputStream getResponseBodyAsStream() throws IOException { - ChannelBuffer buf = ChannelBuffers.dynamicBuffer(); - for (HttpResponseBodyPart bp : bodyParts) { - // Ugly. TODO - // (1) We must remove the downcast, - // (2) we need a CompositeByteArrayInputStream to avoid - // copying the bytes. - if (bp.getClass().isAssignableFrom(ResponseBodyPart.class)) { - buf.writeBytes(bp.getBodyPartBytes()); - } - } - return new ChannelBufferInputStream(buf); + return AsyncHttpProviderUtils.contentToInputStream(bodyParts); } /* @Override */ diff --git a/src/main/java/com/ning/http/client/webdav/WebDavCompletionHandlerBase.java b/src/main/java/com/ning/http/client/webdav/WebDavCompletionHandlerBase.java index d0a483db6d..d5264c6886 100644 --- a/src/main/java/com/ning/http/client/webdav/WebDavCompletionHandlerBase.java +++ b/src/main/java/com/ning/http/client/webdav/WebDavCompletionHandlerBase.java @@ -32,7 +32,7 @@ import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; -import java.util.Collection; +import java.util.List; import java.util.Collections; /** @@ -43,8 +43,8 @@ public abstract class WebDavCompletionHandlerBase implements AsyncHandler { private final Logger logger = LoggerFactory.getLogger(AsyncCompletionHandlerBase.class); - private final Collection bodies = - Collections.synchronizedCollection(new ArrayList()); + private final List bodies = + Collections.synchronizedList(new ArrayList()); private HttpResponseStatus status; private HttpResponseHeaders headers; diff --git a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java index 718dee9f35..f10ef5dff0 100644 --- a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java +++ b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java @@ -18,12 +18,14 @@ import com.ning.http.client.FilePart; import com.ning.http.client.FluentStringsMap; import com.ning.http.client.HttpResponseBodyPart; +import com.ning.http.client.HttpResponseBodyPartsInputStream; import com.ning.http.client.Part; import com.ning.http.client.StringPart; import com.ning.http.multipart.ByteArrayPartSource; import com.ning.http.multipart.MultipartRequestEntity; import com.ning.http.multipart.PartSource; +import java.io.ByteArrayInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; @@ -134,6 +136,8 @@ public final static SimpleDateFormat[] get() { static final String VERSION = "Version"; + static final byte[] EMPTY_BYTE_ARRAY = "".getBytes(); + public final static URI createUri(String u) { URI uri = URI.create(u); final String scheme = uri.getScheme(); @@ -181,13 +185,13 @@ public final static String getAuthority(URI uri) { return url; } - public final static String contentToString(Collection bodyParts, String charset) throws UnsupportedEncodingException { + public final static String contentToString(List bodyParts, String charset) throws UnsupportedEncodingException { return new String(contentToByte(bodyParts), charset); } - public final static byte[] contentToByte(Collection bodyParts) throws UnsupportedEncodingException { + public final static byte[] contentToByte(List bodyParts) throws UnsupportedEncodingException { if (bodyParts.size() == 1) { - return bodyParts.iterator().next().getBodyPartBytes(); + return bodyParts.get(0).getBodyPartBytes(); } else { int size = 0; @@ -206,6 +210,10 @@ public final static byte[] contentToByte(Collection bodyPa } } + public final static InputStream contentToInputStream(List bodyParts) throws UnsupportedEncodingException { + return bodyParts.isEmpty()? new ByteArrayInputStream(EMPTY_BYTE_ARRAY) : new HttpResponseBodyPartsInputStream(bodyParts); + } + public final static String getHost(URI uri) { String host = uri.getHost(); if (host == null) { From 88a4ecd62cf8e6830d8b92e4835a08936a1ddac5 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 20 Feb 2013 15:34:46 +0100 Subject: [PATCH 039/264] clirr = PITA --- pom.xml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/pom.xml b/pom.xml index 7fe9780eb8..277ab625fa 100644 --- a/pom.xml +++ b/pom.xml @@ -451,8 +451,25 @@ **/FilterContext **/FilterContext$* **/NettyResponseFuture + **/NettyResponseFuture$* **/**ResponseBodyPart **/**WebSocket + **/AsyncHttpProvider + **/HttpResponseBodyPartsInputStream + **/AsyncHttpProvider + **/ApacheAsyncHttpProvider + **/ApacheAsyncHttpProvider$* + **/ApacheResponse + **/GrizzlyAsyncHttpProvider + **/GrizzlyAsyncHttpProvider$* + **/GrizzlyResponse + **/JDKAsyncHttpProvider + **/JDKAsyncHttpProvider$* + **/JDKResponse + **/NettyAsyncHttpProvider + **/NettyAsyncHttpProvider$* + **/NettyResponse + **/AsyncHttpProviderUtils From f4c4d81ad916d90d80b39ed496aa1122f25a5e25 Mon Sep 17 00:00:00 2001 From: Ryan Lubke Date: Fri, 22 Feb 2013 14:41:00 -0800 Subject: [PATCH 040/264] Port changes for #230 from master to 1.7. --- .../ning/http/client/consumers/AppendableBodyConsumer.java | 5 ++++- .../com/ning/http/client/consumers/FileBodyConsumer.java | 4 +++- .../ning/http/client/consumers/OutputStreamBodyConsumer.java | 4 +++- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/ning/http/client/consumers/AppendableBodyConsumer.java b/src/main/java/com/ning/http/client/consumers/AppendableBodyConsumer.java index ef04f9b8da..e2976facb5 100644 --- a/src/main/java/com/ning/http/client/consumers/AppendableBodyConsumer.java +++ b/src/main/java/com/ning/http/client/consumers/AppendableBodyConsumer.java @@ -41,7 +41,10 @@ public AppendableBodyConsumer(Appendable appendable) { */ /* @Override */ public void consume(ByteBuffer byteBuffer) throws IOException { - appendable.append(new String(byteBuffer.array(), encoding)); + appendable.append(new String(byteBuffer.array(), + byteBuffer.arrayOffset() + byteBuffer.position(), + byteBuffer.remaining(), + encoding)); } /** diff --git a/src/main/java/com/ning/http/client/consumers/FileBodyConsumer.java b/src/main/java/com/ning/http/client/consumers/FileBodyConsumer.java index ad8b7e288f..02a12d65fd 100644 --- a/src/main/java/com/ning/http/client/consumers/FileBodyConsumer.java +++ b/src/main/java/com/ning/http/client/consumers/FileBodyConsumer.java @@ -35,7 +35,9 @@ public FileBodyConsumer(RandomAccessFile file) { /* @Override */ public void consume(ByteBuffer byteBuffer) throws IOException { // TODO: Channel.transferFrom may be a good idea to investigate. - file.write(byteBuffer.array()); + file.write(byteBuffer.array(), + byteBuffer.arrayOffset() + byteBuffer.position(), + byteBuffer.remaining()); } /** diff --git a/src/main/java/com/ning/http/client/consumers/OutputStreamBodyConsumer.java b/src/main/java/com/ning/http/client/consumers/OutputStreamBodyConsumer.java index d1e806ca43..9f8c93aec1 100644 --- a/src/main/java/com/ning/http/client/consumers/OutputStreamBodyConsumer.java +++ b/src/main/java/com/ning/http/client/consumers/OutputStreamBodyConsumer.java @@ -34,7 +34,9 @@ public OutputStreamBodyConsumer(OutputStream outputStream) { */ /* @Override */ public void consume(ByteBuffer byteBuffer) throws IOException { - outputStream.write(byteBuffer.array()); + outputStream.write(byteBuffer.array(), + byteBuffer.arrayOffset() + byteBuffer.position(), + byteBuffer.remaining()); } /** From 091740ea480dcfee46803133b14cffcd4d08d706 Mon Sep 17 00:00:00 2001 From: Ryan Lubke Date: Fri, 22 Feb 2013 15:33:02 -0800 Subject: [PATCH 041/264] data may come in separate chunks. Test needs to account for this. --- .../com/ning/http/client/async/BasicHttpsTest.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/test/java/com/ning/http/client/async/BasicHttpsTest.java b/src/test/java/com/ning/http/client/async/BasicHttpsTest.java index bcd508e2d6..1f928c53e1 100644 --- a/src/test/java/com/ning/http/client/async/BasicHttpsTest.java +++ b/src/test/java/com/ning/http/client/async/BasicHttpsTest.java @@ -122,10 +122,16 @@ public void handle(String pathInContext, size = httpRequest.getContentLength(); } byte[] bytes = new byte[size]; + int pos = 0; if (bytes.length > 0) { //noinspection ResultOfMethodCallIgnored - int read = httpRequest.getInputStream().read(bytes); - httpResponse.getOutputStream().write(bytes, 0, read); + int read = 0; + while (read != -1) { + read = httpRequest.getInputStream().read(bytes, pos, bytes.length - pos); + pos += read; + } + + httpResponse.getOutputStream().write(bytes); } httpResponse.setStatus(200); From 36d22cfc75dc1d8ac786dbd0e3e6f197e18d84f5 Mon Sep 17 00:00:00 2001 From: Ryan Lubke Date: Fri, 22 Feb 2013 15:33:51 -0800 Subject: [PATCH 042/264] Port changes from PR #214 from master to 1.7. --- .../grizzly/GrizzlyAsyncHttpProvider.java | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java index cce8481020..068cf267c7 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java @@ -18,6 +18,7 @@ import com.ning.http.client.AsyncHttpProvider; import com.ning.http.client.Body; import com.ning.http.client.BodyGenerator; +import com.ning.http.client.ConnectionPoolKeyStrategy; import com.ning.http.client.ConnectionsPool; import com.ning.http.client.Cookie; import com.ning.http.client.FluentCaseInsensitiveStringsMap; @@ -1430,7 +1431,7 @@ private static HttpTransactionContext cleanup(final FilterChainContext ctx, if (!context.provider.connectionManager.canReturnConnection(c)) { context.abort(new IOException("Maximum pooled connections exceeded")); } else { - if (!context.provider.connectionManager.returnConnection(context.requestUrl, c)) { + if (!context.provider.connectionManager.returnConnection(context.request, c)) { ctx.getConnection().close(); } } @@ -2305,7 +2306,7 @@ void doAsyncTrackedConnection(final Request request, final CompletionHandler connectHandler) throws IOException, ExecutionException, InterruptedException { final String url = request.getUrl(); - Connection c = pool.poll(AsyncHttpProviderUtils.getBaseUrl(url)); + Connection c = pool.poll(getPoolKey(request)); if (c == null) { if (!connectionMonitor.acquire()) { throw new IOException("Max connections exceeded"); @@ -2390,9 +2391,9 @@ private ProxyServer getProxyServer(Request request) { } - boolean returnConnection(final String url, final Connection c) { + boolean returnConnection(final Request request, final Connection c) { final boolean result = (DO_NOT_CACHE.get(c) == null - && pool.offer(AsyncHttpProviderUtils.getBaseUrl(url), c)); + && pool.offer(getPoolKey(request), c)); if (result) { if (provider.resolver != null) { provider.resolver.setTimeoutMillis(c, IdleTimeoutFilter.FOREVER); @@ -2453,6 +2454,11 @@ public void updated(Connection result) { }; } + private static String getPoolKey(final Request request) { + final ConnectionPoolKeyStrategy keyStrategy = request.getConnectionPoolKeyStrategy(); + return keyStrategy.getKey(AsyncHttpProviderUtils.createUri(AsyncHttpProviderUtils.getBaseUrl(request.getUrl()))); + } + // ------------------------------------------------------ Nested Classes private static class ConnectionMonitor implements Connection.CloseListener { From 6a167739d3a35d3bffca9ff9f16dd238e2146e20 Mon Sep 17 00:00:00 2001 From: Ryan Lubke Date: Fri, 22 Feb 2013 15:34:40 -0800 Subject: [PATCH 043/264] Return SSL tests to run status. Delegate task handling was tripping up over the UnsupportedOperationException. --- .../java/com/ning/http/client/async/NoNullResponseTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/com/ning/http/client/async/NoNullResponseTest.java b/src/test/java/com/ning/http/client/async/NoNullResponseTest.java index cc9f0890e3..2dcb653225 100644 --- a/src/test/java/com/ning/http/client/async/NoNullResponseTest.java +++ b/src/test/java/com/ning/http/client/async/NoNullResponseTest.java @@ -72,11 +72,11 @@ private SSLContext getSSLContext() throws GeneralSecurityException { private static class MockTrustManager implements X509TrustManager { public X509Certificate[] getAcceptedIssuers() { - throw new UnsupportedOperationException(); + return null; } public void checkClientTrusted(final X509Certificate[] chain, final String authType) throws CertificateException { - throw new UnsupportedOperationException(); + // Do nothing. } public void checkServerTrusted(final X509Certificate[] chain, final String authType) throws CertificateException { From 403b9a8465697ee75ed18984dcf11cca85728f83 Mon Sep 17 00:00:00 2001 From: Ryan Lubke Date: Fri, 22 Feb 2013 15:34:54 -0800 Subject: [PATCH 044/264] Upgrade to Grizzly 2.2.21. --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 277ab625fa..32cc44b8f9 100644 --- a/pom.xml +++ b/pom.xml @@ -545,7 +545,7 @@ org.glassfish.grizzly grizzly-websockets - 2.2.16 + 2.2.21 true From 3cf8b09f2910f5e85564f1bb47490ff655090a7e Mon Sep 17 00:00:00 2001 From: Ryan Lubke Date: Fri, 22 Feb 2013 15:46:00 -0800 Subject: [PATCH 045/264] Data may come in separate chunks. --- .../ning/http/client/async/HostnameVerifierTest.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/test/java/com/ning/http/client/async/HostnameVerifierTest.java b/src/test/java/com/ning/http/client/async/HostnameVerifierTest.java index e2bff473b1..d162dc395b 100644 --- a/src/test/java/com/ning/http/client/async/HostnameVerifierTest.java +++ b/src/test/java/com/ning/http/client/async/HostnameVerifierTest.java @@ -111,10 +111,16 @@ public void handle(String pathInContext, size = httpRequest.getContentLength(); } byte[] bytes = new byte[size]; + int pos = 0; if (bytes.length > 0) { //noinspection ResultOfMethodCallIgnored - int read = httpRequest.getInputStream().read(bytes); - httpResponse.getOutputStream().write(bytes, 0, read); + int read = 0; + while (read != -1) { + read = httpRequest.getInputStream().read(bytes, pos, bytes.length - pos); + pos += read; + } + + httpResponse.getOutputStream().write(bytes); } httpResponse.setStatus(200); From d5b88eea3d128b946830442527132429d7c1753b Mon Sep 17 00:00:00 2001 From: Ryan Lubke Date: Fri, 22 Feb 2013 16:34:49 -0800 Subject: [PATCH 046/264] Grizzly-related changes for #207. By default, fragments will be buffered. Once the last fragment has been received the full message will be passed to the listener. Original functionality can be re-enabled by setting the BUFFER_WEBSOCKET_FRAGMENTS to false on the GrizzlyAsyncHttpProviderConfig instance. --- .../grizzly/GrizzlyAsyncHttpProvider.java | 80 ++++++++++++++++--- .../GrizzlyAsyncHttpProviderConfig.java | 7 ++ 2 files changed, 74 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java index 068cf267c7..d66fe72aa1 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java @@ -16,6 +16,7 @@ import com.ning.http.client.AsyncHandler; import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.AsyncHttpProvider; +import com.ning.http.client.AsyncHttpProviderConfig; import com.ning.http.client.Body; import com.ning.http.client.BodyGenerator; import com.ning.http.client.ConnectionPoolKeyStrategy; @@ -111,6 +112,7 @@ import org.slf4j.LoggerFactory; import javax.net.ssl.SSLContext; +import java.io.ByteArrayOutputStream; import java.io.EOFException; import java.io.File; import java.io.FileInputStream; @@ -135,6 +137,7 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; +import static com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProviderConfig.Property.BUFFER_WEBSOCKET_FRAGMENTS; import static com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProviderConfig.Property.MAX_HTTP_PACKET_HEADER_SIZE; import static com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProviderConfig.Property.TRANSPORT_CUSTOMIZER; @@ -1316,8 +1319,9 @@ protected void onHttpHeadersParsed(HttpHeader httpHeader, if (context.isWSRequest) { try { context.protocolHandler.setConnection(ctx.getConnection()); - DefaultWebSocket ws = new DefaultWebSocket(context.protocolHandler); - context.webSocket = new GrizzlyWebSocketAdapter(ws); + final GrizzlyWebSocketAdapter webSocketAdapter = createWebSocketAdapter(context); + context.webSocket = webSocketAdapter; + DefaultWebSocket ws = webSocketAdapter.gWebSocket; if (context.currentState == AsyncHandler.STATE.UPGRADE) { httpHeader.setChunked(false); ws.onConnect(); @@ -1409,6 +1413,16 @@ protected boolean onHttpPacketParsed(HttpHeader httpHeader, FilterChainContext c // ----------------------------------------------------- Private Methods + private static GrizzlyWebSocketAdapter createWebSocketAdapter(final HttpTransactionContext context) { + DefaultWebSocket ws = new DefaultWebSocket(context.protocolHandler); + AsyncHttpProviderConfig config = context.provider.clientConfig.getAsyncHttpProviderConfig(); + boolean bufferFragments = true; + if (config instanceof GrizzlyAsyncHttpProviderConfig) { + bufferFragments = (Boolean) ((GrizzlyAsyncHttpProviderConfig) config).getProperty(BUFFER_WEBSOCKET_FRAGMENTS); + } + + return new GrizzlyWebSocketAdapter(ws, bufferFragments); + } private static boolean isRedirectAllowed(final HttpTransactionContext ctx) { boolean allowed = ctx.request.isRedirectEnabled(); @@ -2619,13 +2633,16 @@ public void getBytes(byte[] bytes) { private static final class GrizzlyWebSocketAdapter implements WebSocket { - private final org.glassfish.grizzly.websockets.WebSocket gWebSocket; + final DefaultWebSocket gWebSocket; + final boolean bufferFragments; // -------------------------------------------------------- Constructors - GrizzlyWebSocketAdapter(final org.glassfish.grizzly.websockets.WebSocket gWebSocket) { - this.gWebSocket = gWebSocket; + GrizzlyWebSocketAdapter(final DefaultWebSocket gWebSocket, + final boolean bufferFragments) { + this.gWebSocket = gWebSocket; + this.bufferFragments = bufferFragments; } @@ -2706,14 +2723,25 @@ public void close() { private static final class AHCWebSocketListenerAdapter implements org.glassfish.grizzly.websockets.WebSocketListener { private final WebSocketListener ahcListener; - private final WebSocket webSocket; + private final GrizzlyWebSocketAdapter webSocket; + private final StringBuilder stringBuffer; + private final ByteArrayOutputStream byteArrayOutputStream; + // -------------------------------------------------------- Constructors - AHCWebSocketListenerAdapter(final WebSocketListener ahcListener, WebSocket webSocket) { + AHCWebSocketListenerAdapter(final WebSocketListener ahcListener, + final GrizzlyWebSocketAdapter webSocket) { this.ahcListener = ahcListener; this.webSocket = webSocket; + if (webSocket.bufferFragments) { + stringBuffer = new StringBuilder(); + byteArrayOutputStream = new ByteArrayOutputStream(); + } else { + stringBuffer = null; + byteArrayOutputStream = null; + } } @@ -2788,10 +2816,23 @@ public void onPong(org.glassfish.grizzly.websockets.WebSocket webSocket, byte[] } @Override - public void onFragment(org.glassfish.grizzly.websockets.WebSocket webSocket, String s, boolean b) { + public void onFragment(org.glassfish.grizzly.websockets.WebSocket webSocket, String s, boolean last) { try { - if (WebSocketTextListener.class.isAssignableFrom(ahcListener.getClass())) { - WebSocketTextListener.class.cast(ahcListener).onFragment(s, b); + if (this.webSocket.bufferFragments) { + synchronized (this.webSocket) { + stringBuffer.append(s); + if (last) { + if (WebSocketTextListener.class.isAssignableFrom(ahcListener.getClass())) { + final String message = stringBuffer.toString(); + stringBuffer.setLength(0); + WebSocketTextListener.class.cast(ahcListener).onMessage(message); + } + } + } + } else { + if (WebSocketTextListener.class.isAssignableFrom(ahcListener.getClass())) { + WebSocketTextListener.class.cast(ahcListener).onFragment(s, last); + } } } catch (Throwable e) { ahcListener.onError(e); @@ -2799,10 +2840,23 @@ public void onFragment(org.glassfish.grizzly.websockets.WebSocket webSocket, Str } @Override - public void onFragment(org.glassfish.grizzly.websockets.WebSocket webSocket, byte[] bytes, boolean b) { + public void onFragment(org.glassfish.grizzly.websockets.WebSocket webSocket, byte[] bytes, boolean last) { try { - if (WebSocketByteListener.class.isAssignableFrom(ahcListener.getClass())) { - WebSocketByteListener.class.cast(ahcListener).onFragment(bytes, b); + if (this.webSocket.bufferFragments) { + synchronized (this.webSocket) { + byteArrayOutputStream.write(bytes); + if (last) { + if (WebSocketByteListener.class.isAssignableFrom(ahcListener.getClass())) { + final byte[] bytesLocal = byteArrayOutputStream.toByteArray(); + byteArrayOutputStream.reset(); + WebSocketByteListener.class.cast(ahcListener).onMessage(bytesLocal); + } + } + } + } else { + if (WebSocketByteListener.class.isAssignableFrom(ahcListener.getClass())) { + WebSocketByteListener.class.cast(ahcListener).onFragment(bytes, last); + } } } catch (Throwable e) { ahcListener.onError(e); diff --git a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProviderConfig.java b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProviderConfig.java index 8751195bbd..066e1a959d 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProviderConfig.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProviderConfig.java @@ -59,6 +59,13 @@ public static enum Property { MAX_HTTP_PACKET_HEADER_SIZE(Integer.class, HttpCodecFilter.DEFAULT_MAX_HTTP_PACKET_HEADER_SIZE), + /** + * By default, Websocket messages that are fragmented will be buffered. Once all + * fragments have been accumulated, the appropriate onMessage() call back will be + * invoked with the complete message. If this functionality is not desired, set + * this property to false. + */ + BUFFER_WEBSOCKET_FRAGMENTS(Boolean.class, true) ; From 7db68611cf952f191615a6233839c6b48d4f50d9 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 25 Feb 2013 09:24:13 +0100 Subject: [PATCH 047/264] Introduce getResponseBodyAsByteBuffer, directly read from Netty ChannelBuffers --- pom.xml | 20 +------ .../java/com/ning/http/client/Response.java | 10 +++- .../providers/apache/ApacheResponse.java | 5 ++ .../providers/grizzly/GrizzlyResponse.java | 4 ++ .../client/providers/jdk/JDKResponse.java | 5 ++ .../client/providers/netty/NettyResponse.java | 60 ++++++++++++++----- .../providers/netty/ResponseBodyPart.java | 17 +++--- .../http/client/webdav/WebDavResponse.java | 5 ++ 8 files changed, 82 insertions(+), 44 deletions(-) diff --git a/pom.xml b/pom.xml index 32cc44b8f9..a61b194e90 100644 --- a/pom.xml +++ b/pom.xml @@ -76,25 +76,7 @@ io.netty netty - 3.4.4.Final - - - javax.servlet - servlet-api - - - commons-logging - commons-logging - - - org.slf4j - slf4j-api - - - log4j - log4j - - + 3.6.3.Final diff --git a/src/main/java/com/ning/http/client/Response.java b/src/main/java/com/ning/http/client/Response.java index 54ddddf6bc..a4b98464b5 100644 --- a/src/main/java/com/ning/http/client/Response.java +++ b/src/main/java/com/ning/http/client/Response.java @@ -20,8 +20,8 @@ import java.io.InputStream; import java.net.MalformedURLException; import java.net.URI; +import java.nio.ByteBuffer; import java.util.ArrayList; -import java.util.Collection; import java.util.Collections; import java.util.List; @@ -51,6 +51,14 @@ public interface Response { */ public byte[] getResponseBodyAsBytes() throws IOException; + /** + * Return the entire response body as a ByteBuffer. + * + * @return the entire response body as a ByteBuffer. + * @throws IOException + */ + public ByteBuffer getResponseBodyAsByteBuffer() throws IOException; + /** * Returns an input stream for the response body. Note that you should not try to get this more than once, * and that you should not close the stream. diff --git a/src/main/java/com/ning/http/client/providers/apache/ApacheResponse.java b/src/main/java/com/ning/http/client/providers/apache/ApacheResponse.java index 3d8ec79800..52a99f3f13 100644 --- a/src/main/java/com/ning/http/client/providers/apache/ApacheResponse.java +++ b/src/main/java/com/ning/http/client/providers/apache/ApacheResponse.java @@ -24,6 +24,7 @@ import java.io.InputStream; import java.net.MalformedURLException; import java.net.URI; +import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -67,6 +68,10 @@ public byte[] getResponseBodyAsBytes() throws IOException { return AsyncHttpProviderUtils.contentToByte(bodyParts); } + public ByteBuffer getResponseBodyAsByteBuffer() throws IOException { + return ByteBuffer.wrap(getResponseBodyAsBytes()); + } + /* @Override */ public String getResponseBody() throws IOException { return getResponseBody(DEFAULT_CHARSET); diff --git a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponse.java b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponse.java index 1119e00f88..23abef2d52 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponse.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponse.java @@ -33,6 +33,7 @@ import java.io.InputStream; import java.net.MalformedURLException; import java.net.URI; +import java.nio.ByteBuffer; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Collection; @@ -174,6 +175,9 @@ public byte[] getResponseBodyAsBytes() throws IOException { } + public ByteBuffer getResponseBodyAsByteBuffer() throws IOException { + return ByteBuffer.wrap(getResponseBodyAsBytes()); + } /** * {@inheritDoc} diff --git a/src/main/java/com/ning/http/client/providers/jdk/JDKResponse.java b/src/main/java/com/ning/http/client/providers/jdk/JDKResponse.java index f7fd04603e..987ef72044 100644 --- a/src/main/java/com/ning/http/client/providers/jdk/JDKResponse.java +++ b/src/main/java/com/ning/http/client/providers/jdk/JDKResponse.java @@ -25,6 +25,7 @@ import java.io.InputStream; import java.net.MalformedURLException; import java.net.URI; +import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -77,6 +78,10 @@ public byte[] getResponseBodyAsBytes() throws IOException { return AsyncHttpProviderUtils.contentToByte(bodyParts); } + public ByteBuffer getResponseBodyAsByteBuffer() throws IOException { + return ByteBuffer.wrap(getResponseBodyAsBytes()); + } + public String getResponseBody(String charset) throws IOException { if (!contentComputed.get()) { diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyResponse.java b/src/main/java/com/ning/http/client/providers/netty/NettyResponse.java index a0a243a907..2072a3708c 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyResponse.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyResponse.java @@ -27,16 +27,22 @@ import java.io.InputStream; import java.net.MalformedURLException; import java.net.URI; +import java.nio.ByteBuffer; +import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; +import org.jboss.netty.buffer.ChannelBuffer; +import org.jboss.netty.buffer.ChannelBufferInputStream; +import org.jboss.netty.buffer.ChannelBuffers; + /** * Wrapper around the {@link com.ning.http.client.Response} API. */ public class NettyResponse implements Response { - private final static String DEFAULT_CHARSET = "ISO-8859-1"; + private final static Charset DEFAULT_CHARSET = Charset.forName("ISO-8859-1"); private final URI uri; private final List bodyParts; @@ -68,7 +74,11 @@ public String getStatusText() { /* @Override */ public byte[] getResponseBodyAsBytes() throws IOException { - return AsyncHttpProviderUtils.contentToByte(bodyParts); + return getResponseBodyAsByteBuffer().array(); + } + + public ByteBuffer getResponseBodyAsByteBuffer() throws IOException { + return getResponseBodyAsChannelBuffer().toByteBuffer(); } /* @Override */ @@ -77,12 +87,32 @@ public String getResponseBody() throws IOException { } public String getResponseBody(String charset) throws IOException { - return AsyncHttpProviderUtils.contentToString(bodyParts, computeCharset(charset)); + return getResponseBodyAsChannelBuffer().toString(computeCharset(charset)); } /* @Override */ public InputStream getResponseBodyAsStream() throws IOException { - return AsyncHttpProviderUtils.contentToInputStream(bodyParts); + return new ChannelBufferInputStream(getResponseBodyAsChannelBuffer()); + } + + public ChannelBuffer getResponseBodyAsChannelBuffer() throws IOException { + ChannelBuffer b = null; + switch (bodyParts.size()) { + case 0: + b = ChannelBuffers.EMPTY_BUFFER; + break; + case 1: + b = ResponseBodyPart.class.cast(bodyParts.get(0)).getChannelBuffer(); + break; + default: + ChannelBuffer[] channelBuffers = new ChannelBuffer[bodyParts.size()]; + for (int i = 0; i < bodyParts.size(); i++) { + channelBuffers[i] = ResponseBodyPart.class.cast(bodyParts.get(i)).getChannelBuffer(); + } + b = ChannelBuffers.wrappedBuffer(channelBuffers); + } + + return b; } /* @Override */ @@ -92,17 +122,17 @@ public String getResponseBodyExcerpt(int maxLength) throws IOException { } public String getResponseBodyExcerpt(int maxLength, String charset) throws IOException { - String response = AsyncHttpProviderUtils.contentToString(bodyParts, computeCharset(charset)); + String response = getResponseBody(charset); return response.length() <= maxLength ? response : response.substring(0, maxLength); } - - private String computeCharset(String charset) { + + private Charset computeCharset(String charset) { if (charset == null) { - String contentType = getContentType(); - if (contentType != null) - charset = AsyncHttpProviderUtils.parseCharset(contentType); // parseCharset can return null + String contentType = getContentType(); + if (contentType != null) + charset = AsyncHttpProviderUtils.parseCharset(contentType); // parseCharset can return null } - return charset != null? charset: DEFAULT_CHARSET; + return charset != null ? Charset.forName(charset) : DEFAULT_CHARSET; } /* @Override */ @@ -120,19 +150,19 @@ public String getContentType() { /* @Override */ public String getHeader(String name) { - return headers != null? headers.getHeaders().getFirstValue(name): null; + return headers != null ? headers.getHeaders().getFirstValue(name) : null; } /* @Override */ public List getHeaders(String name) { - return headers != null? headers.getHeaders().get(name): Collections. emptyList(); + return headers != null ? headers.getHeaders().get(name) : Collections. emptyList(); } /* @Override */ public FluentCaseInsensitiveStringsMap getHeaders() { - return headers != null? headers.getHeaders(): new FluentCaseInsensitiveStringsMap(); + return headers != null ? headers.getHeaders() : new FluentCaseInsensitiveStringsMap(); } /* @Override */ @@ -148,7 +178,7 @@ public List getCookies() { return Collections.emptyList(); } if (cookies == null) { - List localCookies = new ArrayList(); + List localCookies = new ArrayList(); for (Map.Entry> header : headers.getHeaders().entrySet()) { if (header.getKey().equalsIgnoreCase("Set-Cookie")) { // TODO: ask for parsed header diff --git a/src/main/java/com/ning/http/client/providers/netty/ResponseBodyPart.java b/src/main/java/com/ning/http/client/providers/netty/ResponseBodyPart.java index 8279c76d77..adc744716d 100644 --- a/src/main/java/com/ning/http/client/providers/netty/ResponseBodyPart.java +++ b/src/main/java/com/ning/http/client/providers/netty/ResponseBodyPart.java @@ -63,19 +63,14 @@ public byte[] getBodyPartBytes() { return bytes.get(); } - ChannelBuffer b = chunk != null ? chunk.getContent() : response.getContent(); - int read = b.readableBytes(); - int index = b.readerIndex(); - - byte[] rb = new byte[read]; - b.readBytes(rb); + ChannelBuffer b = getChannelBuffer(); + byte[] rb = b.toByteBuffer().array(); bytes.set(rb); - b.readerIndex(index); - return bytes.get(); + return rb; } public int writeTo(OutputStream outputStream) throws IOException { - ChannelBuffer b = chunk != null ? chunk.getContent() : response.getContent(); + ChannelBuffer b = getChannelBuffer(); int read = b.readableBytes(); int index = b.readerIndex(); if (read > 0) { @@ -85,6 +80,10 @@ public int writeTo(OutputStream outputStream) throws IOException { return read; } + public ChannelBuffer getChannelBuffer() { + return chunk != null ? chunk.getContent() : response.getContent(); + } + @Override public ByteBuffer getBodyByteBuffer() { return ByteBuffer.wrap(getBodyPartBytes()); diff --git a/src/main/java/com/ning/http/client/webdav/WebDavResponse.java b/src/main/java/com/ning/http/client/webdav/WebDavResponse.java index c77cee0320..3a16fc4f00 100644 --- a/src/main/java/com/ning/http/client/webdav/WebDavResponse.java +++ b/src/main/java/com/ning/http/client/webdav/WebDavResponse.java @@ -21,6 +21,7 @@ import java.io.InputStream; import java.net.MalformedURLException; import java.net.URI; +import java.nio.ByteBuffer; import java.util.List; /** @@ -49,6 +50,10 @@ public byte[] getResponseBodyAsBytes() throws IOException { return response.getResponseBodyAsBytes(); } + public ByteBuffer getResponseBodyAsByteBuffer() throws IOException { + return ByteBuffer.wrap(getResponseBodyAsBytes()); + } + public InputStream getResponseBodyAsStream() throws IOException { return response.getResponseBodyAsStream(); } From fa31dec86c77c370f4c531e4af1d396e7ab157aa Mon Sep 17 00:00:00 2001 From: Ryan Lubke Date: Mon, 25 Feb 2013 01:36:49 -0800 Subject: [PATCH 048/264] Minor cleanup to GrizzlyResponse. --- .../client/providers/grizzly/GrizzlyResponse.java | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponse.java b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponse.java index 1119e00f88..b1611b61c8 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponse.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponse.java @@ -160,7 +160,7 @@ public String getResponseBodyExcerpt(int maxLength) throws IOException { */ public String getResponseBody() throws IOException { - return getResponseBody(Charsets.DEFAULT_CHARACTER_ENCODING); + return getResponseBody(null); } @@ -170,10 +170,20 @@ public String getResponseBody() throws IOException { */ public byte[] getResponseBodyAsBytes() throws IOException { - return getResponseBody().getBytes(Charsets.DEFAULT_CHARACTER_ENCODING); + return getResponseBody().getBytes(); } + /** + * @return the response body as a Grizzly {@link Buffer}. + * + * @since 1.7.11. + */ + @SuppressWarnings("UnusedDeclaration") + private Buffer getResponseAsBuffer() { + return responseBody; + } + /** * {@inheritDoc} From 70ee5864a5344740218ee3fe46d840ebfa5df056 Mon Sep 17 00:00:00 2001 From: Ryan Lubke Date: Mon, 25 Feb 2013 01:42:27 -0800 Subject: [PATCH 049/264] Fixed name. --- .../com/ning/http/client/providers/grizzly/GrizzlyResponse.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponse.java b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponse.java index b1611b61c8..2be66e0c6f 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponse.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponse.java @@ -180,7 +180,7 @@ public byte[] getResponseBodyAsBytes() throws IOException { * @since 1.7.11. */ @SuppressWarnings("UnusedDeclaration") - private Buffer getResponseAsBuffer() { + private Buffer getResponseBodyAsBuffer() { return responseBody; } From 615be696904cc15be77a6dd5b50b80f95fa54804 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 25 Feb 2013 15:28:19 +0100 Subject: [PATCH 050/264] Add myself as a developer --- pom.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pom.xml b/pom.xml index a61b194e90..2564784004 100644 --- a/pom.xml +++ b/pom.xml @@ -58,6 +58,11 @@ neotyk Hubert Iwaniuk + + slandelle + Stephane Landelle + slandelle@excilys.com + From 38d5e104fa70c68a8d353e9588b10fa45441d5f1 Mon Sep 17 00:00:00 2001 From: jfarcand Date: Mon, 25 Feb 2013 09:46:16 -0500 Subject: [PATCH 051/264] Fix test --- .../java/com/ning/http/client/async/AsyncStreamHandlerTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/ning/http/client/async/AsyncStreamHandlerTest.java b/src/test/java/com/ning/http/client/async/AsyncStreamHandlerTest.java index 8e77bdd99d..2cce1908d5 100644 --- a/src/test/java/com/ning/http/client/async/AsyncStreamHandlerTest.java +++ b/src/test/java/com/ning/http/client/async/AsyncStreamHandlerTest.java @@ -481,7 +481,7 @@ public void asyncOptionsTest() throws Throwable { public STATE onHeadersReceived(HttpResponseHeaders content) throws Exception { FluentCaseInsensitiveStringsMap h = content.getHeaders(); Assert.assertNotNull(h); - Assert.assertEquals(h.getJoinedValue("Allow", ", "), "GET,HEAD,POST,OPTIONS,TRACE"); + Assert.assertEquals(h.getJoinedValue("Allow", ", "), "OPTIONS,GET,HEAD,POST,TRACE"); return STATE.ABORT; } From 69482f4c040e0060f66b02205c6334ca871d89d4 Mon Sep 17 00:00:00 2001 From: jfarcand Date: Mon, 25 Feb 2013 10:17:59 -0500 Subject: [PATCH 052/264] First pass for #231 --- .../com/ning/http/client/async/AsyncProvidersBasicTest.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java b/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java index 41421e46ef..04ceec6906 100755 --- a/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java +++ b/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java @@ -906,6 +906,9 @@ public void asyncDoPostDelayCancelTest() throws Throwable { public void onThrowable(Throwable t) { } }); + + // Make sure we are connected before cancelling. I know, Thread.sleep sucks! + Thread.sleep(1000); future.cancel(true); Response response = future.get(TIMEOUT, TimeUnit.SECONDS); Assert.assertNull(response); @@ -1553,6 +1556,7 @@ public void onThrowable(Throwable t) { }); + Thread.sleep(1000); future.cancel(true); } catch (IllegalStateException ise) { fail(); From b0c1830f7c496d0c0a6f07b34265efc349674757 Mon Sep 17 00:00:00 2001 From: Ryan Lubke Date: Tue, 26 Feb 2013 09:46:54 -0800 Subject: [PATCH 053/264] Minor change to Grizzly-related #228 changes. --- .../com/ning/http/client/providers/grizzly/GrizzlyResponse.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponse.java b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponse.java index dd009bfe2f..ff54318962 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponse.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponse.java @@ -176,7 +176,7 @@ public byte[] getResponseBodyAsBytes() throws IOException { } public ByteBuffer getResponseBodyAsByteBuffer() throws IOException { - return ByteBuffer.wrap(getResponseBodyAsBytes()); + return responseBody.toByteBuffer(); } /** From 776ec568065197cf31995ff7eb833ae37aca1663 Mon Sep 17 00:00:00 2001 From: Ryan Lubke Date: Thu, 28 Feb 2013 13:49:01 -0800 Subject: [PATCH 054/264] Port fix for #234 to 1.7. --- src/main/java/com/ning/http/client/RequestBuilderBase.java | 2 +- src/test/java/com/ning/http/client/async/PostWithQSTest.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/ning/http/client/RequestBuilderBase.java b/src/main/java/com/ning/http/client/RequestBuilderBase.java index 29b65f3ab8..46b0be93b8 100644 --- a/src/main/java/com/ning/http/client/RequestBuilderBase.java +++ b/src/main/java/com/ning/http/client/RequestBuilderBase.java @@ -163,7 +163,7 @@ private String toUrl(boolean encode) { } else { builder.append(name); } - if (value != null && !value.equals("")) { + if (value != null) { builder.append('='); if (encode) { UTF8UrlEncoder.appendEncoded(builder, value); diff --git a/src/test/java/com/ning/http/client/async/PostWithQSTest.java b/src/test/java/com/ning/http/client/async/PostWithQSTest.java index d99498bd18..6f59c9d93f 100644 --- a/src/test/java/com/ning/http/client/async/PostWithQSTest.java +++ b/src/test/java/com/ning/http/client/async/PostWithQSTest.java @@ -89,7 +89,7 @@ public void postWithNulParamQS() throws IOException, ExecutionException, Timeout /* @Override */ public STATE onStatusReceived(final HttpResponseStatus status) throws Exception { - if (!status.getUrl().toURL().toString().equals("http://127.0.0.1/" + port1 + "/?a")) { + if (!status.getUrl().toURL().toString().equals("http://127.0.0.1/" + port1 + "/?a=")) { throw new IOException(status.getUrl().toURL().toString()); } return super.onStatusReceived(status); @@ -109,7 +109,7 @@ public void postWithNulParamsQS() throws IOException, ExecutionException, Timeou /* @Override */ public STATE onStatusReceived(final HttpResponseStatus status) throws Exception { - if (!status.getUrl().toURL().toString().equals("http://127.0.0.1/" + port1 + "/?a=b&c&d=e")) { + if (!status.getUrl().toURL().toString().equals("http://127.0.0.1/" + port1 + "/?a=b&c=&d=e")) { throw new IOException("failed to parse the query properly"); } return super.onStatusReceived(status); From df40d5f3629ba3d6fac59f8354037a8ad7908367 Mon Sep 17 00:00:00 2001 From: Ryan Lubke Date: Sat, 2 Mar 2013 15:36:27 -0800 Subject: [PATCH 055/264] Fix asyncOptionsTest to be more flexible on order of returned options. Updated Grizzly async provider to use ISO-8859-1 as the default charset for entity bodies when none was specified. --- .../com/ning/http/client/async/AsyncStreamHandlerTest.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/test/java/com/ning/http/client/async/AsyncStreamHandlerTest.java b/src/test/java/com/ning/http/client/async/AsyncStreamHandlerTest.java index 2cce1908d5..3e58bc8871 100644 --- a/src/test/java/com/ning/http/client/async/AsyncStreamHandlerTest.java +++ b/src/test/java/com/ning/http/client/async/AsyncStreamHandlerTest.java @@ -481,7 +481,12 @@ public void asyncOptionsTest() throws Throwable { public STATE onHeadersReceived(HttpResponseHeaders content) throws Exception { FluentCaseInsensitiveStringsMap h = content.getHeaders(); Assert.assertNotNull(h); - Assert.assertEquals(h.getJoinedValue("Allow", ", "), "OPTIONS,GET,HEAD,POST,TRACE"); + String result = h.getJoinedValue("Allow", ", "); + String[] resultParts = result.split(","); + String[] expected = "OPTIONS,GET,HEAD,POST,TRACE".split(","); + Arrays.sort(resultParts); + Arrays.sort(expected); + Assert.assertEquals(expected, resultParts); return STATE.ABORT; } From 7d2e9afd5872e2b5a18f281e37ffa769dc8a7c23 Mon Sep 17 00:00:00 2001 From: Ryan Lubke Date: Sat, 2 Mar 2013 15:37:34 -0800 Subject: [PATCH 056/264] Fix asyncOptionsTest to be more flexible on order of returned options. Updated Grizzly async provider to use ISO-8859-1 as the default charset for entity bodies when none was specified. --- .../client/providers/grizzly/GrizzlyAsyncHttpProvider.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java index d66fe72aa1..1ece4dbdc2 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java @@ -1860,7 +1860,7 @@ public boolean doHandle(final FilterChainContext ctx, String charset = request.getBodyEncoding(); if (charset == null) { - charset = Charsets.DEFAULT_CHARACTER_ENCODING; + charset = Charsets.ASCII_CHARSET.name(); } final byte[] data = new String(request.getByteData(), charset).getBytes(charset); final MemoryManager mm = ctx.getMemoryManager(); @@ -1896,7 +1896,7 @@ public boolean doHandle(final FilterChainContext ctx, String charset = request.getBodyEncoding(); if (charset == null) { - charset = Charsets.DEFAULT_CHARACTER_ENCODING; + charset = Charsets.ASCII_CHARSET.name(); } final byte[] data = request.getStringData().getBytes(charset); final MemoryManager mm = ctx.getMemoryManager(); @@ -1963,7 +1963,7 @@ public boolean doHandle(final FilterChainContext ctx, StringBuilder sb = null; String charset = request.getBodyEncoding(); if (charset == null) { - charset = Charsets.DEFAULT_CHARACTER_ENCODING; + charset = Charsets.ASCII_CHARSET.name(); } final FluentStringsMap params = request.getParams(); if (!params.isEmpty()) { From 8f085d9ce138ee62d01cc2e6359607b65ec48f28 Mon Sep 17 00:00:00 2001 From: Ryan Lubke Date: Sun, 3 Mar 2013 15:08:38 -0800 Subject: [PATCH 057/264] Make sure we close the client when the test is complete. These tests do need some attention. The close() should be in a finally block for those cases where a test fails, or a test is expecting a failure and is allowing the error to be handled by TestNG. --- pom.xml | 1 + .../grizzly/GrizzlyAsyncHttpProvider.java | 1 + .../client/async/AsyncProvidersBasicTest.java | 22 ++++++++++++++----- .../http/client/async/BasicHttpsTest.java | 1 + .../http/client/async/ConnectionPoolTest.java | 2 ++ .../client/async/HostnameVerifierTest.java | 4 ++++ .../http/client/async/RemoteSiteTest.java | 9 ++++++++ .../async/SimpleAsyncHttpClientTest.java | 12 +++++++++- 8 files changed, 45 insertions(+), 7 deletions(-) diff --git a/pom.xml b/pom.xml index 2564784004..bc905dd46a 100644 --- a/pom.xml +++ b/pom.xml @@ -239,6 +239,7 @@ maven-surefire-plugin ${surefire.version} + ${surefire.redirectTestOutputToFile} diff --git a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java index 1ece4dbdc2..c47bbc2f3b 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java @@ -264,6 +264,7 @@ public void close() { } if (timeoutExecutor != null) { timeoutExecutor.stop(); + timeoutExecutor.getThreadPool().shutdownNow(); } } catch (IOException ignored) { } diff --git a/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java b/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java index 04ceec6906..dbe19c1a78 100755 --- a/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java +++ b/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java @@ -1568,17 +1568,25 @@ public void onThrowable(Throwable t) { @Test(groups = {"standalone", "default_provider"}, expectedExceptions = IllegalArgumentException.class) public void getShouldNotAllowBody() throws IllegalArgumentException, IOException { AsyncHttpClient c = getAsyncHttpClient(null); - AsyncHttpClient.BoundRequestBuilder builder = c.prepareGet(getTargetUrl()); - builder.setBody("Boo!"); - builder.execute(); + try { + AsyncHttpClient.BoundRequestBuilder builder = c.prepareGet(getTargetUrl()); + builder.setBody("Boo!"); + builder.execute(); + } finally { + c.close(); + } } @Test(groups = {"standalone", "default_provider"}, expectedExceptions = IllegalArgumentException.class) public void headShouldNotAllowBody() throws IllegalArgumentException, IOException { AsyncHttpClient c = getAsyncHttpClient(null); - AsyncHttpClient.BoundRequestBuilder builder = c.prepareHead(getTargetUrl()); - builder.setBody("Boo!"); - builder.execute(); + try { + AsyncHttpClient.BoundRequestBuilder builder = c.prepareHead(getTargetUrl()); + builder.setBody("Boo!"); + builder.execute(); + } finally { + c.close(); + } } protected String getBrokenTargetUrl() { @@ -1591,6 +1599,7 @@ public void invalidUri() throws Exception { AsyncHttpClient.BoundRequestBuilder builder = c.prepareGet(getBrokenTargetUrl()); Response r = c.executeRequest(builder.build()).get(); assertEquals(200, r.getStatusCode()); + c.close(); } @Test(groups = {"standalone", "default_provider"}) @@ -1599,6 +1608,7 @@ public void asyncHttpClientConfigBeanTest() throws Exception { AsyncHttpClient.BoundRequestBuilder builder = c.prepareGet(getTargetUrl()); Response r = c.executeRequest(builder.build()).get(); assertEquals(200, r.getStatusCode()); + c.close(); } @Test(groups = {"default_provider", "async"}) diff --git a/src/test/java/com/ning/http/client/async/BasicHttpsTest.java b/src/test/java/com/ning/http/client/async/BasicHttpsTest.java index 1f928c53e1..a9a54f20de 100644 --- a/src/test/java/com/ning/http/client/async/BasicHttpsTest.java +++ b/src/test/java/com/ning/http/client/async/BasicHttpsTest.java @@ -224,6 +224,7 @@ public void zeroCopyPostTest() throws Throwable { assertNotNull(resp); assertEquals(resp.getStatusCode(), HttpServletResponse.SC_OK); assertEquals(resp.getResponseBody(), "This is a simple test file"); + client.close(); } @Test(groups = {"standalone", "default_provider"}) diff --git a/src/test/java/com/ning/http/client/async/ConnectionPoolTest.java b/src/test/java/com/ning/http/client/async/ConnectionPoolTest.java index 8f02356c90..184992d572 100644 --- a/src/test/java/com/ning/http/client/async/ConnectionPoolTest.java +++ b/src/test/java/com/ning/http/client/async/ConnectionPoolTest.java @@ -65,6 +65,7 @@ public void testMaxTotalConnections() { } } assertNull(exception); + client.close(); } @Test(groups = {"standalone", "default_provider"}) @@ -96,6 +97,7 @@ public void testMaxTotalConnectionsException() { assertNotNull(exception); assertNotNull(exception.getMessage()); assertEquals(exception.getMessage(),"Too many connections 1"); + client.close(); } @Test(groups = {"standalone", "default_provider", "async"}, enabled = true, invocationCount = 10, alwaysRun = true) diff --git a/src/test/java/com/ning/http/client/async/HostnameVerifierTest.java b/src/test/java/com/ning/http/client/async/HostnameVerifierTest.java index d162dc395b..ca0a4f7c9d 100644 --- a/src/test/java/com/ning/http/client/async/HostnameVerifierTest.java +++ b/src/test/java/com/ning/http/client/async/HostnameVerifierTest.java @@ -212,6 +212,7 @@ public void positiveHostnameVerifierTest() throws Throwable { assertNotNull(resp); assertEquals(resp.getStatusCode(), HttpServletResponse.SC_OK); assertEquals(resp.getResponseBody(), "This is a simple test file"); + client.close(); } @Test(groups = {"standalone", "default_provider"}) @@ -229,6 +230,7 @@ public void negativeHostnameVerifierTest() throws Throwable { } catch (ConnectException ex) { assertEquals(ConnectException.class, ex.getClass()); } + client.close(); } @Test(groups = {"standalone", "default_provider"}) @@ -246,6 +248,7 @@ public void remoteIDHostnameVerifierTest() throws Throwable { } catch (ConnectException ex) { assertEquals(ConnectException.class, ex.getClass()); } + client.close(); } @Test(groups = {"standalone", "default_provider"}) @@ -263,6 +266,7 @@ public void remotePosHostnameVerifierTest() throws Throwable { } catch (ConnectException ex) { assertEquals(ConnectException.class, ex.getClass()); } + client.close(); } public static class PositiveHostVerifier implements HostnameVerifier { diff --git a/src/test/java/com/ning/http/client/async/RemoteSiteTest.java b/src/test/java/com/ning/http/client/async/RemoteSiteTest.java index 17f7cff736..6509b57e59 100644 --- a/src/test/java/com/ning/http/client/async/RemoteSiteTest.java +++ b/src/test/java/com/ning/http/client/async/RemoteSiteTest.java @@ -56,6 +56,7 @@ public void testGoogleCom() throws Throwable { // Works Response response = c.prepareGet("http://www.google.com/").execute().get(10,TimeUnit.SECONDS); assertNotNull(response); + c.close(); } @Test(groups = {"online", "default_provider"}) @@ -65,6 +66,7 @@ public void testMailGoogleCom() throws Throwable { Response response = c.prepareGet("http://mail.google.com/").execute().get(10,TimeUnit.SECONDS); assertNotNull(response); assertEquals(response.getStatusCode(), 200); + c.close(); } @Test(groups = {"online", "default_provider"}) @@ -75,6 +77,7 @@ public void testMicrosoftCom() throws Throwable { Response response = c.prepareGet("http://microsoft.com/").execute().get(10,TimeUnit.SECONDS); assertNotNull(response); assertEquals(response.getStatusCode(), 301); + c.close(); } @Test(groups = {"online", "default_provider"}) @@ -84,6 +87,7 @@ public void testWwwMicrosoftCom() throws Throwable { Response response = c.prepareGet("http://www.microsoft.com/").execute().get(10,TimeUnit.SECONDS); assertNotNull(response); assertEquals(response.getStatusCode(), 302); + c.close(); } @Test(groups = {"online", "default_provider"}) @@ -93,6 +97,7 @@ public void testUpdateMicrosoftCom() throws Throwable { Response response = c.prepareGet("http://update.microsoft.com/").execute().get(10,TimeUnit.SECONDS); assertNotNull(response); assertEquals(response.getStatusCode(), 302); + c.close(); } @Test(groups = {"online", "default_provider"}) @@ -103,6 +108,7 @@ public void testGoogleComWithTimeout() throws Throwable { Response response = c.prepareGet("http://google.com/").execute().get(10,TimeUnit.SECONDS); assertNotNull(response); assertEquals(response.getStatusCode(), 301); + c.close(); } @Test(groups = {"online", "default_provider"}) @@ -175,6 +181,7 @@ public void testUrlRequestParametersEncoding() throws Throwable { log.info(String.format("Executing request [%s] ...", requestUrl2)); Response response = client.prepareGet(requestUrl2).execute().get(); Assert.assertEquals(response.getStatusCode(), 301); + client.close(); } /** @@ -186,6 +193,7 @@ public void testAHC60() throws Throwable { AsyncHttpClient client = getAsyncHttpClient(null); Response response = client.prepareGet("http://www.meetup.com/stackoverflow/Mountain-View-CA/").execute().get(); Assert.assertEquals(response.getStatusCode(), 200); + client.close(); } @Test(groups = {"online", "default_provider"}) @@ -273,6 +281,7 @@ public Response onCompleted() throws Exception { }).get(10, TimeUnit.SECONDS); assertNotNull(response); assertTrue(response.getResponseBody().length() >= 3870); + c.close(); } } diff --git a/src/test/java/com/ning/http/client/async/SimpleAsyncHttpClientTest.java b/src/test/java/com/ning/http/client/async/SimpleAsyncHttpClientTest.java index 2a6cfcfd15..f981fc61b5 100644 --- a/src/test/java/com/ning/http/client/async/SimpleAsyncHttpClientTest.java +++ b/src/test/java/com/ning/http/client/async/SimpleAsyncHttpClientTest.java @@ -12,6 +12,7 @@ */ package com.ning.http.client.async; +import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.ByteArrayPart; import com.ning.http.client.Response; import com.ning.http.client.SimpleAsyncHttpClient; @@ -135,6 +136,8 @@ public void testDerive() throws Exception { SimpleAsyncHttpClient derived = client.derive().build(); assertNotSame(derived, client); + client.close(); + derived.close(); } @Test(groups = { "standalone", "default_provider" }) @@ -207,8 +210,9 @@ public void onBytesReceived(String url, long amount, long current, long total) { @Test(groups = { "standalone", "default_provider" }) public void testNullUrl() throws Exception { try { - new SimpleAsyncHttpClient.Builder().build().derive().build(); + SimpleAsyncHttpClient c = new SimpleAsyncHttpClient.Builder().build().derive().build(); assertTrue(true); + c.close(); } catch (NullPointerException ex) { fail(); } @@ -226,6 +230,8 @@ public void testCloseDerivedValidMaster() throws Exception { Response response = client.get().get(); assertEquals(response.getStatusCode(), 200); + + client.close(); } @Test(groups = { "standalone", "default_provider" }) @@ -262,6 +268,8 @@ public void testMultiPartPut() throws Exception { assertTrue(body.contains("Content-Type: application/test")); assertTrue(body.contains("name=\"baPart")); assertTrue(body.contains("filename=\"fileName")); + + client.close(); } @@ -284,6 +292,8 @@ public void testMultiPartPost() throws Exception { assertTrue(body.contains("Content-Type: application/test")); assertTrue(body.contains("name=\"baPart")); assertTrue(body.contains("filename=\"fileName")); + + client.close(); } From c4e94a169e5bbcef4747f825a3fe972ec66a4c9e Mon Sep 17 00:00:00 2001 From: jfarcand Date: Tue, 5 Mar 2013 08:27:33 -0500 Subject: [PATCH 058/264] [maven-release-plugin] prepare release async-http-client-1.7.11 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index bc905dd46a..66e9786089 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.7.11-SNAPSHOT + 1.7.11 jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From b105cd294e486b30a43b65e3f752730b878e72e0 Mon Sep 17 00:00:00 2001 From: jfarcand Date: Tue, 5 Mar 2013 08:27:39 -0500 Subject: [PATCH 059/264] [maven-release-plugin] prepare for next development iteration --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 66e9786089..3e5f448904 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.7.11 + 1.7.12-SNAPSHOT jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From 560c90b45ebf912af4fa28251c81ac4c3c6e80db Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 7 Mar 2013 14:00:44 +0100 Subject: [PATCH 060/264] Make WebSocket implement Closeable, close #166 --- src/main/java/com/ning/http/client/websocket/WebSocket.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/ning/http/client/websocket/WebSocket.java b/src/main/java/com/ning/http/client/websocket/WebSocket.java index 3917a6b4ad..ae7183fe48 100644 --- a/src/main/java/com/ning/http/client/websocket/WebSocket.java +++ b/src/main/java/com/ning/http/client/websocket/WebSocket.java @@ -12,10 +12,12 @@ */ package com.ning.http.client.websocket; +import java.io.Closeable; + /** * A Websocket client */ -public interface WebSocket { +public interface WebSocket extends Closeable { /** * Send a byte message. From f0fd001e84c0588b9972dbeb7b3933cea9e46fbd Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 7 Mar 2013 14:05:31 +0100 Subject: [PATCH 061/264] Make AsyncHttpClient Closeable in 1.7.x, close #44 --- src/main/java/com/ning/http/client/AsyncHttpClient.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/ning/http/client/AsyncHttpClient.java b/src/main/java/com/ning/http/client/AsyncHttpClient.java index 90c6d5f2fc..99a6a7a4b4 100755 --- a/src/main/java/com/ning/http/client/AsyncHttpClient.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClient.java @@ -25,6 +25,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.io.Closeable; import java.io.IOException; import java.io.InputStream; import java.util.Collection; @@ -138,7 +139,7 @@ * An instance of this class will cache every HTTP 1.1 connections and close them when the {@link AsyncHttpClientConfig#getIdleConnectionTimeoutInMs()} * expires. This object can hold many persistent connections to different host. */ -public class AsyncHttpClient { +public class AsyncHttpClient implements Closeable { private final static String DEFAULT_PROVIDER = "com.ning.http.client.providers.netty.NettyAsyncHttpProvider"; private final AsyncHttpProvider httpProvider; From 3f42040331572c3583ff9db59f1b0ee7383e5e42 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 7 Mar 2013 15:43:46 +0100 Subject: [PATCH 062/264] Add adapter from AHC ListenableFuture to Guava one, close #240, close #98 --- pom.xml | 7 +++ .../client/extra/ListenableFutureAdapter.java | 57 +++++++++++++++++++ 2 files changed, 64 insertions(+) create mode 100644 src/main/java/com/ning/http/client/extra/ListenableFutureAdapter.java diff --git a/pom.xml b/pom.xml index 3e5f448904..48fd9e451a 100644 --- a/pom.xml +++ b/pom.xml @@ -90,6 +90,13 @@ 1.6.2 + + com.google.guava + guava + 11.0.2 + true + + ch.qos.logback diff --git a/src/main/java/com/ning/http/client/extra/ListenableFutureAdapter.java b/src/main/java/com/ning/http/client/extra/ListenableFutureAdapter.java new file mode 100644 index 0000000000..7d32343fca --- /dev/null +++ b/src/main/java/com/ning/http/client/extra/ListenableFutureAdapter.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2010-2012 Sonatype, Inc. All rights reserved. + * + * This program is licensed to you under the Apache License Version 2.0, + * and you may not use this file except in compliance with the Apache License Version 2.0. + * You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the Apache License Version 2.0 is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under. + */ +package com.ning.http.client.extra; + +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executor; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import com.ning.http.client.ListenableFuture; + +public final class ListenableFutureAdapter { + + /** + * @param future an AHC ListenableFuture + * @return a Guava ListenableFuture + */ + public static com.google.common.util.concurrent.ListenableFuture asGuavaFuture(final ListenableFuture future) { + + return new com.google.common.util.concurrent.ListenableFuture() { + + public boolean cancel(boolean mayInterruptIfRunning) { + return future.cancel(mayInterruptIfRunning); + } + + public V get() throws InterruptedException, ExecutionException { + return future.get(); + } + + public V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { + return future.get(timeout, unit); + } + + public boolean isCancelled() { + return future.isCancelled(); + } + + public boolean isDone() { + return future.isDone(); + } + + public void addListener(final Runnable runnable, final Executor executor) { + future.addListener(runnable, executor); + } + }; + } +} From 84c3999229e236ff23f30cfeaf013fd31d02c469 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 8 Mar 2013 07:17:39 +0100 Subject: [PATCH 063/264] Backport 4c867952bfc2debebb265266ed524323114aab7a on 1.7.x, close #213 --- .../http/client/providers/netty/NettyAsyncHttpProvider.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java index c30b2cd8ab..6c565b8f00 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java @@ -2200,6 +2200,7 @@ public void handle(final ChannelHandlerContext ctx, final MessageEvent e) throws //} if (statusCode == 401 + && realm != null && wwwAuth.size() > 0 && !future.getAndSetAuth(true)) { @@ -2257,6 +2258,7 @@ public Object call() throws Exception { List proxyAuth = getAuthorizationToken(response.getHeaders(), HttpHeaders.Names.PROXY_AUTHENTICATE); if (statusCode == 407 + && realm != null && proxyAuth.size() > 0 && !future.getAndSetAuth(true)) { From 5faa1cd1ac0662596c5c73da6d87142f54bc7093 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 8 Mar 2013 09:38:02 +0100 Subject: [PATCH 064/264] Fix ssl doc typo, close #87 --- src/site/apt/ssl.apt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/site/apt/ssl.apt b/src/site/apt/ssl.apt index 9c7e5db94e..aeb3e958a9 100644 --- a/src/site/apt/ssl.apt +++ b/src/site/apt/ssl.apt @@ -35,6 +35,6 @@ SecureRandom secureRandom = new SecureRandom(); SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(keyManagers, trustManagers, secureRandom); Builder builder = new AsyncHttpClientConfig.Builder(); -builder.setSSLContext(myOwnThreadPool); +builder.setSSLContext(sslContext); AsyncHttpClient client = new AsyncHttpClient(builder.build()); +-----+ From b1a6280636f521282b9f827a7b13d75ca0ba94a5 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 8 Mar 2013 15:11:03 +0100 Subject: [PATCH 065/264] Sick with those (not null and not empty) tests everywhere --- src/main/java/com/ning/http/client/Realm.java | 4 ++- .../ning/http/client/RequestBuilderBase.java | 10 +++--- .../com/ning/http/client/ntlm/NTLMEngine.java | 15 ++++---- .../apache/ApacheAsyncHttpProvider.java | 4 ++- .../providers/apache/ApacheResponse.java | 4 ++- .../grizzly/GrizzlyAsyncHttpProvider.java | 20 +++++------ .../providers/grizzly/GrizzlyResponse.java | 10 +++--- .../providers/jdk/JDKAsyncHttpProvider.java | 6 ++-- .../client/providers/jdk/JDKResponse.java | 4 ++- .../netty/NettyAsyncHttpProvider.java | 23 ++++++------- .../client/providers/netty/NettyResponse.java | 4 ++- .../ning/http/util/AuthenticatorUtils.java | 4 ++- .../java/com/ning/http/util/MiscUtil.java | 34 +++++++++++++++++++ .../client/async/AsyncProvidersBasicTest.java | 7 ++-- .../async/AsyncStreamLifecycleTest.java | 2 +- .../ning/http/client/async/EmptyBodyTest.java | 2 +- .../http/client/async/ParamEncodingTest.java | 4 ++- .../http/client/async/PostWithQSTest.java | 4 ++- .../client/async/QueryParametersTest.java | 4 ++- .../com/ning/http/client/async/RC10KTest.java | 2 +- 20 files changed, 114 insertions(+), 53 deletions(-) create mode 100644 src/main/java/com/ning/http/util/MiscUtil.java diff --git a/src/main/java/com/ning/http/client/Realm.java b/src/main/java/com/ning/http/client/Realm.java index 07c84bfa3a..8e68142c98 100644 --- a/src/main/java/com/ning/http/client/Realm.java +++ b/src/main/java/com/ning/http/client/Realm.java @@ -16,6 +16,8 @@ */ package com.ning.http.client; +import static com.ning.http.util.MiscUtil.isNonEmpty; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -579,7 +581,7 @@ private static String toBase16(byte[] bytes) { public Realm build() { // Avoid generating - if (nonce != null && !nonce.equals("")) { + if (isNonEmpty(nonce)) { newCnonce(); try { newResponse(); diff --git a/src/main/java/com/ning/http/client/RequestBuilderBase.java b/src/main/java/com/ning/http/client/RequestBuilderBase.java index 46b0be93b8..b860cc580e 100644 --- a/src/main/java/com/ning/http/client/RequestBuilderBase.java +++ b/src/main/java/com/ning/http/client/RequestBuilderBase.java @@ -15,6 +15,8 @@ */ package com.ning.http.client; +import static com.ning.http.util.MiscUtil.isNonEmpty; + import com.ning.http.client.Request.EntityWriter; import com.ning.http.util.UTF8UrlEncoder; import org.slf4j.Logger; @@ -145,7 +147,7 @@ private String toUrl(boolean encode) { } } - if (queryParams != null && !queryParams.isEmpty()) { + if (isNonEmpty(queryParams)) { StringBuilder builder = new StringBuilder(); if (!url.substring(8).contains("/")) { // no other "/" than http[s]:// -> http://localhost:1234 @@ -300,7 +302,7 @@ public String toString() { sb.append("\t"); sb.append(method); sb.append("\theaders:"); - if (headers != null && !headers.isEmpty()) { + if (isNonEmpty(headers)) { for (String name : headers.keySet()) { sb.append("\t"); sb.append(name); @@ -308,7 +310,7 @@ public String toString() { sb.append(headers.getJoinedValue(name, ", ")); } } - if (params != null && !params.isEmpty()) { + if (isNonEmpty(params)) { sb.append("\tparams:"); for (String name : params.keySet()) { sb.append("\t"); @@ -384,7 +386,7 @@ private String buildUrl(String url) { } } - if (uri.getRawQuery() != null && !uri.getRawQuery().equals("")) { + if (isNonEmpty(uri.getRawQuery())) { String[] queries = uri.getRawQuery().split("&"); int pos; for (String query : queries) { diff --git a/src/main/java/com/ning/http/client/ntlm/NTLMEngine.java b/src/main/java/com/ning/http/client/ntlm/NTLMEngine.java index a56c9bf141..00023369ef 100644 --- a/src/main/java/com/ning/http/client/ntlm/NTLMEngine.java +++ b/src/main/java/com/ning/http/client/ntlm/NTLMEngine.java @@ -38,16 +38,19 @@ package com.ning.http.client.ntlm; -import com.ning.http.util.Base64; +import static com.ning.http.util.MiscUtil.isNonEmpty; -import javax.crypto.Cipher; -import javax.crypto.spec.SecretKeySpec; import java.io.UnsupportedEncodingException; import java.security.Key; import java.security.MessageDigest; import java.util.Arrays; import java.util.Locale; +import javax.crypto.Cipher; +import javax.crypto.spec.SecretKeySpec; + +import com.ning.http.util.Base64; + /** * Provides an implementation for NTLMv1, NTLMv2, and NTLM2 Session forms of the NTLM * authentication protocol. @@ -123,12 +126,12 @@ final String getResponseFor(String message, String username, String password, String host, String domain) throws NTLMEngineException { final String response; - if (message == null || message.trim().equals("")) { - response = getType1Message(host, domain); - } else { + if (isNonEmpty(message)) { Type2Message t2m = new Type2Message(message); response = getType3Message(username, password, host, domain, t2m.getChallenge(), t2m .getFlags(), t2m.getTarget(), t2m.getTargetInfo()); + } else { + response = getType1Message(host, domain); } return response; } diff --git a/src/main/java/com/ning/http/client/providers/apache/ApacheAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/apache/ApacheAsyncHttpProvider.java index ac1531bef5..062ab4c689 100644 --- a/src/main/java/com/ning/http/client/providers/apache/ApacheAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/apache/ApacheAsyncHttpProvider.java @@ -12,6 +12,8 @@ */ package com.ning.http.client.providers.apache; +import static com.ning.http.util.MiscUtil.isNonEmpty; + import com.ning.http.client.AsyncHandler; import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.AsyncHttpProvider; @@ -355,7 +357,7 @@ private HttpMethodBase createMethod(HttpClient client, Request request) throws I } method.setFollowRedirects(false); - if ((request.getCookies() != null) && !request.getCookies().isEmpty()) { + if (isNonEmpty(request.getCookies())) { for (Cookie cookie : request.getCookies()) { method.setRequestHeader("Cookie", AsyncHttpProviderUtils.encodeCookies(request.getCookies())); } diff --git a/src/main/java/com/ning/http/client/providers/apache/ApacheResponse.java b/src/main/java/com/ning/http/client/providers/apache/ApacheResponse.java index 52a99f3f13..d899a40ed1 100644 --- a/src/main/java/com/ning/http/client/providers/apache/ApacheResponse.java +++ b/src/main/java/com/ning/http/client/providers/apache/ApacheResponse.java @@ -12,6 +12,8 @@ */ package com.ning.http.client.providers.apache; +import static com.ning.http.util.MiscUtil.isNonEmpty; + import com.ning.http.client.Cookie; import com.ning.http.client.FluentCaseInsensitiveStringsMap; import com.ning.http.client.HttpResponseBodyPart; @@ -190,6 +192,6 @@ public boolean hasResponseHeaders() { */ /* @Override */ public boolean hasResponseBody() { - return bodyParts != null && !bodyParts.isEmpty(); + return isNonEmpty(bodyParts); } } diff --git a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java index c47bbc2f3b..a3cb4613b0 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java @@ -13,6 +13,8 @@ package com.ning.http.client.providers.grizzly; +import static com.ning.http.util.MiscUtil.isNonEmpty; + import com.ning.http.client.AsyncHandler; import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.AsyncHttpProvider; @@ -970,11 +972,11 @@ private void addHeaders(final Request request, final HttpRequestPacket requestPacket) { final FluentCaseInsensitiveStringsMap map = request.getHeaders(); - if (map != null && !map.isEmpty()) { + if (isNonEmpty(map)) { for (final Map.Entry> entry : map.entrySet()) { final String headerName = entry.getKey(); final List headerValues = entry.getValue(); - if (headerValues != null && !headerValues.isEmpty()) { + if (isNonEmpty(headerValues)) { for (final String headerValue : headerValues) { requestPacket.addHeader(headerName, headerValue); } @@ -1003,7 +1005,7 @@ private void addCookies(final Request request, final HttpRequestPacket requestPacket) { final Collection cookies = request.getCookies(); - if (cookies != null && !cookies.isEmpty()) { + if (isNonEmpty(cookies)) { StringBuilder sb = new StringBuilder(128); org.glassfish.grizzly.http.Cookie[] gCookies = new org.glassfish.grizzly.http.Cookie[cookies.size()]; @@ -1037,12 +1039,12 @@ private void addQueryString(final Request request, final HttpRequestPacket requestPacket) { final FluentStringsMap map = request.getQueryParams(); - if (map != null && !map.isEmpty()) { + if (isNonEmpty(map)) { StringBuilder sb = new StringBuilder(128); for (final Map.Entry> entry : map.entrySet()) { final String name = entry.getKey(); final List values = entry.getValue(); - if (values != null && !values.isEmpty()) { + if (isNonEmpty(values)) { try { for (int i = 0, len = values.size(); i < len; i++) { final String value = values.get(i); @@ -1948,8 +1950,7 @@ private final class ParamsBodyHandler implements BodyHandler { public boolean handlesBodyType(final Request request) { - final FluentStringsMap params = request.getParams(); - return (params != null && !params.isEmpty()); + return isNonEmpty(request.getParams()); } @SuppressWarnings({"unchecked"}) @@ -1971,7 +1972,7 @@ public boolean doHandle(final FilterChainContext ctx, for (Map.Entry> entry : params.entrySet()) { String name = entry.getKey(); List values = entry.getValue(); - if (values != null && !values.isEmpty()) { + if (isNonEmpty(values)) { if (sb == null) { sb = new StringBuilder(128); } @@ -2095,8 +2096,7 @@ private static final class PartsBodyHandler implements BodyHandler { public boolean handlesBodyType(final Request request) { - final List parts = request.getParts(); - return (parts != null && !parts.isEmpty()); + return isNonEmpty(request.getParts()); } @SuppressWarnings({"unchecked"}) diff --git a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponse.java b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponse.java index ff54318962..5984d03174 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponse.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponse.java @@ -13,6 +13,8 @@ package com.ning.http.client.providers.grizzly; +import static com.ning.http.util.MiscUtil.isNonEmpty; + import com.ning.http.client.Cookie; import com.ning.http.client.FluentCaseInsensitiveStringsMap; import com.ning.http.client.HttpResponseBodyPart; @@ -68,7 +70,7 @@ public GrizzlyResponse(final HttpResponseStatus status, this.headers = headers; this.bodyParts = bodyParts; - if (bodyParts != null && !bodyParts.isEmpty()) { + if (isNonEmpty(bodyParts)) { if (bodyParts.size() == 1) { responseBody = ((GrizzlyResponseBodyPart) bodyParts.get(0)).getBodyBuffer(); } else { @@ -261,7 +263,7 @@ public List getCookies() { if (cookies == null) { List values = headers.getHeaders().get("set-cookie"); - if (values != null && !values.isEmpty()) { + if (isNonEmpty(values)) { CookiesBuilder.ServerCookiesBuilder builder = new CookiesBuilder.ServerCookiesBuilder(false); for (String header : values) { @@ -290,7 +292,7 @@ public boolean hasResponseStatus() { * {@inheritDoc} */ public boolean hasResponseHeaders() { - return (headers != null && !headers.getHeaders().isEmpty()); + return headers != null && !headers.getHeaders().isEmpty(); } @@ -298,7 +300,7 @@ public boolean hasResponseHeaders() { * {@inheritDoc} */ public boolean hasResponseBody() { - return (bodyParts != null && !bodyParts.isEmpty()); + return isNonEmpty(bodyParts); } diff --git a/src/main/java/com/ning/http/client/providers/jdk/JDKAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/jdk/JDKAsyncHttpProvider.java index 5e3eb656c3..7552246838 100644 --- a/src/main/java/com/ning/http/client/providers/jdk/JDKAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/jdk/JDKAsyncHttpProvider.java @@ -12,6 +12,8 @@ */ package com.ning.http.client.providers.jdk; +import static com.ning.http.util.MiscUtil.isNonEmpty; + import com.ning.http.client.AsyncHandler; import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.AsyncHttpProvider; @@ -517,7 +519,7 @@ private void configure(URI uri, HttpURLConnection urlConnection, Request request AuthenticatorUtils.computeBasicAuthentication(realm)); break; case DIGEST: - if (realm.getNonce() != null && !realm.getNonce().equals("")) { + if (isNonEmpty(realm.getNonce())) { try { urlConnection.setRequestProperty("Authorization", AuthenticatorUtils.computeDigestAuthentication(realm)); @@ -551,7 +553,7 @@ private void configure(URI uri, HttpURLConnection urlConnection, Request request urlConnection.setRequestProperty("User-Agent", AsyncHttpProviderUtils.constructUserAgent(JDKAsyncHttpProvider.class)); } - if (request.getCookies() != null && !request.getCookies().isEmpty()) { + if (isNonEmpty(request.getCookies())) { urlConnection.setRequestProperty("Cookie", AsyncHttpProviderUtils.encodeCookies(request.getCookies())); } diff --git a/src/main/java/com/ning/http/client/providers/jdk/JDKResponse.java b/src/main/java/com/ning/http/client/providers/jdk/JDKResponse.java index 987ef72044..2fe9566e06 100644 --- a/src/main/java/com/ning/http/client/providers/jdk/JDKResponse.java +++ b/src/main/java/com/ning/http/client/providers/jdk/JDKResponse.java @@ -12,6 +12,8 @@ */ package com.ning.http.client.providers.jdk; +import static com.ning.http.util.MiscUtil.isNonEmpty; + import com.ning.http.client.Cookie; import com.ning.http.client.FluentCaseInsensitiveStringsMap; import com.ning.http.client.HttpResponseBodyPart; @@ -204,6 +206,6 @@ public boolean hasResponseHeaders() { */ /* @Override */ public boolean hasResponseBody() { - return bodyParts != null && !bodyParts.isEmpty(); + return isNonEmpty(bodyParts); } } diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java index 6c565b8f00..610b1b1617 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java @@ -15,6 +15,8 @@ */ package com.ning.http.client.providers.netty; +import static com.ning.http.util.MiscUtil.isNonEmpty; + import com.ning.http.client.AsyncHandler; import com.ning.http.client.AsyncHandler.STATE; import com.ning.http.client.AsyncHttpClientConfig; @@ -617,7 +619,6 @@ private static SpnegoEngine getSpnegoEngine() { return spnegoEngine; } - @SuppressWarnings("deprecation") private static HttpRequest construct(AsyncHttpClientConfig config, Request request, HttpMethod m, @@ -634,15 +635,13 @@ private static HttpRequest construct(AsyncHttpClientConfig config, if (m.equals(HttpMethod.CONNECT)) { nettyRequest = new DefaultHttpRequest(HttpVersion.HTTP_1_0, m, AsyncHttpProviderUtils.getAuthority(uri)); } else { - StringBuilder path = null; + String path = null; if (isProxyServer(config, request)) - path = new StringBuilder(uri.toString()); - else { - path = new StringBuilder(uri.getRawPath()); - if (uri.getQuery() != null) { - path.append("?").append(uri.getRawQuery()); - } - } + path = uri.toString(); + else if (uri.getRawQuery() != null) + path = uri.getRawPath() + "?" + uri.getRawQuery(); + else + path = uri.getRawPath(); nettyRequest = new DefaultHttpRequest(HttpVersion.HTTP_1_1, m, path.toString()); } boolean webSocket = isWebSocket(uri); @@ -708,7 +707,7 @@ private static HttpRequest construct(AsyncHttpClientConfig config, AuthenticatorUtils.computeBasicAuthentication(realm)); break; case DIGEST: - if (realm.getNonce() != null && !realm.getNonce().equals("")) { + if (isNonEmpty(realm.getNonce())) { try { nettyRequest.setHeader(HttpHeaders.Names.AUTHORIZATION, AuthenticatorUtils.computeDigestAuthentication(realm)); @@ -793,7 +792,7 @@ private static HttpRequest construct(AsyncHttpClientConfig config, } if (!m.equals(HttpMethod.CONNECT)) { - if (request.getCookies() != null && !request.getCookies().isEmpty()) { + if (isNonEmpty(request.getCookies())) { CookieEncoder httpCookieEncoder = new CookieEncoder(false); Iterator ic = request.getCookies().iterator(); Cookie c; @@ -830,7 +829,7 @@ private static HttpRequest construct(AsyncHttpClientConfig config, int length = lengthWrapper[0]; nettyRequest.setHeader(HttpHeaders.Names.CONTENT_LENGTH, String.valueOf(length)); nettyRequest.setContent(ChannelBuffers.wrappedBuffer(bytes, 0, length)); - } else if (request.getParams() != null && !request.getParams().isEmpty()) { + } else if (isNonEmpty(request.getParams())) { StringBuilder sb = new StringBuilder(); for (final Entry> paramEntry : request.getParams()) { final String key = paramEntry.getKey(); diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyResponse.java b/src/main/java/com/ning/http/client/providers/netty/NettyResponse.java index 2072a3708c..e83f838a2c 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyResponse.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyResponse.java @@ -15,6 +15,8 @@ */ package com.ning.http.client.providers.netty; +import static com.ning.http.util.MiscUtil.isNonEmpty; + import com.ning.http.client.Cookie; import com.ning.http.client.FluentCaseInsensitiveStringsMap; import com.ning.http.client.HttpResponseBodyPart; @@ -215,7 +217,7 @@ public boolean hasResponseHeaders() { */ /* @Override */ public boolean hasResponseBody() { - return bodyParts != null && !bodyParts.isEmpty(); + return isNonEmpty(bodyParts); } } diff --git a/src/main/java/com/ning/http/util/AuthenticatorUtils.java b/src/main/java/com/ning/http/util/AuthenticatorUtils.java index c1220f256e..96d17174f8 100644 --- a/src/main/java/com/ning/http/util/AuthenticatorUtils.java +++ b/src/main/java/com/ning/http/util/AuthenticatorUtils.java @@ -12,6 +12,8 @@ */ package com.ning.http.util; +import static com.ning.http.util.MiscUtil.isNonEmpty; + import com.ning.http.client.ProxyServer; import com.ning.http.client.Realm; @@ -40,7 +42,7 @@ public static String computeDigestAuthentication(Realm realm) throws NoSuchAlgor builder.append("algorithm").append('=').append(realm.getAlgorithm()).append(", "); construct(builder, "response", realm.getResponse()); - if (realm.getOpaque() != null && realm.getOpaque() != null && realm.getOpaque().equals("") == false) + if (isNonEmpty(realm.getOpaque())) construct(builder, "opaque", realm.getOpaque()); builder.append("qop").append('=').append(realm.getQop()).append(", "); builder.append("nc").append('=').append(realm.getNc()).append(", "); diff --git a/src/main/java/com/ning/http/util/MiscUtil.java b/src/main/java/com/ning/http/util/MiscUtil.java new file mode 100644 index 0000000000..dea244fd7b --- /dev/null +++ b/src/main/java/com/ning/http/util/MiscUtil.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2010-2012 Sonatype, Inc. All rights reserved. + * + * This program is licensed to you under the Apache License Version 2.0, + * and you may not use this file except in compliance with the Apache License Version 2.0. + * You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the Apache License Version 2.0 is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under. + */ +package com.ning.http.util; + +import java.util.Collection; +import java.util.Map; + +public class MiscUtil { + + private MiscUtil() { + } + + public static boolean isNonEmpty(String string) { + return string != null && string.length() != 0; + } + + public static boolean isNonEmpty(Collection collection) { + return collection != null && !collection.isEmpty(); + } + + public static boolean isNonEmpty(Map map) { + return map != null && !map.isEmpty(); + } +} diff --git a/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java b/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java index dbe19c1a78..2a27b409ba 100755 --- a/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java +++ b/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java @@ -15,6 +15,8 @@ */ package com.ning.http.client.async; +import static com.ning.http.util.MiscUtil.isNonEmpty; + import com.ning.http.client.AsyncCompletionHandler; import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClientConfig; @@ -61,7 +63,6 @@ import static org.testng.Assert.assertTrue; import static org.testng.Assert.fail; - public abstract class AsyncProvidersBasicTest extends AbstractBasicTest { private static final String UTF_8 = "text/html;charset=UTF-8"; @@ -1482,7 +1483,7 @@ public void optionsTest() throws Throwable { public void testAwsS3() throws Exception { final AsyncHttpClient c = getAsyncHttpClient(new Builder().build()); Response response = c.prepareGet("http://test.s3.amazonaws.com/").execute().get(); - if (response.getResponseBody() == null || response.getResponseBody().equals("")) { + if (!isNonEmpty(response.getResponseBody())) { fail("No response Body"); } else { assertEquals(response.getStatusCode(), 403); @@ -1495,7 +1496,7 @@ public void testAsyncHttpProviderConfig() throws Exception { final AsyncHttpClient c = getAsyncHttpClient(new Builder().setAsyncHttpClientProviderConfig(getProviderConfig()).build()); Response response = c.prepareGet("http://test.s3.amazonaws.com/").execute().get(); - if (response.getResponseBody() == null || response.getResponseBody().equals("")) { + if (!isNonEmpty(response.getResponseBody())) { fail("No response Body"); } else { assertEquals(response.getStatusCode(), 403); diff --git a/src/test/java/com/ning/http/client/async/AsyncStreamLifecycleTest.java b/src/test/java/com/ning/http/client/async/AsyncStreamLifecycleTest.java index faeaee7cc2..3208972a28 100644 --- a/src/test/java/com/ning/http/client/async/AsyncStreamLifecycleTest.java +++ b/src/test/java/com/ning/http/client/async/AsyncStreamLifecycleTest.java @@ -119,7 +119,7 @@ public void onThrowable(Throwable t) { public STATE onBodyPartReceived(HttpResponseBodyPart e) throws Exception { String s = new String(e.getBodyPartBytes()); log.info("got part: {}", s); - if (s.equals("")) { + if (s.isEmpty()) { //noinspection ThrowableInstanceNeverThrown log.warn("Sampling stacktrace.", new Throwable("trace that, we should not get called for empty body.")); diff --git a/src/test/java/com/ning/http/client/async/EmptyBodyTest.java b/src/test/java/com/ning/http/client/async/EmptyBodyTest.java index 873e1bba88..d687a6cb26 100644 --- a/src/test/java/com/ning/http/client/async/EmptyBodyTest.java +++ b/src/test/java/com/ning/http/client/async/EmptyBodyTest.java @@ -88,7 +88,7 @@ public void onThrowable(Throwable t) { public STATE onBodyPartReceived(HttpResponseBodyPart e) throws Exception { String s = new String(e.getBodyPartBytes()); log.info("got part: {}", s); - if (s.equals("")) { + if (s.isEmpty()) { //noinspection ThrowableInstanceNeverThrown log.warn("Sampling stacktrace.", new Throwable("trace that, we should not get called for empty body.")); diff --git a/src/test/java/com/ning/http/client/async/ParamEncodingTest.java b/src/test/java/com/ning/http/client/async/ParamEncodingTest.java index 02af3160ee..eb742de2d1 100644 --- a/src/test/java/com/ning/http/client/async/ParamEncodingTest.java +++ b/src/test/java/com/ning/http/client/async/ParamEncodingTest.java @@ -15,6 +15,8 @@ */ package com.ning.http.client.async; +import static com.ning.http.util.MiscUtil.isNonEmpty; + import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.Response; import org.eclipse.jetty.server.Request; @@ -42,7 +44,7 @@ public void handle(String s, HttpServletResponse response) throws IOException, ServletException { if ("POST".equalsIgnoreCase(request.getMethod())) { String p = request.getParameter("test"); - if (p != null && !p.equals("")) { + if (isNonEmpty(p)) { response.setStatus(HttpServletResponse.SC_OK); response.addHeader("X-Param", p); } else { diff --git a/src/test/java/com/ning/http/client/async/PostWithQSTest.java b/src/test/java/com/ning/http/client/async/PostWithQSTest.java index 6f59c9d93f..dc214579cf 100644 --- a/src/test/java/com/ning/http/client/async/PostWithQSTest.java +++ b/src/test/java/com/ning/http/client/async/PostWithQSTest.java @@ -15,6 +15,8 @@ */ package com.ning.http.client.async; +import static com.ning.http.util.MiscUtil.isNonEmpty; + import com.ning.http.client.AsyncCompletionHandlerBase; import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.HttpResponseStatus; @@ -54,7 +56,7 @@ public void handle(String s, HttpServletResponse response) throws IOException, ServletException { if ("POST".equalsIgnoreCase(request.getMethod())) { String qs = request.getQueryString(); - if (qs != null && !qs.equals("") && request.getContentLength() == 3) { + if (isNonEmpty(qs) && request.getContentLength() == 3) { ServletInputStream is = request.getInputStream(); response.setStatus(HttpServletResponse.SC_OK); byte buf[] = new byte[is.available()]; diff --git a/src/test/java/com/ning/http/client/async/QueryParametersTest.java b/src/test/java/com/ning/http/client/async/QueryParametersTest.java index 028a9543d4..da715345dd 100644 --- a/src/test/java/com/ning/http/client/async/QueryParametersTest.java +++ b/src/test/java/com/ning/http/client/async/QueryParametersTest.java @@ -15,6 +15,8 @@ */ package com.ning.http.client.async; +import static com.ning.http.util.MiscUtil.isNonEmpty; + import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.Response; import org.eclipse.jetty.server.Request; @@ -49,7 +51,7 @@ public void handle(String s, HttpServletResponse response) throws IOException, ServletException { if ("GET".equalsIgnoreCase(request.getMethod())) { String qs = request.getQueryString(); - if (qs != null && !qs.equals("")) { + if (isNonEmpty(qs)) { for (String qnv : qs.split("&")) { String nv[] = qnv.split("="); response.addHeader(nv[0], nv[1]); diff --git a/src/test/java/com/ning/http/client/async/RC10KTest.java b/src/test/java/com/ning/http/client/async/RC10KTest.java index 51a1e09602..d37c9d2c68 100644 --- a/src/test/java/com/ning/http/client/async/RC10KTest.java +++ b/src/test/java/com/ning/http/client/async/RC10KTest.java @@ -132,7 +132,7 @@ public void onThrowable(Throwable t) { public STATE onBodyPartReceived(HttpResponseBodyPart event) throws Exception { String s = new String(event.getBodyPartBytes()); - result.compareAndSet(-1, new Integer(s.trim().equals("") ? "-1" : s)); + result.compareAndSet(-1, new Integer(s.trim().isEmpty() ? "-1" : s)); return STATE.CONTINUE; } From 9f59ac6ea43f82f78b4d8df9dad6b27934b17037 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 8 Mar 2013 22:20:14 +0100 Subject: [PATCH 066/264] Optimize URI.create/String round trips, fix proposal for #139 --- .../java/com/ning/http/client/Request.java | 5 + .../ning/http/client/RequestBuilderBase.java | 121 ++++++++++-------- .../grizzly/GrizzlyAsyncHttpProvider.java | 36 ++---- .../netty/NettyAsyncHttpProvider.java | 24 ++-- .../client/providers/netty/NettyResponse.java | 4 +- .../http/util/AsyncHttpProviderUtils.java | 12 +- .../java/com/ning/http/util/ProxyUtils.java | 3 +- 7 files changed, 108 insertions(+), 97 deletions(-) diff --git a/src/main/java/com/ning/http/client/Request.java b/src/main/java/com/ning/http/client/Request.java index eb31a23fba..8871dd6cc8 100644 --- a/src/main/java/com/ning/http/client/Request.java +++ b/src/main/java/com/ning/http/client/Request.java @@ -21,6 +21,7 @@ import java.io.InputStream; import java.io.OutputStream; import java.net.InetAddress; +import java.net.URI; import java.util.Collection; import java.util.List; @@ -66,6 +67,10 @@ public static interface EntityWriter { */ public String getUrl(); + public URI getOriginalURI(); + public URI getURI(); + public URI getRawURI(); + /** * Return the InetAddress to override * diff --git a/src/main/java/com/ning/http/client/RequestBuilderBase.java b/src/main/java/com/ning/http/client/RequestBuilderBase.java index b860cc580e..d9cb4965c4 100644 --- a/src/main/java/com/ning/http/client/RequestBuilderBase.java +++ b/src/main/java/com/ning/http/client/RequestBuilderBase.java @@ -18,6 +18,7 @@ import static com.ning.http.util.MiscUtil.isNonEmpty; import com.ning.http.client.Request.EntityWriter; +import com.ning.http.util.AsyncHttpProviderUtils; import com.ning.http.util.UTF8UrlEncoder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -38,15 +39,19 @@ /** * Builder for {@link Request} - * + * * @param */ public abstract class RequestBuilderBase> { private final static Logger logger = LoggerFactory.getLogger(RequestBuilderBase.class); + private static final URI DEFAULT_REQUEST_URL = URI.create("http://localhost/"); + private static final class RequestImpl implements Request { private String method; - private String url = null; + private URI originalUri = null; + private URI uri = null; + private URI rawUri = null; private InetAddress address = null; private InetAddress localAddress = null; private FluentCaseInsensitiveStringsMap headers = new FluentCaseInsensitiveStringsMap(); @@ -78,9 +83,7 @@ public RequestImpl(boolean useRawUrl) { public RequestImpl(Request prototype) { if (prototype != null) { this.method = prototype.getMethod(); - String prototypeUrl = prototype.getUrl(); - int pos = prototypeUrl.indexOf("?"); - this.url = pos > 0 ? prototypeUrl.substring(0, pos) : prototypeUrl; + this.originalUri = prototype.getOriginalURI(); this.address = prototype.getInetAddress(); this.localAddress = prototype.getLocalAddress(); this.headers = new FluentCaseInsensitiveStringsMap(prototype.getHeaders()); @@ -117,12 +120,6 @@ public String getMethod() { return method; } - /* @Override */ - - public String getUrl() { - return toUrl(true); - } - public InetAddress getInetAddress() { return address; } @@ -131,34 +128,66 @@ public InetAddress getLocalAddress() { return localAddress; } - private String toUrl(boolean encode) { + private String removeTrailingSlash(URI uri) { + String uriString = uri.toString(); + if (uriString.endsWith("/")) { + return uriString.substring(0, uriString.length() - 1); + } else { + return uriString; + } + } - if (url == null) { + /* @Override */ + public String getUrl() { + return removeTrailingSlash(getURI()); + } + + /* @Override */ + public String getRawUrl() { + return removeTrailingSlash(getRawURI()); + } + + public URI getOriginalURI() { + return originalUri; + } + + public URI getURI() { + if (uri == null) + uri = toURI(true); + return uri; + } + + public URI getRawURI() { + if (rawUri == null) + rawUri = toURI(false); + return rawUri; + } + + private URI toURI(boolean encode) { + + if (originalUri == null) { logger.debug("setUrl hasn't been invoked. Using http://localhost"); - url = "http://localhost/"; + originalUri = DEFAULT_REQUEST_URL; } - String uri = url; - if (!uri.startsWith("ws")) { - try { - uri = URI.create(url).toURL().toString(); - } catch (Throwable e) { - throw new IllegalArgumentException("Illegal URL: " + url, e); - } + AsyncHttpProviderUtils.validateSupportedScheme(originalUri); + + StringBuilder builder = new StringBuilder(); + builder.append(originalUri.getScheme()).append("://").append(originalUri.getAuthority()); + if (isNonEmpty(originalUri.getRawPath())) { + builder.append(originalUri.getRawPath()); + } else { + builder.append("/"); } if (isNonEmpty(queryParams)) { - StringBuilder builder = new StringBuilder(); - if (!url.substring(8).contains("/")) { // no other "/" than http[s]:// -> http://localhost:1234 - builder.append("/"); - } builder.append("?"); - for (Iterator>> i = queryParams.iterator(); i.hasNext(); ) { + for (Iterator>> i = queryParams.iterator(); i.hasNext();) { Map.Entry> param = i.next(); String name = param.getKey(); - for (Iterator j = param.getValue().iterator(); j.hasNext(); ) { + for (Iterator j = param.getValue().iterator(); j.hasNext();) { String value = j.next(); if (encode) { UTF8UrlEncoder.appendEncoded(builder, name); @@ -181,14 +210,9 @@ private String toUrl(boolean encode) { builder.append('&'); } } - uri += builder.toString(); } - return uri; - } - /* @Override */ - public String getRawUrl() { - return toUrl(false); + return URI.create(builder.toString()); } /* @Override */ @@ -292,12 +316,12 @@ public String getBodyEncoding() { } public ConnectionPoolKeyStrategy getConnectionPoolKeyStrategy() { - return connectionPoolKeyStrategy; - } - + return connectionPoolKeyStrategy; + } + @Override public String toString() { - StringBuilder sb = new StringBuilder(url); + StringBuilder sb = new StringBuilder(getURI().toString()); sb.append("\t"); sb.append(method); @@ -346,7 +370,7 @@ protected RequestBuilderBase(Class derived, Request prototype) { } public T setUrl(String url) { - request.url = buildUrl(url); + request.originalUri = buildURI(url); return derived.cast(this); } @@ -360,7 +384,7 @@ public T setLocalInetAddress(InetAddress address) { return derived.cast(this); } - private String buildUrl(String url) { + private URI buildURI(String url) { URI uri = URI.create(url); StringBuilder buildedUrl = new StringBuilder(); @@ -380,7 +404,7 @@ private String buildUrl(String url) { if (url.indexOf("://") == -1) { String s = buildedUrl.toString(); url = s + url.substring(uri.getScheme().length() + 1); - return buildUrl(url); + return buildURI(url); } else { throw new IllegalArgumentException("Invalid url " + uri.toString()); } @@ -395,7 +419,7 @@ private String buildUrl(String url) { addQueryParameter(query, null); } else { try { - if (this.useRawUrl) { + if (useRawUrl) { addQueryParameter(query.substring(0, pos), query.substring(pos + 1)); } else { addQueryParameter(URLDecoder.decode(query.substring(0, pos), "UTF-8"), URLDecoder.decode(query.substring(pos + 1), "UTF-8")); @@ -406,10 +430,9 @@ private String buildUrl(String url) { } } } - return buildedUrl.toString(); + return uri; } - public T setVirtualHost(String virtualHost) { request.virtualHost = virtualHost; return derived.cast(this); @@ -612,8 +635,8 @@ public T setBodyEncoding(String charset) { } public T setConnectionPoolKeyStrategy(ConnectionPoolKeyStrategy connectionPoolKeyStrategy) { - request.connectionPoolKeyStrategy = connectionPoolKeyStrategy; - return derived.cast(this); + request.connectionPoolKeyStrategy = connectionPoolKeyStrategy; + return derived.cast(this); } public Request build() { @@ -633,13 +656,7 @@ public Request build() { } private boolean allowBody(String method) { - if (method.equalsIgnoreCase("GET") || method.equalsIgnoreCase("OPTIONS") - && method.equalsIgnoreCase("TRACE") - && method.equalsIgnoreCase("HEAD")) { - return false; - } else { - return true; - } + return !(method.equalsIgnoreCase("GET") || method.equalsIgnoreCase("OPTIONS") || method.equalsIgnoreCase("TRACE") || method.equalsIgnoreCase("HEAD")); } public T addOrReplaceCookie(Cookie cookie) { diff --git a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java index a3cb4613b0..1f5ce1b993 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java @@ -846,7 +846,7 @@ private boolean sendAsGrizzlyRequest(final Request request, httpCtx.isWSRequest = true; convertToUpgradeRequest(httpCtx); } - final URI uri = AsyncHttpProviderUtils.createUri(httpCtx.requestUrl); + final URI uri = httpCtx.request.getURI(); final HttpRequestPacket.Builder builder = HttpRequestPacket.builder(); boolean secure = "https".equals(uri.getScheme()); builder.method(request.getMethod()); @@ -1209,7 +1209,7 @@ protected void onInitialLineParsed(HttpHeader httpHeader, } final GrizzlyResponseStatus responseStatus = new GrizzlyResponseStatus((HttpResponsePacket) httpHeader, - getURI(context.requestUrl), + context.request.getURI(), provider); context.responseStatus = responseStatus; if (context.statusHandler != null) { @@ -1457,14 +1457,6 @@ private static HttpTransactionContext cleanup(final FilterChainContext ctx, } - - private static URI getURI(String url) { - - return AsyncHttpProviderUtils.createUri(url); - - } - - private static boolean redirectCountExceeded(final HttpTransactionContext context) { return (context.redirectCount.get() > context.maxRedirectCount); @@ -1521,7 +1513,7 @@ public boolean handleStatus(final HttpResponsePacket responsePacket, final Request req = httpTransactionContext.request; realm = new Realm.RealmBuilder().clone(realm) .setScheme(realm.getAuthScheme()) - .setUri(URI.create(httpTransactionContext.requestUrl).getPath()) + .setUri(httpTransactionContext.request.getURI().getPath()) .setMethodName(req.getMethod()) .setUsePreemptiveAuth(true) .parseWWWAuthenticateHeader(auth) @@ -1600,9 +1592,9 @@ public boolean handleStatus(final HttpResponsePacket responsePacket, URI orig; if (httpTransactionContext.lastRedirectURI == null) { - orig = AsyncHttpProviderUtils.createUri(httpTransactionContext.requestUrl); + orig = httpTransactionContext.request.getURI(); } else { - orig = AsyncHttpProviderUtils.getRedirectUri(AsyncHttpProviderUtils.createUri(httpTransactionContext.requestUrl), + orig = AsyncHttpProviderUtils.getRedirectUri(httpTransactionContext.request.getURI(), httpTransactionContext.lastRedirectURI); } httpTransactionContext.lastRedirectURI = redirectURL; @@ -2320,13 +2312,12 @@ void doAsyncTrackedConnection(final Request request, final GrizzlyResponseFuture requestFuture, final CompletionHandler connectHandler) throws IOException, ExecutionException, InterruptedException { - final String url = request.getUrl(); Connection c = pool.poll(getPoolKey(request)); if (c == null) { if (!connectionMonitor.acquire()) { throw new IOException("Max connections exceeded"); } - doAsyncConnect(url, request, requestFuture, connectHandler); + doAsyncConnect(request, requestFuture, connectHandler); } else { provider.touchConnection(c, request); connectHandler.completed(c); @@ -2338,25 +2329,23 @@ Connection obtainConnection(final Request request, final GrizzlyResponseFuture requestFuture) throws IOException, ExecutionException, InterruptedException, TimeoutException { - final Connection c = (obtainConnection0(request.getUrl(), - request, + final Connection c = (obtainConnection0(request, requestFuture)); DO_NOT_CACHE.set(c, Boolean.TRUE); return c; } - void doAsyncConnect(final String url, - final Request request, + void doAsyncConnect(final Request request, final GrizzlyResponseFuture requestFuture, final CompletionHandler connectHandler) throws IOException, ExecutionException, InterruptedException { - final URI uri = AsyncHttpProviderUtils.createUri(url); ProxyServer proxy = getProxyServer(request); if (ProxyUtils.avoidProxy(proxy, request)) { proxy = null; } + final URI uri = request.getURI(); String host = ((proxy != null) ? proxy.getHost() : uri.getHost()); int port = ((proxy != null) ? proxy.getPort() : uri.getPort()); if(request.getLocalAddress()!=null) { @@ -2369,12 +2358,11 @@ void doAsyncConnect(final String url, } - private Connection obtainConnection0(final String url, - final Request request, + private Connection obtainConnection0(final Request request, final GrizzlyResponseFuture requestFuture) throws IOException, ExecutionException, InterruptedException, TimeoutException { - final URI uri = AsyncHttpProviderUtils.createUri(url); + final URI uri = request.getURI(); ProxyServer proxy = getProxyServer(request); if (ProxyUtils.avoidProxy(proxy, request)) { proxy = null; @@ -2471,7 +2459,7 @@ public void updated(Connection result) { private static String getPoolKey(final Request request) { final ConnectionPoolKeyStrategy keyStrategy = request.getConnectionPoolKeyStrategy(); - return keyStrategy.getKey(AsyncHttpProviderUtils.createUri(AsyncHttpProviderUtils.getBaseUrl(request.getUrl()))); + return keyStrategy.getKey(request.getURI()); } // ------------------------------------------------------ Nested Classes diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java index 610b1b1617..f1f101552c 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java @@ -642,7 +642,7 @@ else if (uri.getRawQuery() != null) path = uri.getRawPath() + "?" + uri.getRawQuery(); else path = uri.getRawPath(); - nettyRequest = new DefaultHttpRequest(HttpVersion.HTTP_1_1, m, path.toString()); + nettyRequest = new DefaultHttpRequest(HttpVersion.HTTP_1_1, m, path); } boolean webSocket = isWebSocket(uri); if (webSocket) { @@ -955,13 +955,12 @@ private ListenableFuture doConnect(final Request request, final AsyncHand } ProxyServer proxyServer = request.getProxyServer() != null ? request.getProxyServer() : config.getProxyServer(); - String requestUrl; + URI uri; if (useRawUrl) { - requestUrl = request.getRawUrl(); + uri = request.getRawURI(); } else { - requestUrl = request.getUrl(); + uri = request.getURI(); } - URI uri = AsyncHttpProviderUtils.createUri(requestUrl); Channel channel = null; if (useCache) { @@ -1214,7 +1213,7 @@ private Realm kerberosChallenge(List proxyAuth, Realm realm, NettyResponseFuture future) throws NTLMEngineException { - URI uri = URI.create(request.getUrl()); + URI uri = request.getURI(); String host = request.getVirtualHost() == null ? AsyncHttpProviderUtils.getHost(uri) : request.getVirtualHost(); String server = proxyServer == null ? host : proxyServer.getHost(); try { @@ -1228,7 +1227,7 @@ private Realm kerberosChallenge(List proxyAuth, } else { realmBuilder = new Realm.RealmBuilder(); } - return realmBuilder.setUri(uri.getPath()) + return realmBuilder.setUri(uri.getRawPath()) .setMethodName(request.getMethod()) .setScheme(Realm.AuthScheme.KERBEROS) .build(); @@ -1259,9 +1258,10 @@ private Realm ntlmChallenge(List wwwAuth, if (realm != null && !realm.isNtlmMessageType2Received()) { String challengeHeader = ntlmEngine.generateType1Msg(ntlmDomain, ntlmHost); + URI uri = request.getURI(); headers.add(HttpHeaders.Names.AUTHORIZATION, "NTLM " + challengeHeader); newRealm = new Realm.RealmBuilder().clone(realm).setScheme(realm.getAuthScheme()) - .setUri(URI.create(request.getUrl()).getPath()) + .setUri(uri.getRawPath()) .setMethodName(request.getMethod()) .setNtlmMessageType2Received(true) .build(); @@ -1287,7 +1287,7 @@ private Realm ntlmChallenge(List wwwAuth, authScheme = Realm.AuthScheme.NTLM; } newRealm = realmBuilder.setScheme(authScheme) - .setUri(URI.create(request.getUrl()).getPath()) + .setUri(request.getURI().getPath()) .setMethodName(request.getMethod()) .build(); } @@ -1321,7 +1321,7 @@ private Realm ntlmProxyChallenge(List wwwAuth, realmBuilder = new Realm.RealmBuilder(); } newRealm = realmBuilder//.setScheme(realm.getAuthScheme()) - .setUri(URI.create(request.getUrl()).getPath()) + .setUri(request.getURI().getPath()) .setMethodName(request.getMethod()) .build(); @@ -2220,7 +2220,7 @@ public void handle(final ChannelHandlerContext ctx, final MessageEvent e) throws realmBuilder = new Realm.RealmBuilder(); } newRealm = realmBuilder - .setUri(URI.create(request.getUrl()).getPath()) + .setUri(request.getURI().getPath()) .setMethodName(request.getMethod()) .setUsePreemptiveAuth(true) .parseWWWAuthenticateHeader(wwwAuth.get(0)) @@ -2293,7 +2293,7 @@ public Object call() throws Exception { try { log.debug("Connecting to proxy {} for scheme {}", proxyServer, request.getUrl()); - upgradeProtocol(ctx.getChannel().getPipeline(), URI.create(request.getUrl()).getScheme()); + upgradeProtocol(ctx.getChannel().getPipeline(), request.getURI().getScheme()); } catch (Throwable ex) { abort(future, ex); } diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyResponse.java b/src/main/java/com/ning/http/client/providers/netty/NettyResponse.java index e83f838a2c..65870b0ca0 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyResponse.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyResponse.java @@ -46,7 +46,6 @@ public class NettyResponse implements Response { private final static Charset DEFAULT_CHARSET = Charset.forName("ISO-8859-1"); - private final URI uri; private final List bodyParts; private final HttpResponseHeaders headers; private final HttpResponseStatus status; @@ -59,7 +58,6 @@ public NettyResponse(HttpResponseStatus status, this.status = status; this.headers = headers; this.bodyParts = bodyParts; - uri = status.getUrl(); } /* @Override */ @@ -140,7 +138,7 @@ private Charset computeCharset(String charset) { /* @Override */ public URI getUri() throws MalformedURLException { - return uri; + return status.getUrl(); } /* @Override */ diff --git a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java index f10ef5dff0..c880592cc3 100644 --- a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java +++ b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java @@ -137,15 +137,19 @@ public final static SimpleDateFormat[] get() { static final String VERSION = "Version"; static final byte[] EMPTY_BYTE_ARRAY = "".getBytes(); - - public final static URI createUri(String u) { - URI uri = URI.create(u); + + public static final void validateSupportedScheme(URI uri) { final String scheme = uri.getScheme(); if (scheme == null || !scheme.equalsIgnoreCase("http") && !scheme.equalsIgnoreCase("https") && !scheme.equalsIgnoreCase("ws") && !scheme.equalsIgnoreCase("wss")) { - throw new IllegalArgumentException("The URI scheme, of the URI " + u + throw new IllegalArgumentException("The URI scheme, of the URI " + uri + ", must be equal (ignoring case) to 'http', 'https', 'ws', or 'wss'"); } + } + + public final static URI createUri(String u) { + URI uri = URI.create(u); + validateSupportedScheme(uri); String path = uri.getPath(); if (path == null) { diff --git a/src/main/java/com/ning/http/util/ProxyUtils.java b/src/main/java/com/ning/http/util/ProxyUtils.java index a3bd9f58e4..ea448b6272 100644 --- a/src/main/java/com/ning/http/util/ProxyUtils.java +++ b/src/main/java/com/ning/http/util/ProxyUtils.java @@ -16,7 +16,6 @@ import com.ning.http.client.ProxyServer.Protocol; import com.ning.http.client.Request; -import java.net.URI; import java.util.List; import java.util.Properties; @@ -70,7 +69,7 @@ public class ProxyUtils { * @return true if we have to avoid proxy use (obeying non-proxy hosts settings), false otherwise. */ public static boolean avoidProxy(final ProxyServer proxyServer, final Request request) { - return avoidProxy(proxyServer, AsyncHttpProviderUtils.getHost(URI.create(request.getUrl()))); + return avoidProxy(proxyServer, AsyncHttpProviderUtils.getHost(request.getOriginalURI())); } /** From b4eb9d57fe5c22851fb21d6da94c599748267149 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 8 Mar 2013 23:21:58 +0100 Subject: [PATCH 067/264] Ensure clients are finally closed, fix #239 --- .../client/async/AsyncProvidersBasicTest.java | 2413 +++++++++-------- .../client/async/AsyncStreamHandlerTest.java | 835 +++--- .../async/AsyncStreamLifecycleTest.java | 101 +- .../http/client/async/AuthTimeoutTest.java | 168 +- .../ning/http/client/async/BasicAuthTest.java | 349 ++- .../http/client/async/BasicHttpsTest.java | 160 +- .../ning/http/client/async/BodyChunkTest.java | 29 +- .../async/BodyDeferringAsyncHandlerTest.java | 259 +- .../client/async/ByteBufferCapacityTest.java | 92 +- .../ning/http/client/async/ChunkingTest.java | 28 +- .../http/client/async/ComplexClientTest.java | 48 +- .../http/client/async/ConnectionPoolTest.java | 392 ++- .../http/client/async/DigestAuthTest.java | 80 +- .../ning/http/client/async/EmptyBodyTest.java | 153 +- .../http/client/async/ErrorResponseTest.java | 49 +- .../client/async/Expect100ContinueTest.java | 53 +- .../client/async/FilePartLargeFileTest.java | 90 +- .../ning/http/client/async/FilterTest.java | 95 +- .../client/async/FollowingThreadTest.java | 98 +- .../ning/http/client/async/Head302Test.java | 63 +- .../client/async/HostnameVerifierTest.java | 114 +- .../client/async/HttpToHttpsRedirectTest.java | 79 +- .../http/client/async/InputStreamTest.java | 64 +- .../client/async/ListenableFutureTest.java | 37 +- .../client/async/MaxConnectionsInThreads.java | 156 +- .../client/async/MaxTotalConnectionTest.java | 170 +- .../client/async/MultipartUploadTest.java | 46 +- .../http/client/async/MultipleHeaderTest.java | 187 +- .../http/client/async/NoNullResponseTest.java | 41 +- .../async/NonAsciiContentLengthTest.java | 105 +- .../http/client/async/ParamEncodingTest.java | 25 +- .../async/PerRequestRelative302Test.java | 87 +- .../client/async/PerRequestTimeoutTest.java | 97 +- .../client/async/PostRedirectGetTest.java | 139 +- .../http/client/async/PostWithQSTest.java | 80 +- .../ning/http/client/async/ProviderUtil.java | 37 +- .../com/ning/http/client/async/ProxyTest.java | 187 +- .../client/async/ProxyyTunnellingTest.java | 127 +- .../http/client/async/PutLargeFileTest.java | 59 +- .../client/async/QueryParametersTest.java | 79 +- .../com/ning/http/client/async/RC10KTest.java | 30 +- .../async/RedirectConnectionUsageTest.java | 5 - .../http/client/async/Relative302Test.java | 94 +- .../http/client/async/RemoteSiteTest.java | 320 +-- .../client/async/RetryNonBlockingIssue.java | 2 +- .../http/client/async/RetryRequestTest.java | 13 +- .../SimpleAsyncClientErrorBehaviourTest.java | 73 +- .../async/SimpleAsyncHttpClientTest.java | 265 +- .../client/async/TransferListenerTest.java | 48 +- .../http/client/async/WebDavBasicTest.java | 136 +- .../http/client/async/ZeroCopyFileTest.java | 238 +- .../GrizzlyAsyncProviderBasicTest.java | 34 +- .../GrizzlyAsyncStreamHandlerTest.java | 7 +- .../GrizzlyAsyncStreamLifecycleTest.java | 7 +- .../async/grizzly/GrizzlyAuthTimeoutTest.java | 9 +- .../async/grizzly/GrizzlyBasicAuthTest.java | 8 +- .../async/grizzly/GrizzlyBasicHttpsTest.java | 9 +- .../async/grizzly/GrizzlyBodyChunkTest.java | 7 +- .../GrizzlyBodyDeferringAsyncHandlerTest.java | 7 +- .../GrizzlyByteBufferCapacityTest.java | 12 +- .../async/grizzly/GrizzlyChunkingTest.java | 7 +- .../grizzly/GrizzlyComplexClientTest.java | 7 +- .../grizzly/GrizzlyConnectionPoolTest.java | 194 +- .../async/grizzly/GrizzlyDigestAuthTest.java | 7 +- .../async/grizzly/GrizzlyEmptyBodyTest.java | 7 +- .../grizzly/GrizzlyErrorResponseTest.java | 8 +- .../grizzly/GrizzlyExpectContinue100Test.java | 10 +- .../async/grizzly/GrizzlyFilterTest.java | 8 +- .../grizzly/GrizzlyFollowingThreadTest.java | 7 +- .../async/grizzly/GrizzlyHead302Test.java | 7 +- .../GrizzlyHttpToHttpsRedirectTest.java | 7 +- .../grizzly/GrizzlyIdleStateHandlerTest.java | 7 +- .../async/grizzly/GrizzlyInputStreamTest.java | 7 +- .../grizzly/GrizzlyListenableFutureTest.java | 7 +- .../GrizzlyMaxConnectionsInThreadsTest.java | 7 +- .../GrizzlyMaxTotalConnectionTest.java | 7 +- .../grizzly/GrizzlyMultipleHeaderTest.java | 7 +- .../grizzly/GrizzlyNoNullResponseTest.java | 7 +- .../GrizzlyNonAsciiContentLengthTest.java | 7 +- .../grizzly/GrizzlyParamEncodingTest.java | 7 +- .../GrizzlyPerRequestRelative302Test.java | 7 +- .../grizzly/GrizzlyPerRequestTimeoutTest.java | 7 +- .../grizzly/GrizzlyPostRedirectGetTest.java | 7 +- .../async/grizzly/GrizzlyPostWithQSTest.java | 7 +- .../async/grizzly/GrizzlyProxyTest.java | 7 +- .../grizzly/GrizzlyProxyTunnelingTest.java | 7 +- .../grizzly/GrizzlyPutLargeFileTest.java | 7 +- .../grizzly/GrizzlyQueryParametersTest.java | 7 +- .../async/grizzly/GrizzlyRC10KTest.java | 7 +- .../GrizzlyRedirectConnectionUsageTest.java | 18 +- .../async/grizzly/GrizzlyRelative302Test.java | 7 +- .../async/grizzly/GrizzlyRemoteSiteTest.java | 7 +- .../grizzly/GrizzlyRetryRequestTest.java | 7 +- .../GrizzlySimpleAsyncHttpClientTest.java | 7 +- .../grizzly/GrizzlyTransferListenerTest.java | 7 +- .../netty/NettyAsyncProviderBasicTest.java | 2 +- .../NettyBodyDeferringAsyncHandlerTest.java | 3 +- .../netty/NettyByteBufferCapacityTest.java | 1 - .../client/async/netty/NettyProxyTest.java | 1 - .../NettyRedirectConnectionUsageTest.java | 2 +- .../async/netty/NettyZeroCopyFileTest.java | 1 - .../ByteArrayBodyGeneratorTest.java | 9 +- .../client/websocket/ByteMessageTest.java | 295 +- .../websocket/CloseCodeReasonMessageTest.java | 54 +- .../http/client/websocket/RedirectTest.java | 98 +- .../client/websocket/TextMessageTest.java | 536 ++-- .../grizzly/GrizzlyByteMessageTest.java | 9 +- .../GrizzlyCloseCodeReasonMsgTest.java | 12 +- .../grizzly/GrizzlyRedirectTest.java | 7 +- .../grizzly/GrizzlyTextMessageTest.java | 11 +- 110 files changed, 5016 insertions(+), 5268 deletions(-) diff --git a/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java b/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java index 2a27b409ba..8cff37fa41 100755 --- a/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java +++ b/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java @@ -16,25 +16,10 @@ package com.ning.http.client.async; import static com.ning.http.util.MiscUtil.isNonEmpty; - -import com.ning.http.client.AsyncCompletionHandler; -import com.ning.http.client.AsyncHttpClient; -import com.ning.http.client.AsyncHttpClientConfig; -import com.ning.http.client.AsyncHttpClientConfig.Builder; -import com.ning.http.client.AsyncHttpClientConfigBean; -import com.ning.http.client.AsyncHttpProviderConfig; -import com.ning.http.client.Cookie; -import com.ning.http.client.FluentCaseInsensitiveStringsMap; -import com.ning.http.client.MaxRedirectException; -import com.ning.http.client.Part; -import com.ning.http.client.ProxyServer; -import com.ning.http.client.Request; -import com.ning.http.client.RequestBuilder; -import com.ning.http.client.Response; -import com.ning.http.client.StringPart; -import com.ning.http.client.providers.netty.NettyAsyncHttpProviderConfig; -import org.testng.Assert; -import org.testng.annotations.Test; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNull; +import static org.testng.Assert.assertTrue; +import static org.testng.Assert.fail; import java.io.ByteArrayInputStream; import java.io.IOException; @@ -58,1535 +43,1633 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertNull; -import static org.testng.Assert.assertTrue; -import static org.testng.Assert.fail; +import org.testng.Assert; +import org.testng.annotations.Test; + +import com.ning.http.client.AsyncCompletionHandler; +import com.ning.http.client.AsyncHttpClient; +import com.ning.http.client.AsyncHttpClientConfig; +import com.ning.http.client.AsyncHttpClientConfig.Builder; +import com.ning.http.client.AsyncHttpClientConfigBean; +import com.ning.http.client.AsyncHttpProviderConfig; +import com.ning.http.client.Cookie; +import com.ning.http.client.FluentCaseInsensitiveStringsMap; +import com.ning.http.client.MaxRedirectException; +import com.ning.http.client.Part; +import com.ning.http.client.ProxyServer; +import com.ning.http.client.Request; +import com.ning.http.client.RequestBuilder; +import com.ning.http.client.Response; +import com.ning.http.client.StringPart; public abstract class AsyncProvidersBasicTest extends AbstractBasicTest { private static final String UTF_8 = "text/html;charset=UTF-8"; - @Test(groups = {"standalone", "default_provider", "async"}) + @Test(groups = { "standalone", "default_provider", "async" }) public void asyncProviderEncodingTest() throws Throwable { - AsyncHttpClient p = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().build()); - Request request = new RequestBuilder("GET").setUrl("http://foo.com/foo.html?q=+%20x").build(); - String requestUrl = request.getUrl(); - Assert.assertEquals(requestUrl, "http://foo.com/foo.html?q=%20%20x"); - Future responseFuture = p.executeRequest(request, new AsyncCompletionHandler() { - @Override - public String onCompleted(Response response) throws Exception { - return response.getUri().toString(); - } + AsyncHttpClient client = getAsyncHttpClient(null); + try { + Request request = new RequestBuilder("GET").setUrl("http://foo.com/foo.html?q=+%20x").build(); + String requestUrl = request.getUrl(); + Assert.assertEquals(requestUrl, "http://foo.com/foo.html?q=%20%20x"); + Future responseFuture = client.executeRequest(request, new AsyncCompletionHandler() { + @Override + public String onCompleted(Response response) throws Exception { + return response.getUri().toString(); + } - /* @Override */ - public void onThrowable(Throwable t) { - t.printStackTrace(); - Assert.fail("Unexpected exception: " + t.getMessage(), t); - } + /* @Override */ + public void onThrowable(Throwable t) { + t.printStackTrace(); + Assert.fail("Unexpected exception: " + t.getMessage(), t); + } - }); - String url = responseFuture.get(); - Assert.assertEquals(url, "http://foo.com/foo.html?q=%20%20x"); - p.close(); + }); + String url = responseFuture.get(); + Assert.assertEquals(url, "http://foo.com/foo.html?q=%20%20x"); + } finally { + client.close(); + } } - @Test(groups = {"standalone", "default_provider", "async"}) + @Test(groups = { "standalone", "default_provider", "async" }) public void asyncProviderEncodingTest2() throws Throwable { - AsyncHttpClient p = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().build()); - Request request = new RequestBuilder("GET").setUrl("http://foo.com/foo.html") - .addQueryParameter("q", "a b") - .build(); - - Future responseFuture = p.executeRequest(request, new AsyncCompletionHandler() { - @Override - public String onCompleted(Response response) throws Exception { - return response.getUri().toString(); - } + AsyncHttpClient client = getAsyncHttpClient(null); + try { + Request request = new RequestBuilder("GET").setUrl("http://foo.com/foo.html").addQueryParameter("q", "a b").build(); - /* @Override */ - public void onThrowable(Throwable t) { - t.printStackTrace(); - Assert.fail("Unexpected exception: " + t.getMessage(), t); - } + Future responseFuture = client.executeRequest(request, new AsyncCompletionHandler() { + @Override + public String onCompleted(Response response) throws Exception { + return response.getUri().toString(); + } + + /* @Override */ + public void onThrowable(Throwable t) { + t.printStackTrace(); + Assert.fail("Unexpected exception: " + t.getMessage(), t); + } - }); - String url = responseFuture.get(); - Assert.assertEquals(url, "http://foo.com/foo.html?q=a%20b"); - p.close(); + }); + String url = responseFuture.get(); + Assert.assertEquals(url, "http://foo.com/foo.html?q=a%20b"); + } finally { + client.close(); + } } - @Test(groups = {"standalone", "default_provider", "async"}) + @Test(groups = { "standalone", "default_provider", "async" }) public void emptyRequestURI() throws Throwable { - AsyncHttpClient p = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().build()); - Request request = new RequestBuilder("GET").setUrl("http://foo.com/") - .build(); - - Future responseFuture = p.executeRequest(request, new AsyncCompletionHandler() { - @Override - public String onCompleted(Response response) throws Exception { - return response.getUri().toString(); - } + AsyncHttpClient client = getAsyncHttpClient(null); + try { + Request request = new RequestBuilder("GET").setUrl("http://foo.com/").build(); - /* @Override */ - public void onThrowable(Throwable t) { - t.printStackTrace(); - Assert.fail("Unexpected exception: " + t.getMessage(), t); - } + Future responseFuture = client.executeRequest(request, new AsyncCompletionHandler() { + @Override + public String onCompleted(Response response) throws Exception { + return response.getUri().toString(); + } + + /* @Override */ + public void onThrowable(Throwable t) { + t.printStackTrace(); + Assert.fail("Unexpected exception: " + t.getMessage(), t); + } - }); - String url = responseFuture.get(); - Assert.assertEquals(url, "http://foo.com/"); - p.close(); + }); + String url = responseFuture.get(); + Assert.assertEquals(url, "http://foo.com/"); + } finally { + client.close(); + } } - @Test(groups = {"standalone", "default_provider", "async"}) + @Test(groups = { "standalone", "default_provider", "async" }) public void asyncProviderContentLenghtGETTest() throws Throwable { - AsyncHttpClient p = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().build()); - final CountDownLatch l = new CountDownLatch(1); - URL url = new URL(getTargetUrl()); - final HttpURLConnection connection = (HttpURLConnection) url.openConnection(); - connection.connect(); + AsyncHttpClient client = getAsyncHttpClient(null); + try { + final CountDownLatch l = new CountDownLatch(1); + URL url = new URL(getTargetUrl()); + final HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.connect(); - Request request = new RequestBuilder("GET").setUrl(getTargetUrl()).build(); - p.executeRequest(request, new AsyncCompletionHandlerAdapter() { + Request request = new RequestBuilder("GET").setUrl(getTargetUrl()).build(); + client.executeRequest(request, new AsyncCompletionHandlerAdapter() { - @Override - public Response onCompleted(Response response) throws Exception { - try { - assertEquals(response.getStatusCode(), 200); - int contentLenght = -1; - if (response.getHeader("content-length") != null) { - contentLenght = Integer.valueOf(response.getHeader("content-length")); + @Override + public Response onCompleted(Response response) throws Exception { + try { + assertEquals(response.getStatusCode(), 200); + int contentLenght = -1; + if (response.getHeader("content-length") != null) { + contentLenght = Integer.valueOf(response.getHeader("content-length")); + } + int ct = connection.getContentLength(); + assertEquals(contentLenght, ct); + } finally { + l.countDown(); } - int ct = connection.getContentLength(); - assertEquals(contentLenght, ct); - } finally { - l.countDown(); + return response; } - return response; - } - @Override - public void onThrowable(Throwable t) { - try { - Assert.fail("Unexpected exception", t); - } finally { - l.countDown(); + @Override + public void onThrowable(Throwable t) { + try { + Assert.fail("Unexpected exception", t); + } finally { + l.countDown(); + } } - } + }).get(); - }).get(); - - if (!l.await(TIMEOUT, TimeUnit.SECONDS)) { - Assert.fail("Timeout out"); + if (!l.await(TIMEOUT, TimeUnit.SECONDS)) { + Assert.fail("Timeout out"); + } + } finally { + client.close(); } - - p.close(); } - @Test(groups = {"standalone", "default_provider", "async"}) + @Test(groups = { "standalone", "default_provider", "async" }) public void asyncContentTypeGETTest() throws Throwable { - AsyncHttpClient p = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().build()); - - final CountDownLatch l = new CountDownLatch(1); - Request request = new RequestBuilder("GET").setUrl(getTargetUrl()).build(); - p.executeRequest(request, new AsyncCompletionHandlerAdapter() { + AsyncHttpClient client = getAsyncHttpClient(null); + try { + final CountDownLatch l = new CountDownLatch(1); + Request request = new RequestBuilder("GET").setUrl(getTargetUrl()).build(); + client.executeRequest(request, new AsyncCompletionHandlerAdapter() { - @Override - public Response onCompleted(Response response) throws Exception { - try { - assertEquals(response.getStatusCode(), 200); - assertEquals(response.getContentType(), UTF_8); - } finally { - l.countDown(); + @Override + public Response onCompleted(Response response) throws Exception { + try { + assertEquals(response.getStatusCode(), 200); + assertEquals(response.getContentType(), UTF_8); + } finally { + l.countDown(); + } + return response; } - return response; + }).get(); + if (!l.await(TIMEOUT, TimeUnit.SECONDS)) { + Assert.fail("Timeout out"); } - }).get(); - if (!l.await(TIMEOUT, TimeUnit.SECONDS)) { - Assert.fail("Timeout out"); + } finally { + client.close(); } - p.close(); } - @Test(groups = {"standalone", "default_provider", "async"}) + @Test(groups = { "standalone", "default_provider", "async" }) public void asyncHeaderGETTest() throws Throwable { - AsyncHttpClient n = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().build()); - final CountDownLatch l = new CountDownLatch(1); - Request request = new RequestBuilder("GET").setUrl(getTargetUrl()).build(); - n.executeRequest(request, new AsyncCompletionHandlerAdapter() { + AsyncHttpClient client = getAsyncHttpClient(null); + try { + final CountDownLatch l = new CountDownLatch(1); + Request request = new RequestBuilder("GET").setUrl(getTargetUrl()).build(); + client.executeRequest(request, new AsyncCompletionHandlerAdapter() { - @Override - public Response onCompleted(Response response) throws Exception { - try { - assertEquals(response.getStatusCode(), 200); - assertEquals(response.getContentType(), UTF_8); - } finally { - l.countDown(); + @Override + public Response onCompleted(Response response) throws Exception { + try { + assertEquals(response.getStatusCode(), 200); + assertEquals(response.getContentType(), UTF_8); + } finally { + l.countDown(); + } + return response; } - return response; - } - }).get(); + }).get(); - if (!l.await(TIMEOUT, TimeUnit.SECONDS)) { - Assert.fail("Timeout out"); + if (!l.await(TIMEOUT, TimeUnit.SECONDS)) { + Assert.fail("Timeout out"); + } + } finally { + client.close(); } - n.close(); } - @Test(groups = {"standalone", "default_provider", "async"}) + @Test(groups = { "standalone", "default_provider", "async" }) public void asyncHeaderPOSTTest() throws Throwable { - final CountDownLatch l = new CountDownLatch(1); - AsyncHttpClient n = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().build()); - - FluentCaseInsensitiveStringsMap h = new FluentCaseInsensitiveStringsMap(); - h.add("Test1", "Test1"); - h.add("Test2", "Test2"); - h.add("Test3", "Test3"); - h.add("Test4", "Test4"); - h.add("Test5", "Test5"); - Request request = new RequestBuilder("GET").setUrl(getTargetUrl()).setHeaders(h).build(); + AsyncHttpClient client = getAsyncHttpClient(null); + try { + final CountDownLatch l = new CountDownLatch(1); + FluentCaseInsensitiveStringsMap h = new FluentCaseInsensitiveStringsMap(); + h.add("Test1", "Test1"); + h.add("Test2", "Test2"); + h.add("Test3", "Test3"); + h.add("Test4", "Test4"); + h.add("Test5", "Test5"); + Request request = new RequestBuilder("GET").setUrl(getTargetUrl()).setHeaders(h).build(); - n.executeRequest(request, new AsyncCompletionHandlerAdapter() { + client.executeRequest(request, new AsyncCompletionHandlerAdapter() { - @Override - public Response onCompleted(Response response) throws Exception { - try { - System.out.println(">>>>> " + response.getStatusText()); - assertEquals(response.getStatusCode(), 200); - for (int i = 1; i < 5; i++) { - assertEquals(response.getHeader("X-Test" + i), "Test" + i); + @Override + public Response onCompleted(Response response) throws Exception { + try { + System.out.println(">>>>> " + response.getStatusText()); + assertEquals(response.getStatusCode(), 200); + for (int i = 1; i < 5; i++) { + assertEquals(response.getHeader("X-Test" + i), "Test" + i); + } + } finally { + l.countDown(); } - } finally { - l.countDown(); + return response; } - return response; - } - }).get(); + }).get(); - if (!l.await(TIMEOUT, TimeUnit.SECONDS)) { - Assert.fail("Timeout out"); + if (!l.await(TIMEOUT, TimeUnit.SECONDS)) { + Assert.fail("Timeout out"); + } + } finally { + client.close(); } - n.close(); } - @Test(groups = {"standalone", "default_provider", "async"}) + @Test(groups = { "standalone", "default_provider", "async" }) public void asyncParamPOSTTest() throws Throwable { - AsyncHttpClient n = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().build()); - - final CountDownLatch l = new CountDownLatch(1); - FluentCaseInsensitiveStringsMap h = new FluentCaseInsensitiveStringsMap(); - h.add("Content-Type", "application/x-www-form-urlencoded"); + AsyncHttpClient client = getAsyncHttpClient(null); + try { + final CountDownLatch l = new CountDownLatch(1); + FluentCaseInsensitiveStringsMap h = new FluentCaseInsensitiveStringsMap(); + h.add("Content-Type", "application/x-www-form-urlencoded"); - Map> m = new HashMap>(); - for (int i = 0; i < 5; i++) { - m.put("param_" + i, Arrays.asList("value_" + i)); - } - Request request = new RequestBuilder("POST").setUrl(getTargetUrl()).setHeaders(h).setParameters(m).build(); - n.executeRequest(request, new AsyncCompletionHandlerAdapter() { + Map> m = new HashMap>(); + for (int i = 0; i < 5; i++) { + m.put("param_" + i, Arrays.asList("value_" + i)); + } + Request request = new RequestBuilder("POST").setUrl(getTargetUrl()).setHeaders(h).setParameters(m).build(); + client.executeRequest(request, new AsyncCompletionHandlerAdapter() { - @Override - public Response onCompleted(Response response) throws Exception { - try { - assertEquals(response.getStatusCode(), 200); - for (int i = 1; i < 5; i++) { - System.out.println(">>>>> " + response.getHeader("X-param_" + i)); - assertEquals(response.getHeader("X-param_" + i), "value_" + i); + @Override + public Response onCompleted(Response response) throws Exception { + try { + assertEquals(response.getStatusCode(), 200); + for (int i = 1; i < 5; i++) { + System.out.println(">>>>> " + response.getHeader("X-param_" + i)); + assertEquals(response.getHeader("X-param_" + i), "value_" + i); + } + + } finally { + l.countDown(); } - - } finally { - l.countDown(); + return response; } - return response; - } - }).get(); + }).get(); - if (!l.await(TIMEOUT, TimeUnit.SECONDS)) { - Assert.fail("Timeout out"); + if (!l.await(TIMEOUT, TimeUnit.SECONDS)) { + Assert.fail("Timeout out"); + } + } finally { + client.close(); } - n.close(); - } - @Test(groups = {"standalone", "default_provider", "async"}) + @Test(groups = { "standalone", "default_provider", "async" }) public void asyncStatusHEADTest() throws Throwable { - AsyncHttpClient n = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().build()); - - final CountDownLatch l = new CountDownLatch(1); - Request request = new RequestBuilder("HEAD").setUrl(getTargetUrl()).build(); - Response response = n.executeRequest(request, new AsyncCompletionHandlerAdapter() { + AsyncHttpClient client = getAsyncHttpClient(null); + try { + final CountDownLatch l = new CountDownLatch(1); + Request request = new RequestBuilder("HEAD").setUrl(getTargetUrl()).build(); + Response response = client.executeRequest(request, new AsyncCompletionHandlerAdapter() { - @Override - public Response onCompleted(Response response) throws Exception { - try { - assertEquals(response.getStatusCode(), 200); - } finally { - l.countDown(); + @Override + public Response onCompleted(Response response) throws Exception { + try { + assertEquals(response.getStatusCode(), 200); + } finally { + l.countDown(); + } + return response; } - return response; - } - }).get(); + }).get(); - try { - String s = response.getResponseBody(); - Assert.assertEquals("",s); - } catch (IllegalStateException ex) { - fail(); - } + try { + String s = response.getResponseBody(); + Assert.assertEquals("", s); + } catch (IllegalStateException ex) { + fail(); + } - if (!l.await(TIMEOUT, TimeUnit.SECONDS)) { - Assert.fail("Timeout out"); + if (!l.await(TIMEOUT, TimeUnit.SECONDS)) { + Assert.fail("Timeout out"); + } + } finally { + client.close(); } - n.close(); - } // TODO: fix test - @Test(groups = {"standalone", "default_provider", "async"}, enabled = false) + @Test(groups = { "standalone", "default_provider", "async" }, enabled = false) public void asyncStatusHEADContentLenghtTest() throws Throwable { - AsyncHttpClient n = getAsyncHttpClient(new AsyncHttpClientConfig.Builder() - .setRequestTimeoutInMs(120 * 1000).build()); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeoutInMs(120 * 1000).build()); + try { + final CountDownLatch l = new CountDownLatch(1); + Request request = new RequestBuilder("HEAD").setUrl(getTargetUrl()).build(); - final CountDownLatch l = new CountDownLatch(1); - Request request = new RequestBuilder("HEAD") - .setUrl(getTargetUrl()) - .build(); + client.executeRequest(request, new AsyncCompletionHandlerAdapter() { + @Override + public Response onCompleted(Response response) throws Exception { + Assert.fail(); + return response; + } - n.executeRequest(request, new AsyncCompletionHandlerAdapter() { - @Override - public Response onCompleted(Response response) throws Exception { - Assert.fail(); - return response; - } + @Override + public void onThrowable(Throwable t) { + try { + assertEquals(t.getClass(), IOException.class); + assertEquals(t.getMessage(), "No response received. Connection timed out"); + } finally { + l.countDown(); + } - @Override - public void onThrowable(Throwable t) { - try { - assertEquals(t.getClass(), IOException.class); - assertEquals(t.getMessage(), "No response received. Connection timed out"); - } finally { - l.countDown(); } + }).get(); + if (!l.await(10 * 5 * 1000, TimeUnit.SECONDS)) { + Assert.fail("Timeout out"); } - }).get(); - - if (!l.await(10 * 5 * 1000, TimeUnit.SECONDS)) { - Assert.fail("Timeout out"); + } finally { + client.close(); } - n.close(); - } - @Test(groups = {"online", "default_provider", "async"}) + @Test(groups = { "online", "default_provider", "async" }) public void asyncNullSchemeTest() throws Throwable { - AsyncHttpClient c = getAsyncHttpClient(null); - + AsyncHttpClient client = getAsyncHttpClient(null); try { - c.prepareGet("www.sun.com").execute(); + client.prepareGet("www.sun.com").execute(); Assert.fail(); } catch (IllegalArgumentException ex) { Assert.assertTrue(true); } - c.close(); - } - @Test(groups = {"standalone", "default_provider", "async"}) + @Test(groups = { "standalone", "default_provider", "async" }) public void asyncDoGetTransferEncodingTest() throws Throwable { - AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().build()); - final CountDownLatch l = new CountDownLatch(1); + AsyncHttpClient client = getAsyncHttpClient(null); + try { + final CountDownLatch l = new CountDownLatch(1); - c.prepareGet(getTargetUrl()).execute(new AsyncCompletionHandlerAdapter() { + client.prepareGet(getTargetUrl()).execute(new AsyncCompletionHandlerAdapter() { - @Override - public Response onCompleted(Response response) throws Exception { - try { - assertEquals(response.getStatusCode(), 200); - assertEquals(response.getHeader("Transfer-Encoding"), "chunked"); - } finally { - l.countDown(); + @Override + public Response onCompleted(Response response) throws Exception { + try { + assertEquals(response.getStatusCode(), 200); + assertEquals(response.getHeader("Transfer-Encoding"), "chunked"); + } finally { + l.countDown(); + } + return response; } - return response; - } - }).get(); + }).get(); - if (!l.await(TIMEOUT, TimeUnit.SECONDS)) { - Assert.fail("Timeout out"); + if (!l.await(TIMEOUT, TimeUnit.SECONDS)) { + Assert.fail("Timeout out"); + } + } finally { + client.close(); } - c.close(); - } - @Test(groups = {"standalone", "default_provider", "async"}) + @Test(groups = { "standalone", "default_provider", "async" }) public void asyncDoGetHeadersTest() throws Throwable { - AsyncHttpClient c = getAsyncHttpClient(null); - final CountDownLatch l = new CountDownLatch(1); - FluentCaseInsensitiveStringsMap h = new FluentCaseInsensitiveStringsMap(); - h.add("Test1", "Test1"); - h.add("Test2", "Test2"); - h.add("Test3", "Test3"); - h.add("Test4", "Test4"); - h.add("Test5", "Test5"); - c.prepareGet(getTargetUrl()).setHeaders(h).execute(new AsyncCompletionHandlerAdapter() { - - @Override - public Response onCompleted(Response response) throws Exception { - try { - assertEquals(response.getStatusCode(), 200); - for (int i = 1; i < 5; i++) { - assertEquals(response.getHeader("X-Test" + i), "Test" + i); + AsyncHttpClient client = getAsyncHttpClient(null); + try { + final CountDownLatch l = new CountDownLatch(1); + FluentCaseInsensitiveStringsMap h = new FluentCaseInsensitiveStringsMap(); + h.add("Test1", "Test1"); + h.add("Test2", "Test2"); + h.add("Test3", "Test3"); + h.add("Test4", "Test4"); + h.add("Test5", "Test5"); + client.prepareGet(getTargetUrl()).setHeaders(h).execute(new AsyncCompletionHandlerAdapter() { + + @Override + public Response onCompleted(Response response) throws Exception { + try { + assertEquals(response.getStatusCode(), 200); + for (int i = 1; i < 5; i++) { + assertEquals(response.getHeader("X-Test" + i), "Test" + i); + } + } finally { + l.countDown(); } - } finally { - l.countDown(); + return response; } - return response; + }).get(); + if (!l.await(TIMEOUT, TimeUnit.SECONDS)) { + Assert.fail("Timeout out"); } - }).get(); - if (!l.await(TIMEOUT, TimeUnit.SECONDS)) { - Assert.fail("Timeout out"); + } finally { + client.close(); } - c.close(); - } - @Test(groups = {"standalone", "default_provider", "async"}) + @Test(groups = { "standalone", "default_provider", "async" }) public void asyncDoGetCookieTest() throws Throwable { - AsyncHttpClient c = getAsyncHttpClient(null); - final CountDownLatch l = new CountDownLatch(1); - FluentCaseInsensitiveStringsMap h = new FluentCaseInsensitiveStringsMap(); - h.add("Test1", "Test1"); - h.add("Test2", "Test2"); - h.add("Test3", "Test3"); - h.add("Test4", "Test4"); - h.add("Test5", "Test5"); - - final Cookie coo = new Cookie("/", "foo", "value", "/", -1, false); - c.prepareGet(getTargetUrl()).setHeaders(h).addCookie(coo).execute(new AsyncCompletionHandlerAdapter() { - - @Override - public Response onCompleted(Response response) throws Exception { - try { - assertEquals(response.getStatusCode(), 200); - List cookies = response.getCookies(); - assertEquals(cookies.size(), 1); - assertEquals(cookies.get(0).toString(), coo.toString()); - } finally { - l.countDown(); + AsyncHttpClient client = getAsyncHttpClient(null); + try { + final CountDownLatch l = new CountDownLatch(1); + FluentCaseInsensitiveStringsMap h = new FluentCaseInsensitiveStringsMap(); + h.add("Test1", "Test1"); + h.add("Test2", "Test2"); + h.add("Test3", "Test3"); + h.add("Test4", "Test4"); + h.add("Test5", "Test5"); + + final Cookie coo = new Cookie("/", "foo", "value", "/", -1, false); + client.prepareGet(getTargetUrl()).setHeaders(h).addCookie(coo).execute(new AsyncCompletionHandlerAdapter() { + + @Override + public Response onCompleted(Response response) throws Exception { + try { + assertEquals(response.getStatusCode(), 200); + List cookies = response.getCookies(); + assertEquals(cookies.size(), 1); + assertEquals(cookies.get(0).toString(), coo.toString()); + } finally { + l.countDown(); + } + return response; } - return response; - } - }).get(); + }).get(); - if (!l.await(TIMEOUT, TimeUnit.SECONDS)) { - Assert.fail("Timeout out"); + if (!l.await(TIMEOUT, TimeUnit.SECONDS)) { + Assert.fail("Timeout out"); + } + } finally { + client.close(); } - c.close(); } - @Test(groups = {"standalone", "default_provider", "async"}) + @Test(groups = { "standalone", "default_provider", "async" }) public void asyncDoPostDefaultContentType() throws Throwable { + AsyncHttpClient client = getAsyncHttpClient(null); + try { + final CountDownLatch l = new CountDownLatch(1); + client.preparePost(getTargetUrl()).addParameter("foo", "bar").execute(new AsyncCompletionHandlerAdapter() { - AsyncHttpClient c = getAsyncHttpClient(null); - final CountDownLatch l = new CountDownLatch(1); - c.preparePost(getTargetUrl()).addParameter("foo", "bar").execute(new AsyncCompletionHandlerAdapter() { - - @Override - public Response onCompleted(Response response) throws Exception { - try { - assertEquals(response.getStatusCode(), 200); - FluentCaseInsensitiveStringsMap h = response.getHeaders(); - assertEquals(h.getJoinedValue("X-Content-Type", ", "), "application/x-www-form-urlencoded"); - } finally { - l.countDown(); + @Override + public Response onCompleted(Response response) throws Exception { + try { + assertEquals(response.getStatusCode(), 200); + FluentCaseInsensitiveStringsMap h = response.getHeaders(); + assertEquals(h.getJoinedValue("X-Content-Type", ", "), "application/x-www-form-urlencoded"); + } finally { + l.countDown(); + } + return response; } - return response; - } - }).get(); + }).get(); - if (!l.await(TIMEOUT, TimeUnit.SECONDS)) { - Assert.fail("Timeout out"); + if (!l.await(TIMEOUT, TimeUnit.SECONDS)) { + Assert.fail("Timeout out"); + } + } finally { + client.close(); } - c.close(); } - @Test(groups = {"standalone", "default_provider", "async"}) + @Test(groups = { "standalone", "default_provider", "async" }) public void asyncDoPostBodyIsoTest() throws Throwable { - - AsyncHttpClient c = getAsyncHttpClient(null); - final CountDownLatch l = new CountDownLatch(1); - Response r = c.preparePost(getTargetUrl()).addHeader("X-ISO", "true").setBody("\u017D\u017D\u017D\u017D\u017D\u017D").execute().get(); - assertEquals(r.getResponseBody().getBytes("ISO-8859-1"),"\u017D\u017D\u017D\u017D\u017D\u017D".getBytes("ISO-8859-1")); - c.close(); - } - - @Test(groups = {"standalone", "default_provider", "async"}) - public void asyncDoPostBytesTest() throws Throwable { - - AsyncHttpClient c = getAsyncHttpClient(null); - final CountDownLatch l = new CountDownLatch(1); - FluentCaseInsensitiveStringsMap h = new FluentCaseInsensitiveStringsMap(); - h.add("Content-Type", "application/x-www-form-urlencoded"); - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < 5; i++) { - sb.append("param_"); - sb.append(i); - sb.append("=value_"); - sb.append(i); - sb.append("&"); + AsyncHttpClient client = getAsyncHttpClient(null); + try { + Response r = client.preparePost(getTargetUrl()).addHeader("X-ISO", "true").setBody("\u017D\u017D\u017D\u017D\u017D\u017D").execute().get(); + assertEquals(r.getResponseBody().getBytes("ISO-8859-1"), "\u017D\u017D\u017D\u017D\u017D\u017D".getBytes("ISO-8859-1")); + } finally { + client.close(); } - sb.deleteCharAt(sb.length() - 1); + } - c.preparePost(getTargetUrl()).setHeaders(h).setBody(sb.toString()).execute(new AsyncCompletionHandlerAdapter() { + @Test(groups = { "standalone", "default_provider", "async" }) + public void asyncDoPostBytesTest() throws Throwable { + AsyncHttpClient client = getAsyncHttpClient(null); + try { + final CountDownLatch l = new CountDownLatch(1); + FluentCaseInsensitiveStringsMap h = new FluentCaseInsensitiveStringsMap(); + h.add("Content-Type", "application/x-www-form-urlencoded"); + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < 5; i++) { + sb.append("param_"); + sb.append(i); + sb.append("=value_"); + sb.append(i); + sb.append("&"); + } + sb.deleteCharAt(sb.length() - 1); - @Override - public Response onCompleted(Response response) throws Exception { - try { - assertEquals(response.getStatusCode(), 200); - for (int i = 1; i < 5; i++) { - System.out.println(">>>>> " + response.getHeader("X-param_" + i)); - assertEquals(response.getHeader("X-param_" + i), "value_" + i); + client.preparePost(getTargetUrl()).setHeaders(h).setBody(sb.toString()).execute(new AsyncCompletionHandlerAdapter() { + @Override + public Response onCompleted(Response response) throws Exception { + try { + assertEquals(response.getStatusCode(), 200); + for (int i = 1; i < 5; i++) { + System.out.println(">>>>> " + response.getHeader("X-param_" + i)); + assertEquals(response.getHeader("X-param_" + i), "value_" + i); + + } + } finally { + l.countDown(); } - } finally { - l.countDown(); + return response; } - return response; - } - }).get(); + }).get(); - if (!l.await(TIMEOUT, TimeUnit.SECONDS)) { - Assert.fail("Timeout out"); + if (!l.await(TIMEOUT, TimeUnit.SECONDS)) { + Assert.fail("Timeout out"); + } + } finally { + client.close(); } - c.close(); } - @Test(groups = {"standalone", "default_provider", "async"}) + @Test(groups = { "standalone", "default_provider", "async" }) public void asyncDoPostInputStreamTest() throws Throwable { + AsyncHttpClient client = getAsyncHttpClient(null); + try { + final CountDownLatch l = new CountDownLatch(1); + FluentCaseInsensitiveStringsMap h = new FluentCaseInsensitiveStringsMap(); + h.add("Content-Type", "application/x-www-form-urlencoded"); + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < 5; i++) { + sb.append("param_"); + sb.append(i); + sb.append("=value_"); + sb.append(i); + sb.append("&"); + } + sb.deleteCharAt(sb.length() - 1); + ByteArrayInputStream is = new ByteArrayInputStream(sb.toString().getBytes()); - AsyncHttpClient c = getAsyncHttpClient(null); - final CountDownLatch l = new CountDownLatch(1); - FluentCaseInsensitiveStringsMap h = new FluentCaseInsensitiveStringsMap(); - h.add("Content-Type", "application/x-www-form-urlencoded"); - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < 5; i++) { - sb.append("param_"); - sb.append(i); - sb.append("=value_"); - sb.append(i); - sb.append("&"); - } - sb.deleteCharAt(sb.length() - 1); - ByteArrayInputStream is = new ByteArrayInputStream(sb.toString().getBytes()); - - c.preparePost(getTargetUrl()).setHeaders(h).setBody(is).execute(new AsyncCompletionHandlerAdapter() { - - @Override - public Response onCompleted(Response response) throws Exception { - try { - assertEquals(response.getStatusCode(), 200); - for (int i = 1; i < 5; i++) { - System.out.println(">>>>> " + response.getHeader("X-param_" + i)); - assertEquals(response.getHeader("X-param_" + i), "value_" + i); + client.preparePost(getTargetUrl()).setHeaders(h).setBody(is).execute(new AsyncCompletionHandlerAdapter() { + @Override + public Response onCompleted(Response response) throws Exception { + try { + assertEquals(response.getStatusCode(), 200); + for (int i = 1; i < 5; i++) { + System.out.println(">>>>> " + response.getHeader("X-param_" + i)); + assertEquals(response.getHeader("X-param_" + i), "value_" + i); + + } + } finally { + l.countDown(); } - } finally { - l.countDown(); + return response; } - return response; + }).get(); + if (!l.await(TIMEOUT, TimeUnit.SECONDS)) { + Assert.fail("Timeout out"); } - }).get(); - if (!l.await(TIMEOUT, TimeUnit.SECONDS)) { - Assert.fail("Timeout out"); + } finally { + client.close(); } - c.close(); } - @Test(groups = {"standalone", "default_provider", "async"}) + @Test(groups = { "standalone", "default_provider", "async" }) public void asyncDoPutInputStreamTest() throws Throwable { + AsyncHttpClient client = getAsyncHttpClient(null); + try { + final CountDownLatch l = new CountDownLatch(1); + FluentCaseInsensitiveStringsMap h = new FluentCaseInsensitiveStringsMap(); + h.add("Content-Type", "application/x-www-form-urlencoded"); + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < 5; i++) { + sb.append("param_"); + sb.append(i); + sb.append("=value_"); + sb.append(i); + sb.append("&"); + } + sb.deleteCharAt(sb.length() - 1); + ByteArrayInputStream is = new ByteArrayInputStream(sb.toString().getBytes()); - AsyncHttpClient c = getAsyncHttpClient(null); - final CountDownLatch l = new CountDownLatch(1); - FluentCaseInsensitiveStringsMap h = new FluentCaseInsensitiveStringsMap(); - h.add("Content-Type", "application/x-www-form-urlencoded"); - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < 5; i++) { - sb.append("param_"); - sb.append(i); - sb.append("=value_"); - sb.append(i); - sb.append("&"); - } - sb.deleteCharAt(sb.length() - 1); - ByteArrayInputStream is = new ByteArrayInputStream(sb.toString().getBytes()); - - c.preparePut(getTargetUrl()).setHeaders(h).setBody(is).execute(new AsyncCompletionHandlerAdapter() { - - @Override - public Response onCompleted(Response response) throws Exception { - try { - assertEquals(response.getStatusCode(), 200); - for (int i = 1; i < 5; i++) { - System.out.println(">>>>> " + response.getHeader("X-param_" + i)); - assertEquals(response.getHeader("X-param_" + i), "value_" + i); + client.preparePut(getTargetUrl()).setHeaders(h).setBody(is).execute(new AsyncCompletionHandlerAdapter() { + @Override + public Response onCompleted(Response response) throws Exception { + try { + assertEquals(response.getStatusCode(), 200); + for (int i = 1; i < 5; i++) { + System.out.println(">>>>> " + response.getHeader("X-param_" + i)); + assertEquals(response.getHeader("X-param_" + i), "value_" + i); + + } + } finally { + l.countDown(); } - } finally { - l.countDown(); + return response; } - return response; + }).get(); + if (!l.await(TIMEOUT, TimeUnit.SECONDS)) { + Assert.fail("Timeout out"); } - }).get(); - if (!l.await(TIMEOUT, TimeUnit.SECONDS)) { - Assert.fail("Timeout out"); + } finally { + client.close(); } - c.close(); } - @Test(groups = {"standalone", "default_provider", "async"}) + @Test(groups = { "standalone", "default_provider", "async" }) public void asyncDoPostEntityWriterTest() throws Throwable { + AsyncHttpClient client = getAsyncHttpClient(null); + try { + final CountDownLatch l = new CountDownLatch(1); + FluentCaseInsensitiveStringsMap h = new FluentCaseInsensitiveStringsMap(); + h.add("Content-Type", "application/x-www-form-urlencoded"); + + final StringBuilder sb = new StringBuilder(); + for (int i = 0; i < 5; i++) { + sb.append("param_"); + sb.append(i); + sb.append("=value_"); + sb.append(i); + sb.append("&"); + } + sb.deleteCharAt(sb.length() - 1); + byte[] bytes = sb.toString().getBytes(); + h.add("Content-Length", String.valueOf(bytes.length)); - AsyncHttpClient c = getAsyncHttpClient(null); - final CountDownLatch l = new CountDownLatch(1); - FluentCaseInsensitiveStringsMap h = new FluentCaseInsensitiveStringsMap(); - h.add("Content-Type", "application/x-www-form-urlencoded"); - - final StringBuilder sb = new StringBuilder(); - for (int i = 0; i < 5; i++) { - sb.append("param_"); - sb.append(i); - sb.append("=value_"); - sb.append(i); - sb.append("&"); - } - sb.deleteCharAt(sb.length() - 1); - byte[] bytes = sb.toString().getBytes(); - h.add("Content-Length", String.valueOf(bytes.length)); - - c.preparePost(getTargetUrl()).setHeaders(h).setBody(new Request.EntityWriter() { + client.preparePost(getTargetUrl()).setHeaders(h).setBody(new Request.EntityWriter() { - /* @Override */ - public void writeEntity(OutputStream out) throws IOException { - out.write(sb.toString().getBytes("UTF-8")); - } - }).execute(new AsyncCompletionHandlerAdapter() { + /* @Override */ + public void writeEntity(OutputStream out) throws IOException { + out.write(sb.toString().getBytes("UTF-8")); + } + }).execute(new AsyncCompletionHandlerAdapter() { - @Override - public Response onCompleted(Response response) throws Exception { - try { - assertEquals(response.getStatusCode(), 200); - for (int i = 1; i < 5; i++) { - System.out.println(">>>>> " + response.getHeader("X-param_" + i)); - assertEquals(response.getHeader("X-param_" + i), "value_" + i); + @Override + public Response onCompleted(Response response) throws Exception { + try { + assertEquals(response.getStatusCode(), 200); + for (int i = 1; i < 5; i++) { + System.out.println(">>>>> " + response.getHeader("X-param_" + i)); + assertEquals(response.getHeader("X-param_" + i), "value_" + i); + } + } finally { + l.countDown(); } - } finally { - l.countDown(); + return response; } - return response; + }).get(); + if (!l.await(TIMEOUT, TimeUnit.SECONDS)) { + Assert.fail("Timeout out"); } - }).get(); - if (!l.await(TIMEOUT, TimeUnit.SECONDS)) { - Assert.fail("Timeout out"); + } finally { + client.close(); } - c.close(); } - @Test(groups = {"standalone", "default_provider", "async"}) + @Test(groups = { "standalone", "default_provider", "async" }) public void asyncDoPostMultiPartTest() throws Throwable { + AsyncHttpClient client = getAsyncHttpClient(null); + try { + final CountDownLatch l = new CountDownLatch(1); - AsyncHttpClient c = getAsyncHttpClient(null); - final CountDownLatch l = new CountDownLatch(1); - - Part p = new StringPart("foo", "bar"); + Part p = new StringPart("foo", "bar"); - c.preparePost(getTargetUrl()).addBodyPart(p).execute(new AsyncCompletionHandlerAdapter() { + client.preparePost(getTargetUrl()).addBodyPart(p).execute(new AsyncCompletionHandlerAdapter() { - @Override - public Response onCompleted(Response response) throws Exception { - try { - String xContentType = response.getHeader("X-Content-Type"); - String boundary = xContentType.substring( - (xContentType.indexOf("boundary") + "boundary".length() + 1)); - - String s = response.getResponseBodyExcerpt(boundary.length() + "--".length()).substring("--".length()); - assertEquals(boundary, s); - } finally { - l.countDown(); + @Override + public Response onCompleted(Response response) throws Exception { + try { + String xContentType = response.getHeader("X-Content-Type"); + String boundary = xContentType.substring((xContentType.indexOf("boundary") + "boundary".length() + 1)); + + String s = response.getResponseBodyExcerpt(boundary.length() + "--".length()).substring("--".length()); + assertEquals(boundary, s); + } finally { + l.countDown(); + } + return response; } - return response; + }).get(); + if (!l.await(TIMEOUT, TimeUnit.SECONDS)) { + Assert.fail("Timeout out"); } - }).get(); - if (!l.await(TIMEOUT, TimeUnit.SECONDS)) { - Assert.fail("Timeout out"); + } finally { + client.close(); } - c.close(); } - @Test(groups = {"standalone", "default_provider", "async"}) + @Test(groups = { "standalone", "default_provider", "async" }) public void asyncDoPostBasicGZIPTest() throws Throwable { - AsyncHttpClientConfig cf = new AsyncHttpClientConfig.Builder().setCompressionEnabled(true).build(); - AsyncHttpClient c = getAsyncHttpClient(cf); - final CountDownLatch l = new CountDownLatch(1); - FluentCaseInsensitiveStringsMap h = new FluentCaseInsensitiveStringsMap(); - h.add("Content-Type", "application/x-www-form-urlencoded"); - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < 5; i++) { - sb.append("param_"); - sb.append(i); - sb.append("=value_"); - sb.append(i); - sb.append("&"); - } - sb.deleteCharAt(sb.length() - 1); + AsyncHttpClient client = getAsyncHttpClient(cf); + try { + final CountDownLatch l = new CountDownLatch(1); + FluentCaseInsensitiveStringsMap h = new FluentCaseInsensitiveStringsMap(); + h.add("Content-Type", "application/x-www-form-urlencoded"); + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < 5; i++) { + sb.append("param_"); + sb.append(i); + sb.append("=value_"); + sb.append(i); + sb.append("&"); + } + sb.deleteCharAt(sb.length() - 1); - c.preparePost(getTargetUrl()).setHeaders(h).setBody(sb.toString()).execute(new AsyncCompletionHandlerAdapter() { + client.preparePost(getTargetUrl()).setHeaders(h).setBody(sb.toString()).execute(new AsyncCompletionHandlerAdapter() { - @Override - public Response onCompleted(Response response) throws Exception { - try { - assertEquals(response.getStatusCode(), 200); - assertEquals(response.getHeader("X-Accept-Encoding"), "gzip"); - } finally { - l.countDown(); + @Override + public Response onCompleted(Response response) throws Exception { + try { + assertEquals(response.getStatusCode(), 200); + assertEquals(response.getHeader("X-Accept-Encoding"), "gzip"); + } finally { + l.countDown(); + } + return response; } - return response; + }).get(); + if (!l.await(TIMEOUT, TimeUnit.SECONDS)) { + Assert.fail("Timeout out"); } - }).get(); - if (!l.await(TIMEOUT, TimeUnit.SECONDS)) { - Assert.fail("Timeout out"); + } finally { + client.close(); } - c.close(); - } - @Test(groups = {"standalone", "default_provider", "async"}) + @Test(groups = { "standalone", "default_provider", "async" }) public void asyncDoPostProxyTest() throws Throwable { - AsyncHttpClientConfig cf = new AsyncHttpClientConfig.Builder().setProxyServer(new ProxyServer("127.0.0.1", port2)).build(); - AsyncHttpClient c = getAsyncHttpClient(cf); - - FluentCaseInsensitiveStringsMap h = new FluentCaseInsensitiveStringsMap(); - h.add("Content-Type", "application/x-www-form-urlencoded"); - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < 5; i++) { - sb.append("param_"); - sb.append(i); - sb.append("=value_"); - sb.append(i); - sb.append("&"); - } - sb.deleteCharAt(sb.length() - 1); - - Response response = c.preparePost(getTargetUrl()).setHeaders(h).setBody(sb.toString()).execute(new AsyncCompletionHandler() { - @Override - public Response onCompleted(Response response) throws Exception { - return response; + AsyncHttpClient client = getAsyncHttpClient(cf); + try { + FluentCaseInsensitiveStringsMap h = new FluentCaseInsensitiveStringsMap(); + h.add("Content-Type", "application/x-www-form-urlencoded"); + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < 5; i++) { + sb.append("param_"); + sb.append(i); + sb.append("=value_"); + sb.append(i); + sb.append("&"); } + sb.deleteCharAt(sb.length() - 1); - @Override - public void onThrowable(Throwable t) { - } - }).get(); + Response response = client.preparePost(getTargetUrl()).setHeaders(h).setBody(sb.toString()).execute(new AsyncCompletionHandler() { + @Override + public Response onCompleted(Response response) throws Exception { + return response; + } + @Override + public void onThrowable(Throwable t) { + } + }).get(); - assertEquals(response.getStatusCode(), 200); - assertEquals(response.getHeader("X-Proxy-Connection"), "keep-alive"); - c.close(); + assertEquals(response.getStatusCode(), 200); + assertEquals(response.getHeader("X-Proxy-Connection"), "keep-alive"); + } finally { + client.close(); + } } - - @Test(groups = {"standalone", "default_provider", "async"}) + @Test(groups = { "standalone", "default_provider", "async" }) public void asyncRequestVirtualServerPOSTTest() throws Throwable { - AsyncHttpClient n = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().build()); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().build()); + try { + FluentCaseInsensitiveStringsMap h = new FluentCaseInsensitiveStringsMap(); + h.add("Content-Type", "application/x-www-form-urlencoded"); - FluentCaseInsensitiveStringsMap h = new FluentCaseInsensitiveStringsMap(); - h.add("Content-Type", "application/x-www-form-urlencoded"); + Map> m = new HashMap>(); + for (int i = 0; i < 5; i++) { + m.put("param_" + i, Arrays.asList("value_" + i)); + } + Request request = new RequestBuilder("POST").setUrl(getTargetUrl()).setHeaders(h).setParameters(m).setVirtualHost("localhost:" + port1).build(); - Map> m = new HashMap>(); - for (int i = 0; i < 5; i++) { - m.put("param_" + i, Arrays.asList("value_" + i)); - } - Request request = new RequestBuilder("POST") - .setUrl(getTargetUrl()) - .setHeaders(h) - .setParameters(m) - .setVirtualHost("localhost:" + port1) - .build(); - - Response response = n.executeRequest(request, new AsyncCompletionHandlerAdapter()).get(); - - assertEquals(response.getStatusCode(), 200); - if (response.getHeader("X-Host").startsWith("localhost")) { - assertEquals(response.getHeader("X-Host"), "localhost:" + port1); - } else { - assertEquals(response.getHeader("X-Host"), "127.0.0.1:" + port1); - } - n.close(); + Response response = client.executeRequest(request, new AsyncCompletionHandlerAdapter()).get(); + assertEquals(response.getStatusCode(), 200); + if (response.getHeader("X-Host").startsWith("localhost")) { + assertEquals(response.getHeader("X-Host"), "localhost:" + port1); + } else { + assertEquals(response.getHeader("X-Host"), "127.0.0.1:" + port1); + } + } finally { + client.close(); + } } - @Test(groups = {"standalone", "default_provider", "async"}) + @Test(groups = { "standalone", "default_provider", "async" }) public void asyncDoPutTest() throws Throwable { + AsyncHttpClient client = getAsyncHttpClient(null); + try { + FluentCaseInsensitiveStringsMap h = new FluentCaseInsensitiveStringsMap(); + h.add("Content-Type", "application/x-www-form-urlencoded"); + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < 5; i++) { + sb.append("param_"); + sb.append(i); + sb.append("=value_"); + sb.append(i); + sb.append("&"); + } + sb.deleteCharAt(sb.length() - 1); - AsyncHttpClient c = getAsyncHttpClient(null); - FluentCaseInsensitiveStringsMap h = new FluentCaseInsensitiveStringsMap(); - h.add("Content-Type", "application/x-www-form-urlencoded"); - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < 5; i++) { - sb.append("param_"); - sb.append(i); - sb.append("=value_"); - sb.append(i); - sb.append("&"); - } - sb.deleteCharAt(sb.length() - 1); - - Response response = c.preparePut(getTargetUrl()).setHeaders(h).setBody(sb.toString()).execute(new AsyncCompletionHandlerAdapter()).get(); - - assertEquals(response.getStatusCode(), 200); - c.close(); + Response response = client.preparePut(getTargetUrl()).setHeaders(h).setBody(sb.toString()).execute(new AsyncCompletionHandlerAdapter()).get(); + assertEquals(response.getStatusCode(), 200); + } finally { + client.close(); + } } - @Test(groups = {"standalone", "default_provider", "async"}) + @Test(groups = { "standalone", "default_provider", "async" }) public void asyncDoPostLatchBytesTest() throws Throwable { + AsyncHttpClient client = getAsyncHttpClient(null); + try { + final CountDownLatch l = new CountDownLatch(1); + FluentCaseInsensitiveStringsMap h = new FluentCaseInsensitiveStringsMap(); + h.add("Content-Type", "application/x-www-form-urlencoded"); + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < 5; i++) { + sb.append("param_"); + sb.append(i); + sb.append("=value_"); + sb.append(i); + sb.append("&"); + } + sb.deleteCharAt(sb.length() - 1); - AsyncHttpClient c = getAsyncHttpClient(null); - final CountDownLatch l = new CountDownLatch(1); - FluentCaseInsensitiveStringsMap h = new FluentCaseInsensitiveStringsMap(); - h.add("Content-Type", "application/x-www-form-urlencoded"); - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < 5; i++) { - sb.append("param_"); - sb.append(i); - sb.append("=value_"); - sb.append(i); - sb.append("&"); - } - sb.deleteCharAt(sb.length() - 1); - - c.preparePost(getTargetUrl()).setHeaders(h).setBody(sb.toString()).execute(new AsyncCompletionHandlerAdapter() { - - @Override - public Response onCompleted(Response response) throws Exception { - try { - assertEquals(response.getStatusCode(), 200); - for (int i = 1; i < 5; i++) { - System.out.println(">>>>> " + response.getHeader("X-param_" + i)); - assertEquals(response.getHeader("X-param_" + i), "value_" + i); + client.preparePost(getTargetUrl()).setHeaders(h).setBody(sb.toString()).execute(new AsyncCompletionHandlerAdapter() { + @Override + public Response onCompleted(Response response) throws Exception { + try { + assertEquals(response.getStatusCode(), 200); + for (int i = 1; i < 5; i++) { + System.out.println(">>>>> " + response.getHeader("X-param_" + i)); + assertEquals(response.getHeader("X-param_" + i), "value_" + i); + + } + return response; + } finally { + l.countDown(); } - return response; - } finally { - l.countDown(); } - } - }); + }); - if (!l.await(TIMEOUT, TimeUnit.SECONDS)) { - Assert.fail("Timeout out"); + if (!l.await(TIMEOUT, TimeUnit.SECONDS)) { + Assert.fail("Timeout out"); + } + } finally { + client.close(); } - c.close(); - } - @Test(groups = {"standalone", "default_provider", "async"}) + @Test(groups = { "standalone", "default_provider", "async" }) public void asyncDoPostDelayCancelTest() throws Throwable { + AsyncHttpClient client = getAsyncHttpClient(null); + try { + FluentCaseInsensitiveStringsMap h = new FluentCaseInsensitiveStringsMap(); + h.add("Content-Type", "application/x-www-form-urlencoded"); + h.add("LockThread", "true"); + StringBuilder sb = new StringBuilder(); + sb.append("LockThread=true"); - AsyncHttpClient c = getAsyncHttpClient(null); - FluentCaseInsensitiveStringsMap h = new FluentCaseInsensitiveStringsMap(); - h.add("Content-Type", "application/x-www-form-urlencoded"); - h.add("LockThread", "true"); - StringBuilder sb = new StringBuilder(); - sb.append("LockThread=true"); + Future future = client.preparePost(getTargetUrl()).setHeaders(h).setBody(sb.toString()).execute(new AsyncCompletionHandlerAdapter() { + @Override + public void onThrowable(Throwable t) { + } + }); - Future future = c.preparePost(getTargetUrl()).setHeaders(h).setBody(sb.toString()).execute(new AsyncCompletionHandlerAdapter(){ - @Override - public void onThrowable(Throwable t) { - } - }); - - // Make sure we are connected before cancelling. I know, Thread.sleep sucks! - Thread.sleep(1000); - future.cancel(true); - Response response = future.get(TIMEOUT, TimeUnit.SECONDS); - Assert.assertNull(response); - c.close(); + // Make sure we are connected before cancelling. I know, Thread.sleep + // sucks! + Thread.sleep(1000); + future.cancel(true); + Response response = future.get(TIMEOUT, TimeUnit.SECONDS); + Assert.assertNull(response); + } finally { + client.close(); + } } - @Test(groups = {"standalone", "default_provider", "async"}) + @Test(groups = { "standalone", "default_provider", "async" }) public void asyncDoPostDelayBytesTest() throws Throwable { + AsyncHttpClient client = getAsyncHttpClient(null); + try { + FluentCaseInsensitiveStringsMap h = new FluentCaseInsensitiveStringsMap(); + h.add("Content-Type", "application/x-www-form-urlencoded"); + h.add("LockThread", "true"); + StringBuilder sb = new StringBuilder(); + sb.append("LockThread=true"); - AsyncHttpClient c = getAsyncHttpClient(null); - FluentCaseInsensitiveStringsMap h = new FluentCaseInsensitiveStringsMap(); - h.add("Content-Type", "application/x-www-form-urlencoded"); - h.add("LockThread", "true"); - StringBuilder sb = new StringBuilder(); - sb.append("LockThread=true"); + try { + Future future = client.preparePost(getTargetUrl()).setHeaders(h).setBody(sb.toString()).execute(new AsyncCompletionHandlerAdapter() { + @Override + public void onThrowable(Throwable t) { + t.printStackTrace(); + } + }); - try { - Future future = c.preparePost(getTargetUrl()).setHeaders(h).setBody(sb.toString()).execute(new AsyncCompletionHandlerAdapter() { - @Override - public void onThrowable(Throwable t) { - t.printStackTrace(); + future.get(10, TimeUnit.SECONDS); + } catch (ExecutionException ex) { + if (ex.getCause() != null && TimeoutException.class.isAssignableFrom(ex.getCause().getClass())) { + Assert.assertTrue(true); } - }); - - future.get(10, TimeUnit.SECONDS); - } catch (ExecutionException ex) { - if (ex.getCause() != null && TimeoutException.class.isAssignableFrom(ex.getCause().getClass())) { + } catch (TimeoutException te) { Assert.assertTrue(true); + } catch (IllegalStateException ex) { + Assert.assertTrue(false); } - } catch (TimeoutException te) { - Assert.assertTrue(true); - } catch (IllegalStateException ex) { - Assert.assertTrue(false); + } finally { + client.close(); } - c.close(); } - @Test(groups = {"standalone", "default_provider", "async"}) + @Test(groups = { "standalone", "default_provider", "async" }) public void asyncDoPostNullBytesTest() throws Throwable { + AsyncHttpClient client = getAsyncHttpClient(null); + try { + FluentCaseInsensitiveStringsMap h = new FluentCaseInsensitiveStringsMap(); + h.add("Content-Type", "application/x-www-form-urlencoded"); + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < 5; i++) { + sb.append("param_"); + sb.append(i); + sb.append("=value_"); + sb.append(i); + sb.append("&"); + } + sb.deleteCharAt(sb.length() - 1); - AsyncHttpClient c = getAsyncHttpClient(null); - FluentCaseInsensitiveStringsMap h = new FluentCaseInsensitiveStringsMap(); - h.add("Content-Type", "application/x-www-form-urlencoded"); - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < 5; i++) { - sb.append("param_"); - sb.append(i); - sb.append("=value_"); - sb.append(i); - sb.append("&"); + Future future = client.preparePost(getTargetUrl()).setHeaders(h).setBody(sb.toString()).execute(new AsyncCompletionHandlerAdapter()); + + Response response = future.get(); + Assert.assertNotNull(response); + assertEquals(response.getStatusCode(), 200); + } finally { + client.close(); } - sb.deleteCharAt(sb.length() - 1); + } - Future future = c.preparePost(getTargetUrl()).setHeaders(h).setBody(sb.toString()).execute(new AsyncCompletionHandlerAdapter()); + @Test(groups = { "standalone", "default_provider", "async" }) + public void asyncDoPostListenerBytesTest() throws Throwable { + AsyncHttpClient client = getAsyncHttpClient(null); + try { + FluentCaseInsensitiveStringsMap h = new FluentCaseInsensitiveStringsMap(); + h.add("Content-Type", "application/x-www-form-urlencoded"); + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < 5; i++) { + sb.append("param_"); + sb.append(i); + sb.append("=value_"); + sb.append(i); + sb.append("&"); + } + sb.deleteCharAt(sb.length() - 1); - Response response = future.get(); - Assert.assertNotNull(response); - assertEquals(response.getStatusCode(), 200); - c.close(); + final CountDownLatch l = new CountDownLatch(1); - } + client.preparePost(getTargetUrl()).setHeaders(h).setBody(sb.toString()).execute(new AsyncCompletionHandlerAdapter() { + @Override + public Response onCompleted(Response response) throws Exception { + try { + assertEquals(response.getStatusCode(), 200); + } finally { + l.countDown(); + } + return response; + } + }); - @Test(groups = {"standalone", "default_provider", "async"}) - public void asyncDoPostListenerBytesTest() throws Throwable { - AsyncHttpClient c = getAsyncHttpClient(null); - FluentCaseInsensitiveStringsMap h = new FluentCaseInsensitiveStringsMap(); - h.add("Content-Type", "application/x-www-form-urlencoded"); - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < 5; i++) { - sb.append("param_"); - sb.append(i); - sb.append("=value_"); - sb.append(i); - sb.append("&"); + if (!l.await(TIMEOUT, TimeUnit.SECONDS)) { + Assert.fail("Latch time out"); + } + } finally { + client.close(); } - sb.deleteCharAt(sb.length() - 1); - - final CountDownLatch l = new CountDownLatch(1); + } - c.preparePost(getTargetUrl()).setHeaders(h).setBody(sb.toString()).execute(new AsyncCompletionHandlerAdapter() { - @Override - public Response onCompleted(Response response) throws Exception { + @Test(groups = { "standalone", "default_provider", "async" }) + public void asyncConnectInvalidFuture() throws Throwable { + AsyncHttpClient client = getAsyncHttpClient(null); + try { + int dummyPort = findFreePort(); + final AtomicInteger count = new AtomicInteger(); + for (int i = 0; i < 20; i++) { try { - assertEquals(response.getStatusCode(), 200); - } finally { - l.countDown(); + Response response = client.preparePost(String.format("http://127.0.0.1:%d/", dummyPort)).execute(new AsyncCompletionHandlerAdapter() { + /* @Override */ + public void onThrowable(Throwable t) { + count.incrementAndGet(); + } + }).get(); + assertNull(response, "Should have thrown ExecutionException"); + } catch (ExecutionException ex) { + Throwable cause = ex.getCause(); + if (!(cause instanceof ConnectException)) { + fail("Should have been caused by ConnectException, not by " + cause.getClass().getName()); + } } - return response; } - }); + assertEquals(count.get(), 20); + } finally { + client.close(); + } + } - if (!l.await(TIMEOUT, TimeUnit.SECONDS)) { - Assert.fail("Latch time out"); + @Test(groups = { "standalone", "default_provider", "async" }) + public void asyncConnectInvalidPortFuture() throws Throwable { + AsyncHttpClient client = getAsyncHttpClient(null); + try { + int dummyPort = findFreePort(); + try { + Response response = client.preparePost(String.format("http://127.0.0.1:%d/", dummyPort)).execute(new AsyncCompletionHandlerAdapter() { + /* @Override */ + public void onThrowable(Throwable t) { + t.printStackTrace(); + } + }).get(); + assertNull(response, "Should have thrown ExecutionException"); + } catch (ExecutionException ex) { + Throwable cause = ex.getCause(); + if (!(cause instanceof ConnectException)) { + fail("Should have been caused by ConnectException, not by " + cause.getClass().getName()); + } + } + } finally { + client.close(); } - c.close(); } - @Test(groups = {"standalone", "default_provider", "async"}) - public void asyncConnectInvalidFuture() throws Throwable { + @Test(groups = { "standalone", "default_provider", "async" }) + public void asyncConnectInvalidPort() throws Throwable { + AsyncHttpClient client = getAsyncHttpClient(null); + try { + // pick a random unused local port + int port = findFreePort(); - int dummyPort = findFreePort(); - AsyncHttpClient c = getAsyncHttpClient(null); - final AtomicInteger count = new AtomicInteger(); - for (int i = 0; i < 20; i++) { try { - Response response = c.preparePost(String.format("http://127.0.0.1:%d/", dummyPort)).execute(new AsyncCompletionHandlerAdapter() { + Response response = client.preparePost(String.format("http://127.0.0.1:%d/", port)).execute(new AsyncCompletionHandlerAdapter() { /* @Override */ public void onThrowable(Throwable t) { - count.incrementAndGet(); + t.printStackTrace(); } }).get(); - assertNull(response, "Should have thrown ExecutionException"); + assertNull(response, "No ExecutionException was thrown"); } catch (ExecutionException ex) { - Throwable cause = ex.getCause(); - if (!(cause instanceof ConnectException)) { - fail("Should have been caused by ConnectException, not by " + cause.getClass().getName()); - } + assertEquals(ex.getCause().getClass(), ConnectException.class); } + } finally { + client.close(); } - assertEquals(count.get(), 20); - c.close(); } - @Test(groups = {"standalone", "default_provider", "async"}) - public void asyncConnectInvalidPortFuture() throws Throwable { - - int dummyPort = findFreePort(); - AsyncHttpClient c = getAsyncHttpClient(null); + @Test(groups = { "standalone", "default_provider", "async" }) + public void asyncConnectInvalidHandlerPort() throws Throwable { + AsyncHttpClient client = getAsyncHttpClient(null); try { - Response response = c.preparePost(String.format("http://127.0.0.1:%d/", dummyPort)).execute(new AsyncCompletionHandlerAdapter() { + final CountDownLatch l = new CountDownLatch(1); + int port = findFreePort(); + + client.prepareGet(String.format("http://127.0.0.1:%d/", port)).execute(new AsyncCompletionHandlerAdapter() { /* @Override */ public void onThrowable(Throwable t) { - t.printStackTrace(); + try { + assertEquals(t.getClass(), ConnectException.class); + } finally { + l.countDown(); + } } - }).get(); - assertNull(response, "Should have thrown ExecutionException"); - } catch (ExecutionException ex) { - Throwable cause = ex.getCause(); - if (!(cause instanceof ConnectException)) { - fail("Should have been caused by ConnectException, not by " + cause.getClass().getName()); + }); + + if (!l.await(TIMEOUT, TimeUnit.SECONDS)) { + Assert.fail("Timed out"); } + } finally { + client.close(); } - c.close(); } - @Test(groups = {"standalone", "default_provider", "async"}) - public void asyncConnectInvalidPort() throws Throwable { - AsyncHttpClient c = getAsyncHttpClient(null); - - // pick a random unused local port - int port = findFreePort(); - + @Test(groups = { "online", "default_provider", "async" }) + public void asyncConnectInvalidHandlerHost() throws Throwable { + AsyncHttpClient client = getAsyncHttpClient(null); try { - Response response = c.preparePost(String.format("http://127.0.0.1:%d/", port)).execute(new AsyncCompletionHandlerAdapter() { + final CountDownLatch l = new CountDownLatch(1); + + client.prepareGet("http://null.apache.org:9999/").execute(new AsyncCompletionHandlerAdapter() { /* @Override */ public void onThrowable(Throwable t) { - t.printStackTrace(); + if (t != null) { + if (t.getClass().equals(ConnectException.class)) { + l.countDown(); + } else if (t.getClass().equals(UnresolvedAddressException.class)) { + l.countDown(); + } + } } - }).get(); - assertNull(response, "No ExecutionException was thrown"); - } catch (ExecutionException ex) { - assertEquals(ex.getCause().getClass(), ConnectException.class); - } - c.close(); - } - - @Test(groups = {"standalone", "default_provider", "async"}) - public void asyncConnectInvalidHandlerPort() throws Throwable { - AsyncHttpClient c = getAsyncHttpClient(null); - final CountDownLatch l = new CountDownLatch(1); - int port = findFreePort(); + }); - c.prepareGet(String.format("http://127.0.0.1:%d/", port)).execute(new AsyncCompletionHandlerAdapter() { - /* @Override */ - public void onThrowable(Throwable t) { - try { - assertEquals(t.getClass(), ConnectException.class); - } finally { - l.countDown(); - } + if (!l.await(TIMEOUT, TimeUnit.SECONDS)) { + Assert.fail("Timed out"); } - }); - - if (!l.await(TIMEOUT, TimeUnit.SECONDS)) { - Assert.fail("Timed out"); + } finally { + client.close(); } - c.close(); } - @Test(groups = {"online", "default_provider", "async"}) - public void asyncConnectInvalidHandlerHost() throws Throwable { - AsyncHttpClient c = getAsyncHttpClient(null); - final CountDownLatch l = new CountDownLatch(1); - - c.prepareGet("http://null.apache.org:9999/").execute(new AsyncCompletionHandlerAdapter() { - /* @Override */ - public void onThrowable(Throwable t) { - if (t != null) { - if (t.getClass().equals(ConnectException.class)) { - l.countDown(); - } else if (t.getClass().equals(UnresolvedAddressException.class)) { - l.countDown(); + @Test(groups = { "standalone", "default_provider", "async" }) + public void asyncConnectInvalidFuturePort() throws Throwable { + AsyncHttpClient client = getAsyncHttpClient(null); + try { + final AtomicBoolean called = new AtomicBoolean(false); + final AtomicBoolean rightCause = new AtomicBoolean(false); + // pick a random unused local port + int port = findFreePort(); + + try { + Response response = client.prepareGet(String.format("http://127.0.0.1:%d/", port)).execute(new AsyncCompletionHandlerAdapter() { + @Override + public void onThrowable(Throwable t) { + called.set(true); + if (t instanceof ConnectException) { + rightCause.set(true); + } } - } + }).get(); + assertNull(response, "No ExecutionException was thrown"); + } catch (ExecutionException ex) { + assertEquals(ex.getCause().getClass(), ConnectException.class); } - }); - - if (!l.await(TIMEOUT, TimeUnit.SECONDS)) { - Assert.fail("Timed out"); + assertTrue(called.get(), "onThrowable should get called."); + assertTrue(rightCause.get(), "onThrowable should get called with ConnectionException"); + } finally { + client.close(); } - c.close(); } - - @Test(groups = {"standalone", "default_provider", "async"}) - public void asyncConnectInvalidFuturePort() throws Throwable { - AsyncHttpClient c = getAsyncHttpClient(null); - - final AtomicBoolean called = new AtomicBoolean(false); - final AtomicBoolean rightCause = new AtomicBoolean(false); - // pick a random unused local port - int port = findFreePort(); - + @Test(groups = { "standalone", "default_provider", "async" }) + public void asyncContentLenghtGETTest() throws Throwable { + AsyncHttpClient client = getAsyncHttpClient(null); try { - Response response = c.prepareGet(String.format("http://127.0.0.1:%d/", port)).execute(new AsyncCompletionHandlerAdapter() { + Response response = client.prepareGet(getTargetUrl()).execute(new AsyncCompletionHandlerAdapter() { + @Override public void onThrowable(Throwable t) { - called.set(true); - if (t instanceof ConnectException) { - rightCause.set(true); - } + Assert.fail("Unexpected exception", t); } }).get(); - assertNull(response, "No ExecutionException was thrown"); - } catch (ExecutionException ex) { - assertEquals(ex.getCause().getClass(), ConnectException.class); - } - assertTrue(called.get(), "onThrowable should get called."); - assertTrue(rightCause.get(), "onThrowable should get called with ConnectionException"); - c.close(); - } - - @Test(groups = {"standalone", "default_provider", "async"}) - public void asyncContentLenghtGETTest() throws Throwable { - AsyncHttpClient c = getAsyncHttpClient(null); - Response response = c.prepareGet(getTargetUrl()).execute(new AsyncCompletionHandlerAdapter() { - - @Override - public void onThrowable(Throwable t) { - Assert.fail("Unexpected exception", t); - } - }).get(); - Assert.assertNotNull(response); - assertEquals(response.getStatusCode(), 200); - c.close(); + Assert.assertNotNull(response); + assertEquals(response.getStatusCode(), 200); + } finally { + client.close(); + } } - @Test(groups = {"standalone", "default_provider", "async"}) + @Test(groups = { "standalone", "default_provider", "async" }) public void asyncResponseBodyTooLarge() throws Throwable { - AsyncHttpClient c = getAsyncHttpClient(null); - Response response = c.preparePost(getTargetUrl()).setBody("0123456789").execute(new AsyncCompletionHandlerAdapter() { + AsyncHttpClient client = getAsyncHttpClient(null); + try { + Response response = client.preparePost(getTargetUrl()).setBody("0123456789").execute(new AsyncCompletionHandlerAdapter() { - @Override - public void onThrowable(Throwable t) { - Assert.fail("Unexpected exception", t); - } - }).get(); + @Override + public void onThrowable(Throwable t) { + Assert.fail("Unexpected exception", t); + } + }).get(); - Assert.assertNotNull(response.getResponseBodyExcerpt(Integer.MAX_VALUE)); - c.close(); + Assert.assertNotNull(response.getResponseBodyExcerpt(Integer.MAX_VALUE)); + } finally { + client.close(); + } } - @Test(groups = {"standalone", "default_provider", "async"}) + @Test(groups = { "standalone", "default_provider", "async" }) public void asyncResponseEmptyBody() throws Throwable { - AsyncHttpClient c = getAsyncHttpClient(null); - Response response = c.prepareGet(getTargetUrl()).execute(new AsyncCompletionHandlerAdapter() { + AsyncHttpClient client = getAsyncHttpClient(null); + try { + Response response = client.prepareGet(getTargetUrl()).execute(new AsyncCompletionHandlerAdapter() { - @Override - public void onThrowable(Throwable t) { - Assert.fail("Unexpected exception", t); - } - }).get(); + @Override + public void onThrowable(Throwable t) { + Assert.fail("Unexpected exception", t); + } + }).get(); - assertEquals(response.getResponseBody(),""); - c.close(); + assertEquals(response.getResponseBody(), ""); + } finally { + client.close(); + } } - @Test(groups = {"standalone", "default_provider", "asyncAPI"}) + @Test(groups = { "standalone", "default_provider", "asyncAPI" }) public void asyncAPIContentLenghtGETTest() throws Throwable { AsyncHttpClient client = getAsyncHttpClient(null); + try { + // Use a l in case the assert fail + final CountDownLatch l = new CountDownLatch(1); - // Use a l in case the assert fail - final CountDownLatch l = new CountDownLatch(1); + client.prepareGet(getTargetUrl()).execute(new AsyncCompletionHandlerAdapter() { - client.prepareGet(getTargetUrl()).execute(new AsyncCompletionHandlerAdapter() { + @Override + public Response onCompleted(Response response) throws Exception { + try { + assertEquals(response.getStatusCode(), 200); + } finally { + l.countDown(); + } + return response; + } - @Override - public Response onCompleted(Response response) throws Exception { - try { - assertEquals(response.getStatusCode(), 200); - } finally { - l.countDown(); + @Override + public void onThrowable(Throwable t) { } - return response; - } + }); - @Override - public void onThrowable(Throwable t) { + if (!l.await(TIMEOUT, TimeUnit.SECONDS)) { + Assert.fail("Timed out"); } - }); - - - if (!l.await(TIMEOUT, TimeUnit.SECONDS)) { - Assert.fail("Timed out"); + } finally { + client.close(); } - client.close(); } - @Test(groups = {"standalone", "default_provider", "asyncAPI"}) + @Test(groups = { "standalone", "default_provider", "asyncAPI" }) public void asyncAPIHandlerExceptionTest() throws Throwable { AsyncHttpClient client = getAsyncHttpClient(null); + try { + // Use a l in case the assert fail + final CountDownLatch l = new CountDownLatch(1); - // Use a l in case the assert fail - final CountDownLatch l = new CountDownLatch(1); - - client.prepareGet(getTargetUrl()).execute(new AsyncCompletionHandlerAdapter() { - @Override - public Response onCompleted(Response response) throws Exception { - throw new IllegalStateException("FOO"); - } + client.prepareGet(getTargetUrl()).execute(new AsyncCompletionHandlerAdapter() { + @Override + public Response onCompleted(Response response) throws Exception { + throw new IllegalStateException("FOO"); + } - @Override - public void onThrowable(Throwable t) { - try { - if (t.getMessage() != null) { - assertEquals(t.getMessage(), "FOO"); + @Override + public void onThrowable(Throwable t) { + try { + if (t.getMessage() != null) { + assertEquals(t.getMessage(), "FOO"); + } + } finally { + l.countDown(); } - } finally { - l.countDown(); } - } - }); - + }); - if (!l.await(TIMEOUT, TimeUnit.SECONDS)) { - Assert.fail("Timed out"); + if (!l.await(TIMEOUT, TimeUnit.SECONDS)) { + Assert.fail("Timed out"); + } + } finally { + client.close(); } - client.close(); - } - @Test(groups = {"standalone", "default_provider", "async"}) + @Test(groups = { "standalone", "default_provider", "async" }) public void asyncDoGetDelayHandlerTest() throws Throwable { - FluentCaseInsensitiveStringsMap h = new FluentCaseInsensitiveStringsMap(); - h.add("LockThread", "true"); AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeoutInMs(5 * 1000).build()); + try { + FluentCaseInsensitiveStringsMap h = new FluentCaseInsensitiveStringsMap(); + h.add("LockThread", "true"); - // Use a l in case the assert fail - final CountDownLatch l = new CountDownLatch(1); + // Use a l in case the assert fail + final CountDownLatch l = new CountDownLatch(1); - client.prepareGet(getTargetUrl()).setHeaders(h).execute(new AsyncCompletionHandlerAdapter() { + client.prepareGet(getTargetUrl()).setHeaders(h).execute(new AsyncCompletionHandlerAdapter() { - @Override - public Response onCompleted(Response response) throws Exception { - try { - Assert.fail("Must not receive a response"); - } finally { - l.countDown(); + @Override + public Response onCompleted(Response response) throws Exception { + try { + Assert.fail("Must not receive a response"); + } finally { + l.countDown(); + } + return response; } - return response; - } - @Override - public void onThrowable(Throwable t) { - try { - if (t instanceof TimeoutException) { - Assert.assertTrue(true); - } else { - Assert.fail("Unexpected exception", t); + @Override + public void onThrowable(Throwable t) { + try { + if (t instanceof TimeoutException) { + Assert.assertTrue(true); + } else { + Assert.fail("Unexpected exception", t); + } + } finally { + l.countDown(); } - } finally { - l.countDown(); } - } - }); + }); - if (!l.await(TIMEOUT, TimeUnit.SECONDS)) { - Assert.fail("Timed out"); + if (!l.await(TIMEOUT, TimeUnit.SECONDS)) { + Assert.fail("Timed out"); + } + } finally { + client.close(); } - client.close(); - } - @Test(groups = {"standalone", "default_provider", "async"}) + @Test(groups = { "standalone", "default_provider", "async" }) public void asyncDoGetQueryStringTest() throws Throwable { AsyncHttpClient client = getAsyncHttpClient(null); + try { + // Use a l in case the assert fail + final CountDownLatch l = new CountDownLatch(1); - // Use a l in case the assert fail - final CountDownLatch l = new CountDownLatch(1); - - AsyncCompletionHandler handler = new AsyncCompletionHandlerAdapter() { + AsyncCompletionHandler handler = new AsyncCompletionHandlerAdapter() { - @Override - public Response onCompleted(Response response) throws Exception { - try { - Assert.assertTrue(response.getHeader("X-pathInfo") != null); - Assert.assertTrue(response.getHeader("X-queryString") != null); - } finally { - l.countDown(); + @Override + public Response onCompleted(Response response) throws Exception { + try { + Assert.assertTrue(response.getHeader("X-pathInfo") != null); + Assert.assertTrue(response.getHeader("X-queryString") != null); + } finally { + l.countDown(); + } + return response; } - return response; - } - }; + }; - Request req = new RequestBuilder("GET") - .setUrl(getTargetUrl() + "?foo=bar").build(); + Request req = new RequestBuilder("GET").setUrl(getTargetUrl() + "?foo=bar").build(); - client.executeRequest(req, handler).get(); + client.executeRequest(req, handler).get(); - if (!l.await(TIMEOUT, TimeUnit.SECONDS)) { - Assert.fail("Timed out"); + if (!l.await(TIMEOUT, TimeUnit.SECONDS)) { + Assert.fail("Timed out"); + } + } finally { + client.close(); } - client.close(); } - @Test(groups = {"standalone", "default_provider", "async"}) + @Test(groups = { "standalone", "default_provider", "async" }) public void asyncDoGetKeepAliveHandlerTest() throws Throwable { AsyncHttpClient client = getAsyncHttpClient(null); + try { + // Use a l in case the assert fail + final CountDownLatch l = new CountDownLatch(2); - // Use a l in case the assert fail - final CountDownLatch l = new CountDownLatch(2); + AsyncCompletionHandler handler = new AsyncCompletionHandlerAdapter() { - AsyncCompletionHandler handler = new AsyncCompletionHandlerAdapter() { + String remoteAddr = null; - String remoteAddr = null; + @Override + public Response onCompleted(Response response) throws Exception { + assertEquals(response.getStatusCode(), 200); + if (remoteAddr == null) { + remoteAddr = response.getHeader("X-KEEP-ALIVE"); + l.countDown(); + } else { + assertEquals(response.getHeader("X-KEEP-ALIVE"), remoteAddr); + l.countDown(); + } - @Override - public Response onCompleted(Response response) throws Exception { - assertEquals(response.getStatusCode(), 200); - if (remoteAddr == null) { - remoteAddr = response.getHeader("X-KEEP-ALIVE"); - l.countDown(); - } else { - assertEquals(response.getHeader("X-KEEP-ALIVE"), remoteAddr); - l.countDown(); + return response; } + }; - return response; - } - }; - - client.prepareGet(getTargetUrl()).execute(handler).get(); - client.prepareGet(getTargetUrl()).execute(handler); + client.prepareGet(getTargetUrl()).execute(handler).get(); + client.prepareGet(getTargetUrl()).execute(handler); - if (!l.await(TIMEOUT, TimeUnit.SECONDS)) { - Assert.fail("Timed out"); + if (!l.await(TIMEOUT, TimeUnit.SECONDS)) { + Assert.fail("Timed out"); + } + } finally { + client.close(); } - client.close(); } - @Test(groups = {"online", "default_provider", "async"}) + @Test(groups = { "online", "default_provider", "async" }) public void asyncDoGetMaxRedirectTest() throws Throwable { AsyncHttpClient client = getAsyncHttpClient(new Builder().setMaximumNumberOfRedirects(0).setFollowRedirects(true).build()); + try { + // Use a l in case the assert fail + final CountDownLatch l = new CountDownLatch(1); - // Use a l in case the assert fail - final CountDownLatch l = new CountDownLatch(1); - - AsyncCompletionHandler handler = new AsyncCompletionHandlerAdapter() { + AsyncCompletionHandler handler = new AsyncCompletionHandlerAdapter() { - @Override - public Response onCompleted(Response response) throws Exception { - Assert.fail("Should not be here"); - return response; - } + @Override + public Response onCompleted(Response response) throws Exception { + Assert.fail("Should not be here"); + return response; + } - @Override - public void onThrowable(Throwable t) { - t.printStackTrace(); - try { - assertEquals(t.getClass(), MaxRedirectException.class); - } finally { - l.countDown(); + @Override + public void onThrowable(Throwable t) { + t.printStackTrace(); + try { + assertEquals(t.getClass(), MaxRedirectException.class); + } finally { + l.countDown(); + } } - } - }; + }; - client.prepareGet("http://google.com/").execute(handler); + client.prepareGet("http://google.com/").execute(handler); - if (!l.await(TIMEOUT, TimeUnit.SECONDS)) { - Assert.fail("Timed out"); + if (!l.await(TIMEOUT, TimeUnit.SECONDS)) { + Assert.fail("Timed out"); + } + } finally { + client.close(); } - client.close(); } - @Test(groups = {"online", "default_provider", "async"}) + @Test(groups = { "online", "default_provider", "async" }) public void asyncDoGetNestedTest() throws Throwable { final AsyncHttpClient client = getAsyncHttpClient(new Builder().build()); + try { + // Use a l in case the assert fail + final CountDownLatch l = new CountDownLatch(2); - // Use a l in case the assert fail - final CountDownLatch l = new CountDownLatch(2); - - final AsyncCompletionHandlerAdapter handler = new AsyncCompletionHandlerAdapter() { + final AsyncCompletionHandlerAdapter handler = new AsyncCompletionHandlerAdapter() { - private final static int MAX_NESTED = 2; + private final static int MAX_NESTED = 2; - private AtomicInteger nestedCount = new AtomicInteger(0); + private AtomicInteger nestedCount = new AtomicInteger(0); - @Override - public Response onCompleted(Response response) throws Exception { - try { - if (nestedCount.getAndIncrement() < MAX_NESTED) { - System.out.println("Executing a nested request: " + nestedCount); - client.prepareGet("http://google.com/").execute(this); + @Override + public Response onCompleted(Response response) throws Exception { + try { + if (nestedCount.getAndIncrement() < MAX_NESTED) { + System.out.println("Executing a nested request: " + nestedCount); + client.prepareGet("http://google.com/").execute(this); + } + } finally { + l.countDown(); } - } finally { - l.countDown(); + return response; } - return response; - } - - @Override - public void onThrowable(Throwable t) { - t.printStackTrace(); - } - }; + @Override + public void onThrowable(Throwable t) { + t.printStackTrace(); + } + }; - client.prepareGet("http://www.google.com/").execute(handler); + client.prepareGet("http://www.google.com/").execute(handler); - if (!l.await(TIMEOUT, TimeUnit.SECONDS)) { - Assert.fail("Timed out"); + if (!l.await(TIMEOUT, TimeUnit.SECONDS)) { + Assert.fail("Timed out"); + } + } finally { + client.close(); } - client.close(); } - @Test(groups = {"online", "default_provider", "async"}) + @Test(groups = { "online", "default_provider", "async" }) public void asyncDoGetStreamAndBodyTest() throws Throwable { - final AsyncHttpClient client = getAsyncHttpClient(new Builder().build()); - Response r = client.prepareGet("http://www.google.com/").execute().get(); - - r.getResponseBody(); - r.getResponseBodyAsStream(); + AsyncHttpClient client = getAsyncHttpClient(new Builder().build()); + try { + Response r = client.prepareGet("http://www.google.com/").execute().get(); - client.close(); + r.getResponseBody(); + r.getResponseBodyAsStream(); + } finally { + client.close(); + } } - @Test(groups = {"online", "default_provider", "async"}) + @Test(groups = { "online", "default_provider", "async" }) public void asyncUrlWithoutPathTest() throws Throwable { - final AsyncHttpClient client = getAsyncHttpClient(new Builder().build()); - Response r = client.prepareGet("http://www.google.com/").execute().get(); - - r.getResponseBody(); - r.getResponseBodyAsStream(); + AsyncHttpClient client = getAsyncHttpClient(new Builder().build()); + try { + Response r = client.prepareGet("http://www.google.com/").execute().get(); - client.close(); + r.getResponseBody(); + r.getResponseBodyAsStream(); + } finally { + client.close(); + } } - @Test(groups = {"default_provider", "async"}) + @Test(groups = { "default_provider", "async" }) public void optionsTest() throws Throwable { - final AsyncHttpClient client = getAsyncHttpClient(new Builder().build()); - Response r = client.prepareOptions(getTargetUrl()).execute().get(); - - assertEquals(r.getStatusCode(), 200); - assertEquals(r.getHeader("Allow"), "GET,HEAD,POST,OPTIONS,TRACE"); + AsyncHttpClient client = getAsyncHttpClient(new Builder().build()); + try { + Response r = client.prepareOptions(getTargetUrl()).execute().get(); - client.close(); + assertEquals(r.getStatusCode(), 200); + assertEquals(r.getHeader("Allow"), "GET,HEAD,POST,OPTIONS,TRACE"); + } finally { + client.close(); + } } - @Test(groups = {"online", "default_provider"}) + @Test(groups = { "online", "default_provider" }) public void testAwsS3() throws Exception { - final AsyncHttpClient c = getAsyncHttpClient(new Builder().build()); - Response response = c.prepareGet("http://test.s3.amazonaws.com/").execute().get(); - if (!isNonEmpty(response.getResponseBody())) { - fail("No response Body"); - } else { - assertEquals(response.getStatusCode(), 403); + AsyncHttpClient client = getAsyncHttpClient(new Builder().build()); + try { + Response response = client.prepareGet("http://test.s3.amazonaws.com/").execute().get(); + if (!isNonEmpty(response.getResponseBody())) { + fail("No response Body"); + } else { + assertEquals(response.getStatusCode(), 403); + } + } finally { + client.close(); } - c.close(); } - @Test(groups = {"online", "default_provider"}) + @Test(groups = { "online", "default_provider" }) public void testAsyncHttpProviderConfig() throws Exception { - final AsyncHttpClient c = getAsyncHttpClient(new Builder().setAsyncHttpClientProviderConfig(getProviderConfig()).build()); - Response response = c.prepareGet("http://test.s3.amazonaws.com/").execute().get(); - if (!isNonEmpty(response.getResponseBody())) { - fail("No response Body"); - } else { - assertEquals(response.getStatusCode(), 403); + AsyncHttpClient client = getAsyncHttpClient(new Builder().setAsyncHttpClientProviderConfig(getProviderConfig()).build()); + try { + Response response = client.prepareGet("http://test.s3.amazonaws.com/").execute().get(); + if (!isNonEmpty(response.getResponseBody())) { + fail("No response Body"); + } else { + assertEquals(response.getStatusCode(), 403); + } + } finally { + client.close(); } - c.close(); } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void idleRequestTimeoutTest() throws Exception { - AsyncHttpClient c = getAsyncHttpClient( - new AsyncHttpClientConfig.Builder().setIdleConnectionInPoolTimeoutInMs(5000).setRequestTimeoutInMs(10000).build()); - FluentCaseInsensitiveStringsMap h = new FluentCaseInsensitiveStringsMap(); - h.add("Content-Type", "application/x-www-form-urlencoded"); - h.add("LockThread", "true"); - - long t1 = System.currentTimeMillis(); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setIdleConnectionInPoolTimeoutInMs(5000).setRequestTimeoutInMs(10000).build()); try { - c.prepareGet(getTargetUrl()).setHeaders(h).setUrl(getTargetUrl()).execute(new AsyncHandlerAdapter() { + FluentCaseInsensitiveStringsMap h = new FluentCaseInsensitiveStringsMap(); + h.add("Content-Type", "application/x-www-form-urlencoded"); + h.add("LockThread", "true"); - /* @Override */ - public void onThrowable(Throwable t) { -// t.printStackTrace(); - } + long t1 = System.currentTimeMillis(); + try { + client.prepareGet(getTargetUrl()).setHeaders(h).setUrl(getTargetUrl()).execute(new AsyncHandlerAdapter() { - }).get(); - Assert.fail(); - } catch (Throwable ex) { - final long elapsedTime = System.currentTimeMillis() - t1; - System.out.println("EXPIRED: " + (elapsedTime)); - Assert.assertNotNull(ex.getCause()); - Assert.assertTrue(elapsedTime >= 10000 && elapsedTime <= 25000); + /* @Override */ + public void onThrowable(Throwable t) { + // t.printStackTrace(); + } + + }).get(); + Assert.fail(); + } catch (Throwable ex) { + final long elapsedTime = System.currentTimeMillis() - t1; + System.out.println("EXPIRED: " + (elapsedTime)); + Assert.assertNotNull(ex.getCause()); + Assert.assertTrue(elapsedTime >= 10000 && elapsedTime <= 25000); + } + } finally { + client.close(); } - c.close(); } - @Test(groups = {"standalone", "default_provider", "async"}) + @Test(groups = { "standalone", "default_provider", "async" }) public void asyncDoPostCancelTest() throws Throwable { - - AsyncHttpClient c = getAsyncHttpClient(null); - FluentCaseInsensitiveStringsMap h = new FluentCaseInsensitiveStringsMap(); - h.add("Content-Type", "application/x-www-form-urlencoded"); - h.add("LockThread", "true"); - StringBuilder sb = new StringBuilder(); - sb.append("LockThread=true"); - - final AtomicReference ex = new AtomicReference(); - ex.set(null); + AsyncHttpClient client = getAsyncHttpClient(null); try { - Future future = c.preparePost(getTargetUrl()).setHeaders(h).setBody(sb.toString()).execute(new AsyncCompletionHandlerAdapter() { + FluentCaseInsensitiveStringsMap h = new FluentCaseInsensitiveStringsMap(); + h.add("Content-Type", "application/x-www-form-urlencoded"); + h.add("LockThread", "true"); + StringBuilder sb = new StringBuilder(); + sb.append("LockThread=true"); + + final AtomicReference ex = new AtomicReference(); + ex.set(null); + try { + Future future = client.preparePost(getTargetUrl()).setHeaders(h).setBody(sb.toString()).execute(new AsyncCompletionHandlerAdapter() { - @Override - public void onThrowable(Throwable t) { - if (t instanceof CancellationException) { - ex.set((CancellationException)t); + @Override + public void onThrowable(Throwable t) { + if (t instanceof CancellationException) { + ex.set((CancellationException) t); + } + t.printStackTrace(); } - t.printStackTrace(); - } - - }); - Thread.sleep(1000); - future.cancel(true); - } catch (IllegalStateException ise) { - fail(); + }); + + Thread.sleep(1000); + future.cancel(true); + } catch (IllegalStateException ise) { + fail(); + } + Assert.assertNotNull(ex.get()); + } finally { + client.close(); } - Assert.assertNotNull(ex.get()); - c.close(); } - @Test(groups = {"standalone", "default_provider"}, expectedExceptions = IllegalArgumentException.class) + @Test(groups = { "standalone", "default_provider" }, expectedExceptions = IllegalArgumentException.class) public void getShouldNotAllowBody() throws IllegalArgumentException, IOException { - AsyncHttpClient c = getAsyncHttpClient(null); + AsyncHttpClient client = getAsyncHttpClient(null); try { - AsyncHttpClient.BoundRequestBuilder builder = c.prepareGet(getTargetUrl()); + AsyncHttpClient.BoundRequestBuilder builder = client.prepareGet(getTargetUrl()); builder.setBody("Boo!"); builder.execute(); } finally { - c.close(); + client.close(); } } - @Test(groups = {"standalone", "default_provider"}, expectedExceptions = IllegalArgumentException.class) + @Test(groups = { "standalone", "default_provider" }, expectedExceptions = IllegalArgumentException.class) public void headShouldNotAllowBody() throws IllegalArgumentException, IOException { - AsyncHttpClient c = getAsyncHttpClient(null); + AsyncHttpClient client = getAsyncHttpClient(null); try { - AsyncHttpClient.BoundRequestBuilder builder = c.prepareHead(getTargetUrl()); + AsyncHttpClient.BoundRequestBuilder builder = client.prepareHead(getTargetUrl()); builder.setBody("Boo!"); builder.execute(); } finally { - c.close(); + client.close(); } } @@ -1594,45 +1677,55 @@ protected String getBrokenTargetUrl() { return String.format("http:127.0.0.1:%d/foo/test", port1); } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void invalidUri() throws Exception { - AsyncHttpClient c = getAsyncHttpClient(null); - AsyncHttpClient.BoundRequestBuilder builder = c.prepareGet(getBrokenTargetUrl()); - Response r = c.executeRequest(builder.build()).get(); - assertEquals(200, r.getStatusCode()); - c.close(); + AsyncHttpClient client = getAsyncHttpClient(null); + try { + AsyncHttpClient.BoundRequestBuilder builder = client.prepareGet(getBrokenTargetUrl()); + Response r = client.executeRequest(builder.build()).get(); + assertEquals(200, r.getStatusCode()); + } finally { + client.close(); + } } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void asyncHttpClientConfigBeanTest() throws Exception { - AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfigBean().setUserAgent("test")); - AsyncHttpClient.BoundRequestBuilder builder = c.prepareGet(getTargetUrl()); - Response r = c.executeRequest(builder.build()).get(); - assertEquals(200, r.getStatusCode()); - c.close(); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfigBean().setUserAgent("test")); + try { + AsyncHttpClient.BoundRequestBuilder builder = client.prepareGet(getTargetUrl()); + Response r = client.executeRequest(builder.build()).get(); + assertEquals(200, r.getStatusCode()); + } finally { + client.close(); + } } - @Test(groups = {"default_provider", "async"}) + @Test(groups = { "default_provider", "async" }) public void bodyAsByteTest() throws Throwable { - final AsyncHttpClient client = getAsyncHttpClient(new Builder().build()); - Response r = client.prepareGet(getTargetUrl()).execute().get(); - - assertEquals(r.getStatusCode(), 200); - assertEquals(r.getResponseBodyAsBytes(), new byte[]{}); + AsyncHttpClient client = getAsyncHttpClient(new Builder().build()); + try { + Response r = client.prepareGet(getTargetUrl()).execute().get(); - client.close(); + assertEquals(r.getStatusCode(), 200); + assertEquals(r.getResponseBodyAsBytes(), new byte[] {}); + } finally { + client.close(); + } } - @Test(groups = {"default_provider", "async"}) + @Test(groups = { "default_provider", "async" }) public void mirrorByteTest() throws Throwable { - final AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().build()); - Response r = client.preparePost(getTargetUrl()).setBody("MIRROR").execute().get(); - - assertEquals(r.getStatusCode(), 200); - assertEquals(new String(r.getResponseBodyAsBytes(), "UTF-8"), "MIRROR"); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().build()); + try { + Response r = client.preparePost(getTargetUrl()).setBody("MIRROR").execute().get(); - client.close(); + assertEquals(r.getStatusCode(), 200); + assertEquals(new String(r.getResponseBodyAsBytes(), "UTF-8"), "MIRROR"); + } finally { + client.close(); + } } - protected abstract AsyncHttpProviderConfig getProviderConfig(); + protected abstract AsyncHttpProviderConfig getProviderConfig(); } diff --git a/src/test/java/com/ning/http/client/async/AsyncStreamHandlerTest.java b/src/test/java/com/ning/http/client/async/AsyncStreamHandlerTest.java index 3e58bc8871..00c1f00726 100644 --- a/src/test/java/com/ning/http/client/async/AsyncStreamHandlerTest.java +++ b/src/test/java/com/ning/http/client/async/AsyncStreamHandlerTest.java @@ -40,516 +40,543 @@ public abstract class AsyncStreamHandlerTest extends AbstractBasicTest { private final static String RESPONSE = "param_1_"; private final static String UTF8 = "text/html;charset=utf-8"; - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void asyncStreamGETTest() throws Throwable { - final CountDownLatch l = new CountDownLatch(1); - AsyncHttpClient c = getAsyncHttpClient(null); - - c.prepareGet(getTargetUrl()).execute(new AsyncHandlerAdapter() { - - @Override - public STATE onHeadersReceived(HttpResponseHeaders content) throws Exception { - try { - FluentCaseInsensitiveStringsMap h = content.getHeaders(); - Assert.assertNotNull(h); - Assert.assertEquals(h.getJoinedValue("content-type", ", ").toLowerCase(), UTF8); - return STATE.ABORT; - } finally { - l.countDown(); + AsyncHttpClient client = getAsyncHttpClient(null); + try { + final CountDownLatch l = new CountDownLatch(1); + + client.prepareGet(getTargetUrl()).execute(new AsyncHandlerAdapter() { + + @Override + public STATE onHeadersReceived(HttpResponseHeaders content) throws Exception { + try { + FluentCaseInsensitiveStringsMap h = content.getHeaders(); + Assert.assertNotNull(h); + Assert.assertEquals(h.getJoinedValue("content-type", ", ").toLowerCase(), UTF8); + return STATE.ABORT; + } finally { + l.countDown(); + } } - } - @Override - public void onThrowable(Throwable t) { - try { - Assert.fail("", t); - } finally { - l.countDown(); + @Override + public void onThrowable(Throwable t) { + try { + Assert.fail("", t); + } finally { + l.countDown(); + } } - } - }); + }); - if (!l.await(5, TimeUnit.SECONDS)) { - Assert.fail("Timeout out"); + if (!l.await(5, TimeUnit.SECONDS)) { + Assert.fail("Timeout out"); + } + } finally { + client.close(); } - c.close(); } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void asyncStreamPOSTTest() throws Throwable { - final CountDownLatch l = new CountDownLatch(1); - FluentCaseInsensitiveStringsMap h = new FluentCaseInsensitiveStringsMap(); - h.add("Content-Type", "application/x-www-form-urlencoded"); - Map> m = new HashMap>(); - m.put("param_1", Arrays.asList("value_1")); - - AsyncHttpClient c = getAsyncHttpClient(null); - - c.preparePost(getTargetUrl()).setParameters(m).execute(new AsyncHandlerAdapter() { - private StringBuilder builder = new StringBuilder(); - - @Override - public STATE onHeadersReceived(HttpResponseHeaders content) throws Exception { - FluentCaseInsensitiveStringsMap h = content.getHeaders(); - Assert.assertNotNull(h); - Assert.assertEquals(h.getJoinedValue("content-type", ", ").toLowerCase(), UTF8); - return STATE.CONTINUE; - } + AsyncHttpClient client = getAsyncHttpClient(null); + try { + final CountDownLatch l = new CountDownLatch(1); + FluentCaseInsensitiveStringsMap h = new FluentCaseInsensitiveStringsMap(); + h.add("Content-Type", "application/x-www-form-urlencoded"); + Map> m = new HashMap>(); + m.put("param_1", Arrays.asList("value_1")); - @Override - public STATE onBodyPartReceived(HttpResponseBodyPart content) throws Exception { - builder.append(new String(content.getBodyPartBytes())); - return STATE.CONTINUE; - } + client.preparePost(getTargetUrl()).setParameters(m).execute(new AsyncHandlerAdapter() { + private StringBuilder builder = new StringBuilder(); - @Override - public String onCompleted() throws Exception { - try { - String r = builder.toString().trim(); - Assert.assertEquals(r, RESPONSE); - return r; - } finally { - l.countDown(); + @Override + public STATE onHeadersReceived(HttpResponseHeaders content) throws Exception { + FluentCaseInsensitiveStringsMap h = content.getHeaders(); + Assert.assertNotNull(h); + Assert.assertEquals(h.getJoinedValue("content-type", ", ").toLowerCase(), UTF8); + return STATE.CONTINUE; + } + + @Override + public STATE onBodyPartReceived(HttpResponseBodyPart content) throws Exception { + builder.append(new String(content.getBodyPartBytes())); + return STATE.CONTINUE; } - } - }); - if (!l.await(10, TimeUnit.SECONDS)) { - Assert.fail("Timeout out"); + @Override + public String onCompleted() throws Exception { + try { + String r = builder.toString().trim(); + Assert.assertEquals(r, RESPONSE); + return r; + } finally { + l.countDown(); + } + } + }); + + if (!l.await(10, TimeUnit.SECONDS)) { + Assert.fail("Timeout out"); + } + } finally { + client.close(); } - c.close(); } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void asyncStreamInterruptTest() throws Throwable { - final CountDownLatch l = new CountDownLatch(1); - FluentCaseInsensitiveStringsMap h = new FluentCaseInsensitiveStringsMap(); - h.add("Content-Type", "application/x-www-form-urlencoded"); + AsyncHttpClient client = getAsyncHttpClient(null); + try { + final CountDownLatch l = new CountDownLatch(1); + FluentCaseInsensitiveStringsMap h = new FluentCaseInsensitiveStringsMap(); + h.add("Content-Type", "application/x-www-form-urlencoded"); - Map> m = new HashMap>(); - m.put("param_1", Arrays.asList("value_1")); + Map> m = new HashMap>(); + m.put("param_1", Arrays.asList("value_1")); - final AtomicBoolean a = new AtomicBoolean(true); - AsyncHttpClient c = getAsyncHttpClient(null); + final AtomicBoolean a = new AtomicBoolean(true); - c.preparePost(getTargetUrl()).setParameters(m).execute(new AsyncHandlerAdapter() { + client.preparePost(getTargetUrl()).setParameters(m).execute(new AsyncHandlerAdapter() { - @Override - public STATE onHeadersReceived(HttpResponseHeaders content) throws Exception { - FluentCaseInsensitiveStringsMap h = content.getHeaders(); - Assert.assertNotNull(h); - Assert.assertEquals(h.getJoinedValue("content-type", ", ").toLowerCase(), UTF8); - return STATE.ABORT; - } + @Override + public STATE onHeadersReceived(HttpResponseHeaders content) throws Exception { + FluentCaseInsensitiveStringsMap h = content.getHeaders(); + Assert.assertNotNull(h); + Assert.assertEquals(h.getJoinedValue("content-type", ", ").toLowerCase(), UTF8); + return STATE.ABORT; + } - @Override - public STATE onBodyPartReceived(final HttpResponseBodyPart content) throws Exception { - a.set(false); - Assert.fail("Interrupted not working"); - return STATE.ABORT; - } + @Override + public STATE onBodyPartReceived(final HttpResponseBodyPart content) throws Exception { + a.set(false); + Assert.fail("Interrupted not working"); + return STATE.ABORT; + } - @Override - public void onThrowable(Throwable t) { - try { - Assert.fail("", t); - } finally { - l.countDown(); + @Override + public void onThrowable(Throwable t) { + try { + Assert.fail("", t); + } finally { + l.countDown(); + } } - } - }); + }); - l.await(5, TimeUnit.SECONDS); - Assert.assertTrue(a.get()); - c.close(); + l.await(5, TimeUnit.SECONDS); + Assert.assertTrue(a.get()); + } finally { + client.close(); + } } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void asyncStreamFutureTest() throws Throwable { - Map> m = new HashMap>(); - m.put("param_1", Arrays.asList("value_1")); - AsyncHttpClient c = getAsyncHttpClient(null); - - Future f = c.preparePost(getTargetUrl()).setParameters(m).execute(new AsyncHandlerAdapter() { - private StringBuilder builder = new StringBuilder(); - - @Override - public STATE onHeadersReceived(HttpResponseHeaders content) throws Exception { - FluentCaseInsensitiveStringsMap h = content.getHeaders(); - Assert.assertNotNull(h); - Assert.assertEquals(h.getJoinedValue("content-type", ", ").toLowerCase(), UTF8); - return STATE.CONTINUE; - } + AsyncHttpClient client = getAsyncHttpClient(null); + try { + Map> m = new HashMap>(); + m.put("param_1", Arrays.asList("value_1")); - @Override - public STATE onBodyPartReceived(HttpResponseBodyPart content) throws Exception { - builder.append(new String(content.getBodyPartBytes())); - return STATE.CONTINUE; - } + Future f = client.preparePost(getTargetUrl()).setParameters(m).execute(new AsyncHandlerAdapter() { + private StringBuilder builder = new StringBuilder(); - @Override - public String onCompleted() throws Exception { - String r = builder.toString().trim(); - Assert.assertEquals(r, RESPONSE); - return r; - } + @Override + public STATE onHeadersReceived(HttpResponseHeaders content) throws Exception { + FluentCaseInsensitiveStringsMap h = content.getHeaders(); + Assert.assertNotNull(h); + Assert.assertEquals(h.getJoinedValue("content-type", ", ").toLowerCase(), UTF8); + return STATE.CONTINUE; + } - @Override - public void onThrowable(Throwable t) { - Assert.fail("", t); - } - }); + @Override + public STATE onBodyPartReceived(HttpResponseBodyPart content) throws Exception { + builder.append(new String(content.getBodyPartBytes())); + return STATE.CONTINUE; + } - try { - String r = f.get(5, TimeUnit.SECONDS); - Assert.assertNotNull(r); - Assert.assertEquals(r.trim(), RESPONSE); - } catch (TimeoutException ex) { - Assert.fail(); + @Override + public String onCompleted() throws Exception { + String r = builder.toString().trim(); + Assert.assertEquals(r, RESPONSE); + return r; + } + + @Override + public void onThrowable(Throwable t) { + Assert.fail("", t); + } + }); + + try { + String r = f.get(5, TimeUnit.SECONDS); + Assert.assertNotNull(r); + Assert.assertEquals(r.trim(), RESPONSE); + } catch (TimeoutException ex) { + Assert.fail(); + } + } finally { + client.close(); } - c.close(); } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void asyncStreamThrowableRefusedTest() throws Throwable { + AsyncHttpClient client = getAsyncHttpClient(null); + try { + final CountDownLatch l = new CountDownLatch(1); - final CountDownLatch l = new CountDownLatch(1); - AsyncHttpClient c = getAsyncHttpClient(null); - - c.prepareGet(getTargetUrl()).execute(new AsyncHandlerAdapter() { - - @Override - public STATE onHeadersReceived(HttpResponseHeaders content) throws Exception { - throw new RuntimeException("FOO"); - } + client.prepareGet(getTargetUrl()).execute(new AsyncHandlerAdapter() { - @Override + @Override + public STATE onHeadersReceived(HttpResponseHeaders content) throws Exception { + throw new RuntimeException("FOO"); + } - public void onThrowable(Throwable t) { - try { - if (t.getMessage() != null) { - Assert.assertEquals(t.getMessage(), "FOO"); + @Override + public void onThrowable(Throwable t) { + try { + if (t.getMessage() != null) { + Assert.assertEquals(t.getMessage(), "FOO"); + } + } finally { + l.countDown(); } - } finally { - l.countDown(); } - } - }); - + }); - if (!l.await(10, TimeUnit.SECONDS)) { - Assert.fail("Timed out"); + if (!l.await(10, TimeUnit.SECONDS)) { + Assert.fail("Timed out"); + } + } finally { + client.close(); } - c.close(); } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void asyncStreamReusePOSTTest() throws Throwable { - final CountDownLatch l = new CountDownLatch(1); - FluentCaseInsensitiveStringsMap h = new FluentCaseInsensitiveStringsMap(); - h.add("Content-Type", "application/x-www-form-urlencoded"); - - Map> m = new HashMap>(); - m.put("param_1", Arrays.asList("value_1")); - AsyncHttpClient c = getAsyncHttpClient(null); - - c.preparePost(getTargetUrl()).setParameters(m).execute(new AsyncHandlerAdapter() { - private StringBuilder builder = new StringBuilder(); - - @Override - public STATE onHeadersReceived(HttpResponseHeaders content) throws Exception { - FluentCaseInsensitiveStringsMap h = content.getHeaders(); - Assert.assertNotNull(h); - Assert.assertEquals(h.getJoinedValue("content-type", ", ").toLowerCase(), UTF8); - return STATE.CONTINUE; - } + AsyncHttpClient client = getAsyncHttpClient(null); + try { + final CountDownLatch l = new CountDownLatch(1); + FluentCaseInsensitiveStringsMap h = new FluentCaseInsensitiveStringsMap(); + h.add("Content-Type", "application/x-www-form-urlencoded"); - @Override - public STATE onBodyPartReceived(HttpResponseBodyPart content) throws Exception { - builder.append(new String(content.getBodyPartBytes())); - return STATE.CONTINUE; - } + Map> m = new HashMap>(); + m.put("param_1", Arrays.asList("value_1")); - @Override - public String onCompleted() throws Exception { - try { - String r = builder.toString().trim(); - Assert.assertEquals(r, RESPONSE); - return r; - } finally { - l.countDown(); + client.preparePost(getTargetUrl()).setParameters(m).execute(new AsyncHandlerAdapter() { + private StringBuilder builder = new StringBuilder(); + + @Override + public STATE onHeadersReceived(HttpResponseHeaders content) throws Exception { + FluentCaseInsensitiveStringsMap h = content.getHeaders(); + Assert.assertNotNull(h); + Assert.assertEquals(h.getJoinedValue("content-type", ", ").toLowerCase(), UTF8); + return STATE.CONTINUE; } - } - }); + @Override + public STATE onBodyPartReceived(HttpResponseBodyPart content) throws Exception { + builder.append(new String(content.getBodyPartBytes())); + return STATE.CONTINUE; + } - if (!l.await(20, TimeUnit.SECONDS)) { - Assert.fail("Timeout out"); - } + @Override + public String onCompleted() throws Exception { + try { + String r = builder.toString().trim(); + Assert.assertEquals(r, RESPONSE); + return r; + } finally { + l.countDown(); + } - // Let do the same again - c.preparePost(getTargetUrl()).setParameters(m).execute(new AsyncHandlerAdapter() { - private StringBuilder builder = new StringBuilder(); + } + }); - @Override - public STATE onHeadersReceived(HttpResponseHeaders content) throws Exception { - FluentCaseInsensitiveStringsMap h = content.getHeaders(); - Assert.assertNotNull(h); - Assert.assertEquals(h.getJoinedValue("content-type", ", ").toLowerCase(), UTF8); - return STATE.CONTINUE; + if (!l.await(20, TimeUnit.SECONDS)) { + Assert.fail("Timeout out"); } - @Override - public STATE onBodyPartReceived(HttpResponseBodyPart content) throws Exception { - builder.append(new String(content.getBodyPartBytes())); - return STATE.CONTINUE; - } + // Let do the same again + client.preparePost(getTargetUrl()).setParameters(m).execute(new AsyncHandlerAdapter() { + private StringBuilder builder = new StringBuilder(); - @Override - public String onCompleted() throws Exception { - try { - String r = builder.toString().trim(); - Assert.assertEquals(r, RESPONSE); - return r; - } finally { - l.countDown(); + @Override + public STATE onHeadersReceived(HttpResponseHeaders content) throws Exception { + FluentCaseInsensitiveStringsMap h = content.getHeaders(); + Assert.assertNotNull(h); + Assert.assertEquals(h.getJoinedValue("content-type", ", ").toLowerCase(), UTF8); + return STATE.CONTINUE; } - } - }); - if (!l.await(20, TimeUnit.SECONDS)) { - Assert.fail("Timeout out"); + @Override + public STATE onBodyPartReceived(HttpResponseBodyPart content) throws Exception { + builder.append(new String(content.getBodyPartBytes())); + return STATE.CONTINUE; + } + + @Override + public String onCompleted() throws Exception { + try { + String r = builder.toString().trim(); + Assert.assertEquals(r, RESPONSE); + return r; + } finally { + l.countDown(); + } + } + }); + + if (!l.await(20, TimeUnit.SECONDS)) { + Assert.fail("Timeout out"); + } + } finally { + client.close(); } - c.close(); } - @Test(groups = {"online", "default_provider"}) + @Test(groups = { "online", "default_provider" }) public void asyncStream301WithBody() throws Throwable { - final CountDownLatch l = new CountDownLatch(1); - AsyncHttpClient c = getAsyncHttpClient(null); - c.prepareGet("http://google.com/").execute(new AsyncHandlerAdapter() { - private StringBuilder builder = new StringBuilder(); - - @Override - public STATE onHeadersReceived(HttpResponseHeaders content) throws Exception { - FluentCaseInsensitiveStringsMap h = content.getHeaders(); - Assert.assertNotNull(h); - Assert.assertEquals(h.getJoinedValue("content-type", ", ").toLowerCase(), "text/html; charset=utf-8"); - return STATE.CONTINUE; - } + AsyncHttpClient client = getAsyncHttpClient(null); + try { + final CountDownLatch l = new CountDownLatch(1); + client.prepareGet("http://google.com/").execute(new AsyncHandlerAdapter() { + private StringBuilder builder = new StringBuilder(); - @Override - public STATE onBodyPartReceived(HttpResponseBodyPart content) throws Exception { - builder.append(new String(content.getBodyPartBytes())); - return STATE.CONTINUE; - } + @Override + public STATE onHeadersReceived(HttpResponseHeaders content) throws Exception { + FluentCaseInsensitiveStringsMap h = content.getHeaders(); + Assert.assertNotNull(h); + Assert.assertEquals(h.getJoinedValue("content-type", ", ").toLowerCase(), "text/html; charset=utf-8"); + return STATE.CONTINUE; + } - @Override - public String onCompleted() throws Exception { - String r = builder.toString(); - Assert.assertTrue(r.contains("301 Moved")); - l.countDown(); - return r; - } - }); + @Override + public STATE onBodyPartReceived(HttpResponseBodyPart content) throws Exception { + builder.append(new String(content.getBodyPartBytes())); + return STATE.CONTINUE; + } + + @Override + public String onCompleted() throws Exception { + String r = builder.toString(); + Assert.assertTrue(r.contains("301 Moved")); + l.countDown(); + return r; + } + }); - if (!l.await(20, TimeUnit.SECONDS)) { - Assert.fail("Timeout out"); + if (!l.await(20, TimeUnit.SECONDS)) { + Assert.fail("Timeout out"); + } + } finally { + client.close(); } - c.close(); } - @Test(groups = {"online", "default_provider"}) + @Test(groups = { "online", "default_provider" }) public void asyncStream301RedirectWithBody() throws Throwable { - final CountDownLatch l = new CountDownLatch(1); - AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setFollowRedirects(true).build()); - c.prepareGet("http://google.com/").execute(new AsyncHandlerAdapter() { - private StringBuilder builder = new StringBuilder(); - - @Override - public STATE onHeadersReceived(HttpResponseHeaders content) throws Exception { - FluentCaseInsensitiveStringsMap h = content.getHeaders(); - Assert.assertNotNull(h); - Assert.assertEquals(h.getFirstValue( "server" ), "gws"); - // This assertion below is not an invariant, since implicitly contains locale-dependant settings - // and fails when run in country having own localized Google site and it's locale relies on something - // other than ISO-8859-1. - // In Hungary for example, http://google.com/ redirects to http://www.google.hu/, a localized - // Google site, that uses ISO-8892-2 encoding (default for HU). Similar is true for other - // non-ISO-8859-1 using countries that have "localized" google, like google.hr, google.rs, google.cz, google.sk etc. - // - // Assert.assertEquals(h.getJoinedValue("content-type", ", "), "text/html; charset=ISO-8859-1"); - return STATE.CONTINUE; - } + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setFollowRedirects(true).build()); + try { + final CountDownLatch l = new CountDownLatch(1); + client.prepareGet("http://google.com/").execute(new AsyncHandlerAdapter() { + private StringBuilder builder = new StringBuilder(); - @Override - public STATE onBodyPartReceived(HttpResponseBodyPart content) throws Exception { - builder.append(new String(content.getBodyPartBytes())); - return STATE.CONTINUE; - } + @Override + public STATE onHeadersReceived(HttpResponseHeaders content) throws Exception { + FluentCaseInsensitiveStringsMap h = content.getHeaders(); + Assert.assertNotNull(h); + Assert.assertEquals(h.getFirstValue("server"), "gws"); + // This assertion below is not an invariant, since implicitly contains locale-dependant settings + // and fails when run in country having own localized Google site and it's locale relies on something + // other than ISO-8859-1. + // In Hungary for example, http://google.com/ redirects to http://www.google.hu/, a localized + // Google site, that uses ISO-8892-2 encoding (default for HU). Similar is true for other + // non-ISO-8859-1 using countries that have "localized" google, like google.hr, google.rs, google.cz, google.sk etc. + // + // Assert.assertEquals(h.getJoinedValue("content-type", ", "), "text/html; charset=ISO-8859-1"); + return STATE.CONTINUE; + } - @Override - public String onCompleted() throws Exception { - String r = builder.toString(); - Assert.assertTrue(!r.contains("301 Moved")); - l.countDown(); + @Override + public STATE onBodyPartReceived(HttpResponseBodyPart content) throws Exception { + builder.append(new String(content.getBodyPartBytes())); + return STATE.CONTINUE; + } - return r; - } - }); + @Override + public String onCompleted() throws Exception { + String r = builder.toString(); + Assert.assertTrue(!r.contains("301 Moved")); + l.countDown(); - if (!l.await(20, TimeUnit.SECONDS)) { - Assert.fail("Timeout out"); + return r; + } + }); + + if (!l.await(20, TimeUnit.SECONDS)) { + Assert.fail("Timeout out"); + } + } finally { + client.close(); } - c.close(); } - @Test(groups = {"standalone", "default_provider"}, timeOut = 3000, description = "Test behavior of 'read only status line' scenario.") + @Test(groups = { "standalone", "default_provider" }, timeOut = 3000, description = "Test behavior of 'read only status line' scenario.") public void asyncStreamJustStatusLine() throws Throwable { - final int STATUS = 0; - final int COMPLETED = 1; - final int OTHER = 2; - final boolean[] whatCalled = new boolean[]{false, false, false}; - final CountDownLatch latch = new CountDownLatch(1); AsyncHttpClient client = getAsyncHttpClient(null); - Future statusCode = client.prepareGet(getTargetUrl()).execute(new AsyncHandler() { - private int status = -1; + try { + final int STATUS = 0; + final int COMPLETED = 1; + final int OTHER = 2; + final boolean[] whatCalled = new boolean[] { false, false, false }; + final CountDownLatch latch = new CountDownLatch(1); + Future statusCode = client.prepareGet(getTargetUrl()).execute(new AsyncHandler() { + private int status = -1; + + /* @Override */ + public void onThrowable(Throwable t) { + whatCalled[OTHER] = true; + latch.countDown(); + } - /* @Override */ - public void onThrowable(Throwable t) { - whatCalled[OTHER] = true; - latch.countDown(); - } + /* @Override */ + public STATE onBodyPartReceived(HttpResponseBodyPart bodyPart) throws Exception { + whatCalled[OTHER] = true; + latch.countDown(); + return STATE.ABORT; + } - /* @Override */ - public STATE onBodyPartReceived(HttpResponseBodyPart bodyPart) throws Exception { - whatCalled[OTHER] = true; - latch.countDown(); - return STATE.ABORT; - } + /* @Override */ + public STATE onStatusReceived(HttpResponseStatus responseStatus) throws Exception { + whatCalled[STATUS] = true; + System.out.println(responseStatus); + status = responseStatus.getStatusCode(); + latch.countDown(); + return STATE.ABORT; + } - /* @Override */ - public STATE onStatusReceived(HttpResponseStatus responseStatus) throws Exception { - whatCalled[STATUS] = true; - System.out.println(responseStatus); - status = responseStatus.getStatusCode(); - latch.countDown(); - return STATE.ABORT; - } + /* @Override */ + public STATE onHeadersReceived(HttpResponseHeaders headers) throws Exception { + whatCalled[OTHER] = true; + latch.countDown(); + return STATE.ABORT; + } - /* @Override */ - public STATE onHeadersReceived(HttpResponseHeaders headers) throws Exception { - whatCalled[OTHER] = true; - latch.countDown(); - return STATE.ABORT; - } + /* @Override */ + public Integer onCompleted() throws Exception { + whatCalled[COMPLETED] = true; + latch.countDown(); + return status; + } + }); - /* @Override */ - public Integer onCompleted() throws Exception { - whatCalled[COMPLETED] = true; - latch.countDown(); - return status; + if (!latch.await(2, TimeUnit.SECONDS)) { + Assert.fail("Timeout"); + return; } - }); - - if (!latch.await(2, TimeUnit.SECONDS)) { - Assert.fail("Timeout"); - return; - } - Integer status = statusCode.get(TIMEOUT, TimeUnit.SECONDS); - Assert.assertEquals((int) status, 200, "Expected status code failed."); + Integer status = statusCode.get(TIMEOUT, TimeUnit.SECONDS); + Assert.assertEquals((int) status, 200, "Expected status code failed."); - if (!whatCalled[STATUS]) { - Assert.fail("onStatusReceived not called."); - } - if (!whatCalled[COMPLETED]) { - Assert.fail("onCompleted not called."); - } - if (whatCalled[OTHER]) { - Assert.fail("Other method of AsyncHandler got called."); + if (!whatCalled[STATUS]) { + Assert.fail("onStatusReceived not called."); + } + if (!whatCalled[COMPLETED]) { + Assert.fail("onCompleted not called."); + } + if (whatCalled[OTHER]) { + Assert.fail("Other method of AsyncHandler got called."); + } + } finally { + client.close(); } - client.close(); } - @Test(groups = {"online", "default_provider"}) + @Test(groups = { "online", "default_provider" }) public void asyncOptionsTest() throws Throwable { - final CountDownLatch l = new CountDownLatch(1); - AsyncHttpClient c = getAsyncHttpClient(null); - c.prepareOptions("http://www.apache.org/").execute(new AsyncHandlerAdapter() { - - @Override - public STATE onHeadersReceived(HttpResponseHeaders content) throws Exception { - FluentCaseInsensitiveStringsMap h = content.getHeaders(); - Assert.assertNotNull(h); - String result = h.getJoinedValue("Allow", ", "); - String[] resultParts = result.split(","); - String[] expected = "OPTIONS,GET,HEAD,POST,TRACE".split(","); - Arrays.sort(resultParts); - Arrays.sort(expected); - Assert.assertEquals(expected, resultParts); - return STATE.ABORT; - } + AsyncHttpClient client = getAsyncHttpClient(null); + try { + final CountDownLatch l = new CountDownLatch(1); + client.prepareOptions("http://www.apache.org/").execute(new AsyncHandlerAdapter() { - @Override - public STATE onBodyPartReceived(HttpResponseBodyPart content) throws Exception { - return STATE.CONTINUE; - } + @Override + public STATE onHeadersReceived(HttpResponseHeaders content) throws Exception { + FluentCaseInsensitiveStringsMap h = content.getHeaders(); + Assert.assertNotNull(h); + String result = h.getJoinedValue("Allow", ", "); + String[] resultParts = result.split(","); + String[] expected = "OPTIONS,GET,HEAD,POST,TRACE".split(","); + Arrays.sort(resultParts); + Arrays.sort(expected); + Assert.assertEquals(expected, resultParts); + return STATE.ABORT; + } - @Override - public String onCompleted() throws Exception { - try { - return "OK"; - } finally { - l.countDown(); + @Override + public STATE onBodyPartReceived(HttpResponseBodyPart content) throws Exception { + return STATE.CONTINUE; } - } - }); - if (!l.await(20, TimeUnit.SECONDS)) { - Assert.fail("Timeout out"); + @Override + public String onCompleted() throws Exception { + try { + return "OK"; + } finally { + l.countDown(); + } + } + }); + + if (!l.await(20, TimeUnit.SECONDS)) { + Assert.fail("Timeout out"); + } + } finally { + client.close(); } - c.close(); } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void closeConnectionTest() throws Throwable { - final CountDownLatch l = new CountDownLatch(1); - AsyncHttpClient c = getAsyncHttpClient(null); - - Response r = c.prepareGet(getTargetUrl()).execute(new AsyncHandler() { + AsyncHttpClient client = getAsyncHttpClient(null); + try { + Response r = client.prepareGet(getTargetUrl()).execute(new AsyncHandler() { - private Response.ResponseBuilder builder = new Response.ResponseBuilder(); + private Response.ResponseBuilder builder = new Response.ResponseBuilder(); - public STATE onHeadersReceived(HttpResponseHeaders content) throws Exception { - builder.accumulate(content); - return STATE.CONTINUE; - } + public STATE onHeadersReceived(HttpResponseHeaders content) throws Exception { + builder.accumulate(content); + return STATE.CONTINUE; + } - public void onThrowable(Throwable t) { - } + public void onThrowable(Throwable t) { + } - public STATE onBodyPartReceived(HttpResponseBodyPart content) throws Exception { - builder.accumulate(content); + public STATE onBodyPartReceived(HttpResponseBodyPart content) throws Exception { + builder.accumulate(content); - if (content.isLast()) { - content.markUnderlyingConnectionAsClosed(); + if (content.isLast()) { + content.markUnderlyingConnectionAsClosed(); + } + return STATE.CONTINUE; } - return STATE.CONTINUE; - } - public STATE onStatusReceived(HttpResponseStatus responseStatus) throws Exception { - builder.accumulate(responseStatus); + public STATE onStatusReceived(HttpResponseStatus responseStatus) throws Exception { + builder.accumulate(responseStatus); - return STATE.CONTINUE; - } + return STATE.CONTINUE; + } - public Response onCompleted() throws Exception { - return builder.build(); - } - }).get(); + public Response onCompleted() throws Exception { + return builder.build(); + } + }).get(); - Assert.assertNotNull(r); - Assert.assertEquals(r.getStatusCode(), 200); - c.close(); + Assert.assertNotNull(r); + Assert.assertEquals(r.getStatusCode(), 200); + } finally { + client.close(); + } } } diff --git a/src/test/java/com/ning/http/client/async/AsyncStreamLifecycleTest.java b/src/test/java/com/ning/http/client/async/AsyncStreamLifecycleTest.java index 3208972a28..d12e647e58 100644 --- a/src/test/java/com/ning/http/client/async/AsyncStreamLifecycleTest.java +++ b/src/test/java/com/ning/http/client/async/AsyncStreamLifecycleTest.java @@ -47,7 +47,7 @@ /** * Tests default asynchronous life cycle. - * + * * @author Hubert Iwaniuk */ public abstract class AsyncStreamLifecycleTest extends AbstractBasicTest { @@ -63,8 +63,7 @@ public void tearDownGlobal() throws Exception { @Override public AbstractHandler configureHandler() throws Exception { return new AbstractHandler() { - public void handle(String s, Request request, HttpServletRequest req, final HttpServletResponse resp) - throws IOException, ServletException { + public void handle(String s, Request request, HttpServletRequest req, final HttpServletResponse resp) throws IOException, ServletException { resp.setContentType("text/plain;charset=utf-8"); resp.setStatus(200); final Continuation continuation = ContinuationSupport.getContinuation(req); @@ -100,62 +99,64 @@ public void run() { }; } - //TODO Netty only. + // TODO Netty only. - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void testStream() throws IOException { - AsyncHttpClient ahc = getAsyncHttpClient(null); - final AtomicBoolean err = new AtomicBoolean(false); - final LinkedBlockingQueue queue = new LinkedBlockingQueue(); - final AtomicBoolean status = new AtomicBoolean(false); - final AtomicInteger headers = new AtomicInteger(0); - final CountDownLatch latch = new CountDownLatch(1); - ahc.executeRequest(ahc.prepareGet(getTargetUrl()).build(), new AsyncHandler() { - public void onThrowable(Throwable t) { - fail("Got throwable.", t); - err.set(true); - } + AsyncHttpClient client = getAsyncHttpClient(null); + try { + final AtomicBoolean err = new AtomicBoolean(false); + final LinkedBlockingQueue queue = new LinkedBlockingQueue(); + final AtomicBoolean status = new AtomicBoolean(false); + final AtomicInteger headers = new AtomicInteger(0); + final CountDownLatch latch = new CountDownLatch(1); + client.executeRequest(client.prepareGet(getTargetUrl()).build(), new AsyncHandler() { + public void onThrowable(Throwable t) { + fail("Got throwable.", t); + err.set(true); + } - public STATE onBodyPartReceived(HttpResponseBodyPart e) throws Exception { - String s = new String(e.getBodyPartBytes()); - log.info("got part: {}", s); - if (s.isEmpty()) { - //noinspection ThrowableInstanceNeverThrown - log.warn("Sampling stacktrace.", - new Throwable("trace that, we should not get called for empty body.")); + public STATE onBodyPartReceived(HttpResponseBodyPart e) throws Exception { + String s = new String(e.getBodyPartBytes()); + log.info("got part: {}", s); + if (s.isEmpty()) { + // noinspection ThrowableInstanceNeverThrown + log.warn("Sampling stacktrace.", new Throwable("trace that, we should not get called for empty body.")); + } + queue.put(s); + return STATE.CONTINUE; } - queue.put(s); - return STATE.CONTINUE; - } - public STATE onStatusReceived(HttpResponseStatus e) throws Exception { - status.set(true); - return STATE.CONTINUE; - } + public STATE onStatusReceived(HttpResponseStatus e) throws Exception { + status.set(true); + return STATE.CONTINUE; + } - public STATE onHeadersReceived(HttpResponseHeaders e) throws Exception { - if (headers.incrementAndGet() == 2) { - throw new Exception("Analyze this."); + public STATE onHeadersReceived(HttpResponseHeaders e) throws Exception { + if (headers.incrementAndGet() == 2) { + throw new Exception("Analyze this."); + } + return STATE.CONTINUE; } - return STATE.CONTINUE; - } - public Object onCompleted() throws Exception { - latch.countDown(); - return null; + public Object onCompleted() throws Exception { + latch.countDown(); + return null; + } + }); + try { + assertTrue(latch.await(1, TimeUnit.SECONDS), "Latch failed."); + } catch (InterruptedException e) { + fail("Interrupted.", e); } - }); - try { - assertTrue(latch.await(1, TimeUnit.SECONDS), "Latch failed."); - } catch (InterruptedException e) { - fail("Interrupted.", e); + assertFalse(err.get()); + assertEquals(queue.size(), 2); + assertTrue(queue.contains("part1")); + assertTrue(queue.contains("part2")); + assertTrue(status.get()); + assertEquals(headers.get(), 1); + } finally { + client.close(); } - assertFalse(err.get()); - assertEquals(queue.size(), 2); - assertTrue(queue.contains("part1")); - assertTrue(queue.contains("part2")); - assertTrue(status.get()); - assertEquals(headers.get(), 1); - ahc.close(); } } diff --git a/src/test/java/com/ning/http/client/async/AuthTimeoutTest.java b/src/test/java/com/ning/http/client/async/AuthTimeoutTest.java index 37b83eff80..b5a4c99618 100644 --- a/src/test/java/com/ning/http/client/async/AuthTimeoutTest.java +++ b/src/test/java/com/ning/http/client/async/AuthTimeoutTest.java @@ -39,7 +39,6 @@ import java.io.IOException; import java.io.OutputStream; import java.util.ArrayList; -import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -50,8 +49,7 @@ import static org.testng.Assert.assertNotNull; import static org.testng.Assert.fail; -public abstract class AuthTimeoutTest - extends AbstractBasicTest { +public abstract class AuthTimeoutTest extends AbstractBasicTest { private final static String user = "user"; @@ -59,8 +57,7 @@ public abstract class AuthTimeoutTest protected AsyncHttpClient client; - public void setUpServer(String auth) - throws Exception { + public void setUpServer(String auth) throws Exception { server = new Server(); Logger root = Logger.getRootLogger(); root.setLevel(Level.DEBUG); @@ -79,7 +76,7 @@ public void setUpServer(String auth) Constraint constraint = new Constraint(); constraint.setName(auth); - constraint.setRoles(new String[]{user, admin}); + constraint.setRoles(new String[] { user, admin }); constraint.setAuthenticate(true); ConstraintMapping mapping = new ConstraintMapping(); @@ -106,10 +103,8 @@ public void setUpServer(String auth) log.info("Local HTTP server started successfully"); } - private class SimpleHandler - extends AbstractHandler { - public void handle(String s, Request r, HttpServletRequest request, HttpServletResponse response) - throws IOException, ServletException { + private class SimpleHandler extends AbstractHandler { + public void handle(String s, Request r, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { // NOTE: handler sends less bytes than are given in Content-Length, which should lead to timeout @@ -129,150 +124,138 @@ public void handle(String s, Request r, HttpServletRequest request, HttpServletR } } - @Test(groups = {"standalone", "default_provider"}, enabled = false) - public void basicAuthTimeoutTest() - throws Exception { + @Test(groups = { "standalone", "default_provider" }, enabled = false) + public void basicAuthTimeoutTest() throws Exception { setUpServer(Constraint.__BASIC_AUTH); - - Future f = execute(false); try { - f.get(); - fail("expected timeout"); - } - catch (Exception e) { - inspectException(e); + Future f = execute(false); + try { + f.get(); + fail("expected timeout"); + } catch (Exception e) { + inspectException(e); + } + } finally { + client.close(); } - client.close(); } - @Test(groups = {"standalone", "default_provider"}, enabled = false) - public void basicPreemptiveAuthTimeoutTest() - throws Exception { + @Test(groups = { "standalone", "default_provider" }, enabled = false) + public void basicPreemptiveAuthTimeoutTest() throws Exception { setUpServer(Constraint.__BASIC_AUTH); - - Future f = execute(true); try { - f.get(); - fail("expected timeout"); - } - catch (Exception e) { - inspectException(e); + Future f = execute(true); + try { + f.get(); + fail("expected timeout"); + } catch (Exception e) { + inspectException(e); + } + } finally { + client.close(); } - client.close(); } - @Test(groups = {"standalone", "default_provider"}, enabled = false) - public void digestAuthTimeoutTest() - throws Exception { + @Test(groups = { "standalone", "default_provider" }, enabled = false) + public void digestAuthTimeoutTest() throws Exception { setUpServer(Constraint.__DIGEST_AUTH); - - Future f = execute(false); try { - f.get(); - fail("expected timeout"); - } - catch (Exception e) { - inspectException(e); + Future f = execute(false); + try { + f.get(); + fail("expected timeout"); + } catch (Exception e) { + inspectException(e); + } + } finally { + client.close(); } - client.close(); } - @Test(groups = {"standalone", "default_provider"}, enabled = false) - public void digestPreemptiveAuthTimeoutTest() - throws Exception { + @Test(groups = { "standalone", "default_provider" }, enabled = false) + public void digestPreemptiveAuthTimeoutTest() throws Exception { setUpServer(Constraint.__DIGEST_AUTH); - Future f = execute(true); try { + Future f = execute(true); f.get(); fail("expected timeout"); - } - catch (Exception e) { + } catch (Exception e) { inspectException(e); + } finally { + client.close(); } - client.close(); } - @Test(groups = {"standalone", "default_provider"}, enabled = false) - public void basicFutureAuthTimeoutTest() - throws Exception { + @Test(groups = { "standalone", "default_provider" }, enabled = false) + public void basicFutureAuthTimeoutTest() throws Exception { setUpServer(Constraint.__BASIC_AUTH); - - Future f = execute(false); try { + Future f = execute(false); f.get(1, TimeUnit.SECONDS); fail("expected timeout"); - } - catch (Exception e) { + } catch (Exception e) { inspectException(e); + } finally { + client.close(); } - client.close(); } - @Test(groups = {"standalone", "default_provider"}, enabled = false) - public void basicFuturePreemptiveAuthTimeoutTest() - throws Exception { + @Test(groups = { "standalone", "default_provider" }, enabled = false) + public void basicFuturePreemptiveAuthTimeoutTest() throws Exception { setUpServer(Constraint.__BASIC_AUTH); - - Future f = execute(true); try { + Future f = execute(true); f.get(1, TimeUnit.SECONDS); fail("expected timeout"); - } - catch (Exception e) { + } catch (Exception e) { inspectException(e); + } finally { + client.close(); } - client.close(); } - @Test(groups = {"standalone", "default_provider"}, enabled = false) - public void digestFutureAuthTimeoutTest() - throws Exception { + @Test(groups = { "standalone", "default_provider" }, enabled = false) + public void digestFutureAuthTimeoutTest() throws Exception { setUpServer(Constraint.__DIGEST_AUTH); - - Future f = execute(false); try { + Future f = execute(false); f.get(1, TimeUnit.SECONDS); fail("expected timeout"); - } - catch (Exception e) { + } catch (Exception e) { inspectException(e); + } finally { + client.close(); } - client.close(); } - @Test(groups = {"standalone", "default_provider"}, enabled = false) - public void digestFuturePreemptiveAuthTimeoutTest() - throws Exception { + @Test(groups = { "standalone", "default_provider" }, enabled = false) + public void digestFuturePreemptiveAuthTimeoutTest() throws Exception { setUpServer(Constraint.__DIGEST_AUTH); - Future f = execute(true); try { + Future f = execute(true); f.get(1, TimeUnit.SECONDS); fail("expected timeout"); - } - catch (Exception e) { + } catch (Exception e) { inspectException(e); + } finally { + client.close(); } - client.close(); } protected void inspectException(Throwable t) { assertNotNull(t.getCause()); assertEquals(t.getCause().getClass(), IOException.class); - if (!t.getCause().getMessage().startsWith("Remotely Closed")){ + if (!t.getCause().getMessage().startsWith("Remotely Closed")) { fail(); - }; + } + ; } - protected Future execute(boolean preemptive) - throws IOException { - client = - getAsyncHttpClient( - new AsyncHttpClientConfig.Builder().setIdleConnectionInPoolTimeoutInMs(2000).setConnectionTimeoutInMs(20000).setRequestTimeoutInMs(2000).build()); - AsyncHttpClient.BoundRequestBuilder r = - client.prepareGet(getTargetUrl()).setRealm(realm(preemptive)).setHeader("X-Content", - "Test"); + protected Future execute(boolean preemptive) throws IOException { + client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setIdleConnectionInPoolTimeoutInMs(2000).setConnectionTimeoutInMs(20000).setRequestTimeoutInMs(2000).build()); + AsyncHttpClient.BoundRequestBuilder r = client.prepareGet(getTargetUrl()).setRealm(realm(preemptive)).setHeader("X-Content", "Test"); Future f = r.execute(); return f; } @@ -287,8 +270,7 @@ protected String getTargetUrl() { } @Override - public AbstractHandler configureHandler() - throws Exception { + public AbstractHandler configureHandler() throws Exception { return new SimpleHandler(); } } diff --git a/src/test/java/com/ning/http/client/async/BasicAuthTest.java b/src/test/java/com/ning/http/client/async/BasicAuthTest.java index bbdefbd3e7..4c7aec83ea 100644 --- a/src/test/java/com/ning/http/client/async/BasicAuthTest.java +++ b/src/test/java/com/ning/http/client/async/BasicAuthTest.java @@ -54,7 +54,6 @@ import java.io.IOException; import java.net.URL; import java.util.ArrayList; -import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -62,7 +61,6 @@ import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; -import java.util.concurrent.atomic.AtomicBoolean; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNotNull; @@ -81,8 +79,7 @@ public void setUpGlobal() throws Exception { server = new Server(); Logger root = Logger.getRootLogger(); root.setLevel(Level.DEBUG); - root.addAppender(new ConsoleAppender( - new PatternLayout(PatternLayout.TTCC_CONVERSION_PATTERN))); + root.addAppender(new ConsoleAppender(new PatternLayout(PatternLayout.TTCC_CONVERSION_PATTERN))); port1 = findFreePort(); Connector listener = new SelectChannelConnector(); @@ -97,7 +94,7 @@ public void setUpGlobal() throws Exception { Constraint constraint = new Constraint(); constraint.setName(Constraint.__BASIC_AUTH); - constraint.setRoles(new String[]{user, admin}); + constraint.setRoles(new String[] { user, admin }); constraint.setAuthenticate(true); ConstraintMapping mapping = new ConstraintMapping(); @@ -136,8 +133,7 @@ private String getFileContent(final File file) { } return sb.toString(); } - throw new IllegalArgumentException("File does not exist or cannot be read: " - + file.getCanonicalPath()); + throw new IllegalArgumentException("File does not exist or cannot be read: " + file.getCanonicalPath()); } catch (IOException ioe) { throw new IllegalStateException(ioe); } finally { @@ -166,7 +162,7 @@ private void setUpSecondServer() throws Exception { Constraint constraint = new Constraint(); constraint.setName(Constraint.__DIGEST_AUTH); - constraint.setRoles(new String[]{user, admin}); + constraint.setRoles(new String[] { user, admin }); constraint.setAuthenticate(true); ConstraintMapping mapping = new ConstraintMapping(); @@ -180,8 +176,7 @@ private void setUpSecondServer() throws Exception { ConstraintSecurityHandler security = new ConstraintSecurityHandler() { @Override - public void handle(String arg0, Request arg1, HttpServletRequest arg2, HttpServletResponse arg3) - throws IOException, ServletException { + public void handle(String arg0, Request arg1, HttpServletRequest arg2, HttpServletResponse arg3) throws IOException, ServletException { System.err.println("request in security handler"); System.err.println("Authorization: " + arg2.getHeader("Authorization")); System.err.println("RequestUri: " + arg2.getRequestURI()); @@ -208,12 +203,7 @@ private void stopSecondServer() throws Exception { private class RedirectHandler extends AbstractHandler { - private AtomicBoolean redirectOnce = new AtomicBoolean(false); - - public void handle(String s, - Request r, - HttpServletRequest request, - HttpServletResponse response) throws IOException, ServletException { + public void handle(String s, Request r, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { System.err.println("redirecthandler"); System.err.println("request: " + request.getRequestURI()); @@ -240,10 +230,7 @@ public void handle(String s, } private class SimpleHandler extends AbstractHandler { - public void handle(String s, - Request r, - HttpServletRequest request, - HttpServletResponse response) throws IOException, ServletException { + public void handle(String s, Request r, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { if (request.getHeader("X-401") != null) { response.setStatus(401); @@ -256,7 +243,6 @@ public void handle(String s, response.addHeader("X-Content-Length", String.valueOf(request.getContentLength())); response.setStatus(200); - int size = 10 * 1024; if (request.getContentLength() > 0) { size = request.getContentLength(); @@ -273,28 +259,30 @@ public void handle(String s, } } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void basicAuthTest() throws IOException, ExecutionException, TimeoutException, InterruptedException { AsyncHttpClient client = getAsyncHttpClient(null); - AsyncHttpClient.BoundRequestBuilder r = client.prepareGet(getTargetUrl()) - .setRealm((new Realm.RealmBuilder()).setPrincipal(user).setPassword(admin).build()); - - Future f = r.execute(); - Response resp = f.get(3, TimeUnit.SECONDS); - assertNotNull(resp); - assertNotNull(resp.getHeader("X-Auth")); - assertEquals(resp.getStatusCode(), HttpServletResponse.SC_OK); - client.close(); + try { + AsyncHttpClient.BoundRequestBuilder r = client.prepareGet(getTargetUrl()).setRealm((new Realm.RealmBuilder()).setPrincipal(user).setPassword(admin).build()); + + Future f = r.execute(); + Response resp = f.get(3, TimeUnit.SECONDS); + assertNotNull(resp); + assertNotNull(resp.getHeader("X-Auth")); + assertEquals(resp.getStatusCode(), HttpServletResponse.SC_OK); + } finally { + client.close(); + } } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void redirectAndBasicAuthTest() throws Exception, ExecutionException, TimeoutException, InterruptedException { AsyncHttpClient client = null; try { setUpSecondServer(); client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setFollowRedirects(true).setMaximumNumberOfRedirects(10).build()); AsyncHttpClient.BoundRequestBuilder r = client.prepareGet(getTargetUrl2()) - // .setHeader( "X-302", "/bla" ) + // .setHeader( "X-302", "/bla" ) .setRealm((new Realm.RealmBuilder()).setPrincipal(user).setPassword(admin).build()); Future f = r.execute(); @@ -304,7 +292,8 @@ public void redirectAndBasicAuthTest() throws Exception, ExecutionException, Tim assertNotNull(resp.getHeader("X-Auth")); } finally { - if (client != null) client.close(); + if (client != null) + client.close(); stopSecondServer(); } } @@ -318,152 +307,165 @@ protected String getTargetUrl2() { return "http://127.0.0.1/" + port2 + "/uff"; } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void basic401Test() throws IOException, ExecutionException, TimeoutException, InterruptedException { AsyncHttpClient client = getAsyncHttpClient(null); - AsyncHttpClient.BoundRequestBuilder r = client.prepareGet(getTargetUrl()) - .setHeader("X-401", "401").setRealm((new Realm.RealmBuilder()).setPrincipal(user).setPassword(admin).build()); - - Future f = r.execute(new AsyncHandler() { + try { + AsyncHttpClient.BoundRequestBuilder r = client.prepareGet(getTargetUrl()).setHeader("X-401", "401").setRealm((new Realm.RealmBuilder()).setPrincipal(user).setPassword(admin).build()); - private HttpResponseStatus status; + Future f = r.execute(new AsyncHandler() { + private HttpResponseStatus status; - public void onThrowable(Throwable t) { + public void onThrowable(Throwable t) { - } + } - public STATE onBodyPartReceived(HttpResponseBodyPart bodyPart) throws Exception { - return STATE.CONTINUE; - } + public STATE onBodyPartReceived(HttpResponseBodyPart bodyPart) throws Exception { + return STATE.CONTINUE; + } - public STATE onStatusReceived(HttpResponseStatus responseStatus) throws Exception { - this.status = responseStatus; + public STATE onStatusReceived(HttpResponseStatus responseStatus) throws Exception { + this.status = responseStatus; - if (status.getStatusCode() != 200) { - return STATE.ABORT; + if (status.getStatusCode() != 200) { + return STATE.ABORT; + } + return STATE.CONTINUE; } - return STATE.CONTINUE; - } - public STATE onHeadersReceived(HttpResponseHeaders headers) throws Exception { - return STATE.CONTINUE; - } + public STATE onHeadersReceived(HttpResponseHeaders headers) throws Exception { + return STATE.CONTINUE; + } - public Integer onCompleted() throws Exception { - return status.getStatusCode(); - } - }); - Integer statusCode = f.get(10, TimeUnit.SECONDS); - assertNotNull(statusCode); - assertEquals(statusCode.intValue(), 401); - client.close(); + public Integer onCompleted() throws Exception { + return status.getStatusCode(); + } + }); + Integer statusCode = f.get(10, TimeUnit.SECONDS); + assertNotNull(statusCode); + assertEquals(statusCode.intValue(), 401); + } finally { + client.close(); + } } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void basicAuthTestPreemtiveTest() throws IOException, ExecutionException, TimeoutException, InterruptedException { AsyncHttpClient client = getAsyncHttpClient(null); - AsyncHttpClient.BoundRequestBuilder r = client.prepareGet(getTargetUrl()) - .setRealm((new Realm.RealmBuilder()).setPrincipal(user).setPassword(admin).setUsePreemptiveAuth(true).build()); - - Future f = r.execute(); - Response resp = f.get(3, TimeUnit.SECONDS); - assertNotNull(resp); - assertNotNull(resp.getHeader("X-Auth")); - assertEquals(resp.getStatusCode(), HttpServletResponse.SC_OK); - client.close(); + try { + AsyncHttpClient.BoundRequestBuilder r = client.prepareGet(getTargetUrl()).setRealm((new Realm.RealmBuilder()).setPrincipal(user).setPassword(admin).setUsePreemptiveAuth(true).build()); + + Future f = r.execute(); + Response resp = f.get(3, TimeUnit.SECONDS); + assertNotNull(resp); + assertNotNull(resp.getHeader("X-Auth")); + assertEquals(resp.getStatusCode(), HttpServletResponse.SC_OK); + } finally { + client.close(); + } } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void basicAuthNegativeTest() throws IOException, ExecutionException, TimeoutException, InterruptedException { AsyncHttpClient client = getAsyncHttpClient(null); - AsyncHttpClient.BoundRequestBuilder r = client.prepareGet(getTargetUrl()) - .setRealm((new Realm.RealmBuilder()).setPrincipal("fake").setPassword(admin).build()); - - Future f = r.execute(); - Response resp = f.get(3, TimeUnit.SECONDS); - assertNotNull(resp); - assertEquals(resp.getStatusCode(), 401); - client.close(); + try { + AsyncHttpClient.BoundRequestBuilder r = client.prepareGet(getTargetUrl()).setRealm((new Realm.RealmBuilder()).setPrincipal("fake").setPassword(admin).build()); + + Future f = r.execute(); + Response resp = f.get(3, TimeUnit.SECONDS); + assertNotNull(resp); + assertEquals(resp.getStatusCode(), 401); + } finally { + client.close(); + } } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void basicAuthInputStreamTest() throws IOException, ExecutionException, TimeoutException, InterruptedException { AsyncHttpClient client = getAsyncHttpClient(null); - ByteArrayInputStream is = new ByteArrayInputStream("test".getBytes()); - AsyncHttpClient.BoundRequestBuilder r = client.preparePost(getTargetUrl()) - .setBody(is).setRealm((new Realm.RealmBuilder()).setPrincipal(user).setPassword(admin).build()); - - Future f = r.execute(); - Response resp = f.get(30, TimeUnit.SECONDS); - assertNotNull(resp); - assertNotNull(resp.getHeader("X-Auth")); - assertEquals(resp.getStatusCode(), HttpServletResponse.SC_OK); - assertEquals(resp.getResponseBody(), "test"); - client.close(); + try { + ByteArrayInputStream is = new ByteArrayInputStream("test".getBytes()); + AsyncHttpClient.BoundRequestBuilder r = client.preparePost(getTargetUrl()).setBody(is).setRealm((new Realm.RealmBuilder()).setPrincipal(user).setPassword(admin).build()); + + Future f = r.execute(); + Response resp = f.get(30, TimeUnit.SECONDS); + assertNotNull(resp); + assertNotNull(resp.getHeader("X-Auth")); + assertEquals(resp.getStatusCode(), HttpServletResponse.SC_OK); + assertEquals(resp.getResponseBody(), "test"); + } finally { + client.close(); + } } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void basicAuthFileTest() throws Throwable { AsyncHttpClient client = getAsyncHttpClient(null); - ClassLoader cl = getClass().getClassLoader(); - // override system properties - URL url = cl.getResource("SimpleTextFile.txt"); - File file = new File(url.toURI()); - final String fileContent = getFileContent(file); - - AsyncHttpClient.BoundRequestBuilder r = client.preparePost(getTargetUrl()) - .setBody(file).setRealm((new Realm.RealmBuilder()).setPrincipal(user).setPassword(admin).build()); - - Future f = r.execute(); - Response resp = f.get(3, TimeUnit.SECONDS); - assertNotNull(resp); - assertNotNull(resp.getHeader("X-Auth")); - assertEquals(resp.getStatusCode(), HttpServletResponse.SC_OK); - assertEquals(resp.getResponseBody(), fileContent); - client.close(); + try { + ClassLoader cl = getClass().getClassLoader(); + // override system properties + URL url = cl.getResource("SimpleTextFile.txt"); + File file = new File(url.toURI()); + final String fileContent = getFileContent(file); + + AsyncHttpClient.BoundRequestBuilder r = client.preparePost(getTargetUrl()).setBody(file).setRealm((new Realm.RealmBuilder()).setPrincipal(user).setPassword(admin).build()); + + Future f = r.execute(); + Response resp = f.get(3, TimeUnit.SECONDS); + assertNotNull(resp); + assertNotNull(resp.getHeader("X-Auth")); + assertEquals(resp.getStatusCode(), HttpServletResponse.SC_OK); + assertEquals(resp.getResponseBody(), fileContent); + } finally { + client.close(); + } } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void basicAuthAsyncConfigTest() throws Throwable { - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder() - .setRealm((new Realm.RealmBuilder()).setPrincipal(user).setPassword(admin).build()).build()); - ClassLoader cl = getClass().getClassLoader(); - // override system properties - URL url = cl.getResource("SimpleTextFile.txt"); - File file = new File(url.toURI()); - final String fileContent = getFileContent(file); - - AsyncHttpClient.BoundRequestBuilder r = client.preparePost(getTargetUrl()).setBody(file); - - Future f = r.execute(); - Response resp = f.get(3, TimeUnit.SECONDS); - assertNotNull(resp); - assertNotNull(resp.getHeader("X-Auth")); - assertEquals(resp.getStatusCode(), HttpServletResponse.SC_OK); - assertEquals(resp.getResponseBody(), fileContent); - client.close(); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRealm((new Realm.RealmBuilder()).setPrincipal(user).setPassword(admin).build()).build()); + try { + ClassLoader cl = getClass().getClassLoader(); + // override system properties + URL url = cl.getResource("SimpleTextFile.txt"); + File file = new File(url.toURI()); + final String fileContent = getFileContent(file); + + AsyncHttpClient.BoundRequestBuilder r = client.preparePost(getTargetUrl()).setBody(file); + + Future f = r.execute(); + Response resp = f.get(3, TimeUnit.SECONDS); + assertNotNull(resp); + assertNotNull(resp.getHeader("X-Auth")); + assertEquals(resp.getStatusCode(), HttpServletResponse.SC_OK); + assertEquals(resp.getResponseBody(), fileContent); + } finally { + client.close(); + } } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void basicAuthFileNoKeepAliveTest() throws Throwable { AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setAllowPoolingConnection(false).build()); - ClassLoader cl = getClass().getClassLoader(); - // override system properties - URL url = cl.getResource("SimpleTextFile.txt"); - File file = new File(url.toURI()); - final String fileContent = getFileContent(file); - - AsyncHttpClient.BoundRequestBuilder r = client.preparePost(getTargetUrl()) - .setBody(file).setRealm((new Realm.RealmBuilder()).setPrincipal(user).setPassword(admin).build()); - - Future f = r.execute(); - Response resp = f.get(3, TimeUnit.SECONDS); - assertNotNull(resp); - assertNotNull(resp.getHeader("X-Auth")); - assertEquals(resp.getStatusCode(), HttpServletResponse.SC_OK); - assertEquals(resp.getResponseBody(), fileContent); - client.close(); + try { + ClassLoader cl = getClass().getClassLoader(); + // override system properties + URL url = cl.getResource("SimpleTextFile.txt"); + File file = new File(url.toURI()); + final String fileContent = getFileContent(file); + + AsyncHttpClient.BoundRequestBuilder r = client.preparePost(getTargetUrl()).setBody(file).setRealm((new Realm.RealmBuilder()).setPrincipal(user).setPassword(admin).build()); + + Future f = r.execute(); + Response resp = f.get(3, TimeUnit.SECONDS); + assertNotNull(resp); + assertNotNull(resp.getHeader("X-Auth")); + assertEquals(resp.getStatusCode(), HttpServletResponse.SC_OK); + assertEquals(resp.getResponseBody(), fileContent); + } finally { + client.close(); + } } @Override @@ -471,40 +473,37 @@ public AbstractHandler configureHandler() throws Exception { return new SimpleHandler(); } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void StringBufferBodyConsumerTest() throws Throwable { - - SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder() - .setRealmPrincipal(user) - .setRealmPassword(admin) - .setUrl(getTargetUrl()) - .setHeader("Content-Type", "text/html").build(); - - StringBuilder s = new StringBuilder(); - Future future = client.post(new InputStreamBodyGenerator(new ByteArrayInputStream(MY_MESSAGE.getBytes())), new AppendableBodyConsumer(s)); - - System.out.println("waiting for response"); - Response response = future.get(); - assertEquals(response.getStatusCode(), 200); - assertEquals(s.toString(), MY_MESSAGE); - assertEquals(response.getStatusCode(), HttpServletResponse.SC_OK); - assertNotNull(response.getHeader("X-Auth")); - - client.close(); + SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setRealmPrincipal(user).setRealmPassword(admin).setUrl(getTargetUrl()).setHeader("Content-Type", "text/html").build(); + try { + StringBuilder s = new StringBuilder(); + Future future = client.post(new InputStreamBodyGenerator(new ByteArrayInputStream(MY_MESSAGE.getBytes())), new AppendableBodyConsumer(s)); + + System.out.println("waiting for response"); + Response response = future.get(); + assertEquals(response.getStatusCode(), 200); + assertEquals(s.toString(), MY_MESSAGE); + assertEquals(response.getStatusCode(), HttpServletResponse.SC_OK); + assertNotNull(response.getHeader("X-Auth")); + } finally { + client.close(); + } } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void noneAuthTest() throws IOException, ExecutionException, TimeoutException, InterruptedException { AsyncHttpClient client = getAsyncHttpClient(null); - AsyncHttpClient.BoundRequestBuilder r = client.prepareGet(getTargetUrl()) - .setRealm((new Realm.RealmBuilder()).setPrincipal(user).setPassword(admin).build()); - - Future f = r.execute(); - Response resp = f.get(3, TimeUnit.SECONDS); - assertNotNull(resp); - assertNotNull(resp.getHeader("X-Auth")); - assertEquals(resp.getStatusCode(), HttpServletResponse.SC_OK); - client.close(); + try { + AsyncHttpClient.BoundRequestBuilder r = client.prepareGet(getTargetUrl()).setRealm((new Realm.RealmBuilder()).setPrincipal(user).setPassword(admin).build()); + + Future f = r.execute(); + Response resp = f.get(3, TimeUnit.SECONDS); + assertNotNull(resp); + assertNotNull(resp.getHeader("X-Auth")); + assertEquals(resp.getStatusCode(), HttpServletResponse.SC_OK); + } finally { + client.close(); + } } } - diff --git a/src/test/java/com/ning/http/client/async/BasicHttpsTest.java b/src/test/java/com/ning/http/client/async/BasicHttpsTest.java index a9a54f20de..2d2c180fd2 100644 --- a/src/test/java/com/ning/http/client/async/BasicHttpsTest.java +++ b/src/test/java/com/ning/http/client/async/BasicHttpsTest.java @@ -65,10 +65,7 @@ public abstract class BasicHttpsTest extends AbstractBasicTest { public static class EchoHandler extends AbstractHandler { /* @Override */ - public void handle(String pathInContext, - Request r, - HttpServletRequest httpRequest, - HttpServletResponse httpResponse) throws ServletException, IOException { + public void handle(String pathInContext, Request r, HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws ServletException, IOException { httpResponse.setContentType("text/html; charset=utf-8"); Enumeration e = httpRequest.getHeaderNames(); @@ -124,7 +121,7 @@ public void handle(String pathInContext, byte[] bytes = new byte[size]; int pos = 0; if (bytes.length > 0) { - //noinspection ResultOfMethodCallIgnored + // noinspection ResultOfMethodCallIgnored int read = 0; while (read != -1) { read = httpRequest.getInputStream().read(bytes, pos, bytes.length - pos); @@ -167,8 +164,7 @@ protected int findFreePort() throws IOException { socket = new ServerSocket(0); return socket.getLocalPort(); - } - finally { + } finally { if (socket != null) { socket.close(); } @@ -209,111 +205,95 @@ public void setUpGlobal() throws Exception { log.info("Local HTTP server started successfully"); } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void zeroCopyPostTest() throws Throwable { - final AsyncHttpClient client = getAsyncHttpClient(new Builder().setSSLContext(createSSLContext()).build()); - - ClassLoader cl = getClass().getClassLoader(); - // override system properties - URL url = cl.getResource("SimpleTextFile.txt"); - File file = new File(url.toURI()); - - Future f = client.preparePost(getTargetUrl()).setBody(file).setHeader("Content-Type", "text/html").execute(); - Response resp = f.get(); - assertNotNull(resp); - assertEquals(resp.getStatusCode(), HttpServletResponse.SC_OK); - assertEquals(resp.getResponseBody(), "This is a simple test file"); - client.close(); + try { + ClassLoader cl = getClass().getClassLoader(); + // override system properties + URL url = cl.getResource("SimpleTextFile.txt"); + File file = new File(url.toURI()); + + Future f = client.preparePost(getTargetUrl()).setBody(file).setHeader("Content-Type", "text/html").execute(); + Response resp = f.get(); + assertNotNull(resp); + assertEquals(resp.getStatusCode(), HttpServletResponse.SC_OK); + assertEquals(resp.getResponseBody(), "This is a simple test file"); + } finally { + client.close(); + } } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void multipleSSLRequestsTest() throws Throwable { final AsyncHttpClient c = getAsyncHttpClient(new Builder().setSSLContext(createSSLContext()).build()); + try { + String body = "hello there"; - String body = "hello there"; - - // once - Response response = c.preparePost(getTargetUrl()) - .setBody(body) - .setHeader("Content-Type", "text/html") - .execute().get(TIMEOUT, TimeUnit.SECONDS); + // once + Response response = c.preparePost(getTargetUrl()).setBody(body).setHeader("Content-Type", "text/html").execute().get(TIMEOUT, TimeUnit.SECONDS); - assertEquals(response.getResponseBody(), body); + assertEquals(response.getResponseBody(), body); - // twice - response = c.preparePost(getTargetUrl()) - .setBody(body) - .setHeader("Content-Type", "text/html") - .execute().get(TIMEOUT, TimeUnit.SECONDS); + // twice + response = c.preparePost(getTargetUrl()).setBody(body).setHeader("Content-Type", "text/html").execute().get(TIMEOUT, TimeUnit.SECONDS); - assertEquals(response.getResponseBody(), body); - c.close(); + assertEquals(response.getResponseBody(), body); + } finally { + c.close(); + } } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void multipleSSLWithoutCacheTest() throws Throwable { final AsyncHttpClient c = getAsyncHttpClient(new Builder().setSSLContext(createSSLContext()).setAllowSslConnectionPool(false).build()); + try { + String body = "hello there"; + c.preparePost(getTargetUrl()).setBody(body).setHeader("Content-Type", "text/html").execute(); - String body = "hello there"; - c.preparePost(getTargetUrl()) - .setBody(body) - .setHeader("Content-Type", "text/html") - .execute(); - - c.preparePost(getTargetUrl()) - .setBody(body) - .setHeader("Content-Type", "text/html") - .execute(); + c.preparePost(getTargetUrl()).setBody(body).setHeader("Content-Type", "text/html").execute(); - Response response = c.preparePost(getTargetUrl()) - .setBody(body) - .setHeader("Content-Type", "text/html") - .execute().get(); + Response response = c.preparePost(getTargetUrl()).setBody(body).setHeader("Content-Type", "text/html").execute().get(); - assertEquals(response.getResponseBody(), body); - c.close(); + assertEquals(response.getResponseBody(), body); + } finally { + c.close(); + } } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void reconnectsAfterFailedCertificationPath() throws Throwable { final AsyncHttpClient c = getAsyncHttpClient(new Builder().setSSLContext(createSSLContext()).build()); - - final String body = "hello there"; - - TRUST_SERVER_CERT.set(false); try { - // first request fails because server certificate is rejected + final String body = "hello there"; + + TRUST_SERVER_CERT.set(false); try { - c.preparePost(getTargetUrl()) - .setBody(body) - .setHeader("Content-Type", "text/html") - .execute().get(TIMEOUT, TimeUnit.SECONDS); - } - catch (final ExecutionException e) { - Throwable cause = e.getCause(); - if (cause instanceof ConnectException) { - assertNotNull(cause.getCause()); - assertTrue(cause.getCause() instanceof SSLHandshakeException); - } else { - assertTrue(cause instanceof SSLHandshakeException); + // first request fails because server certificate is rejected + try { + c.preparePost(getTargetUrl()).setBody(body).setHeader("Content-Type", "text/html").execute().get(TIMEOUT, TimeUnit.SECONDS); + } catch (final ExecutionException e) { + Throwable cause = e.getCause(); + if (cause instanceof ConnectException) { + assertNotNull(cause.getCause()); + assertTrue(cause.getCause() instanceof SSLHandshakeException); + } else { + assertTrue(cause instanceof SSLHandshakeException); + } } - } - TRUST_SERVER_CERT.set(true); + TRUST_SERVER_CERT.set(true); - // second request should succeed - final Response response = c.preparePost(getTargetUrl()) - .setBody(body) - .setHeader("Content-Type", "text/html") - .execute().get(TIMEOUT, TimeUnit.SECONDS); + // second request should succeed + final Response response = c.preparePost(getTargetUrl()).setBody(body).setHeader("Content-Type", "text/html").execute().get(TIMEOUT, TimeUnit.SECONDS); - assertEquals(response.getResponseBody(), body); - } - finally { - TRUST_SERVER_CERT.set(true); + assertEquals(response.getResponseBody(), body); + } finally { + TRUST_SERVER_CERT.set(true); + } + } finally { + c.close(); } - c.close(); } private static SSLContext createSSLContext() { @@ -330,15 +310,14 @@ private static SSLContext createSSLContext() { // Initialize the SSLContext to work with our key managers. KeyManager[] keyManagers = kmf.getKeyManagers(); - TrustManager[] trustManagers = new TrustManager[]{DUMMY_TRUST_MANAGER}; + TrustManager[] trustManagers = new TrustManager[] { DUMMY_TRUST_MANAGER }; SecureRandom secureRandom = new SecureRandom(); SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(keyManagers, trustManagers, secureRandom); return sslContext; - } - catch (Exception e) { + } catch (Exception e) { throw new Error("Failed to initialize the server-side SSLContext", e); } } @@ -349,17 +328,14 @@ public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; } - public void checkClientTrusted( - X509Certificate[] chain, String authType) throws CertificateException { + public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { } - public void checkServerTrusted( - X509Certificate[] chain, String authType) throws CertificateException { + public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { if (!TRUST_SERVER_CERT.get()) { throw new CertificateException("Server certificate not trusted."); } } }; - } diff --git a/src/test/java/com/ning/http/client/async/BodyChunkTest.java b/src/test/java/com/ning/http/client/async/BodyChunkTest.java index 8db2bfb649..c86605f704 100644 --- a/src/test/java/com/ning/http/client/async/BodyChunkTest.java +++ b/src/test/java/com/ning/http/client/async/BodyChunkTest.java @@ -31,9 +31,8 @@ public abstract class BodyChunkTest extends AbstractBasicTest { private final static String MY_MESSAGE = "my message"; - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void negativeContentTypeTest() throws Throwable { - AsyncHttpClientConfig.Builder confbuilder = new AsyncHttpClientConfig.Builder(); confbuilder = confbuilder.setConnectionTimeoutInMs(100); confbuilder = confbuilder.setMaximumConnectionsTotal(50); @@ -41,23 +40,19 @@ public void negativeContentTypeTest() throws Throwable { // Create client AsyncHttpClient client = getAsyncHttpClient(confbuilder.build()); + try { + RequestBuilder requestBuilder = new RequestBuilder("POST").setUrl(getTargetUrl()).setHeader("Content-Type", "message/rfc822"); - RequestBuilder requestBuilder = new RequestBuilder("POST") - .setUrl(getTargetUrl()) - .setHeader("Content-Type", "message/rfc822"); - - requestBuilder.setBody(new InputStreamBodyGenerator(new ByteArrayInputStream(MY_MESSAGE.getBytes()))); + requestBuilder.setBody(new InputStreamBodyGenerator(new ByteArrayInputStream(MY_MESSAGE.getBytes()))); - Future future = client.executeRequest(requestBuilder.build()); + Future future = client.executeRequest(requestBuilder.build()); - System.out.println("waiting for response"); - Response response = future.get(); - assertEquals(response.getStatusCode(), 200); - assertEquals(response.getResponseBody(), MY_MESSAGE); - - client.close(); + System.out.println("waiting for response"); + Response response = future.get(); + assertEquals(response.getStatusCode(), 200); + assertEquals(response.getResponseBody(), MY_MESSAGE); + } finally { + client.close(); + } } - } - - diff --git a/src/test/java/com/ning/http/client/async/BodyDeferringAsyncHandlerTest.java b/src/test/java/com/ning/http/client/async/BodyDeferringAsyncHandlerTest.java index 48e1836a65..7960b0bfb2 100644 --- a/src/test/java/com/ning/http/client/async/BodyDeferringAsyncHandlerTest.java +++ b/src/test/java/com/ning/http/client/async/BodyDeferringAsyncHandlerTest.java @@ -44,9 +44,7 @@ public abstract class BodyDeferringAsyncHandlerTest extends AbstractBasicTest { public static class SlowAndBigHandler extends AbstractHandler { - public void handle(String pathInContext, Request request, - HttpServletRequest httpRequest, HttpServletResponse httpResponse) - throws IOException, ServletException { + public void handle(String pathInContext, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws IOException, ServletException { // 512MB large download // 512 * 1024 * 1024 = 536870912 @@ -56,8 +54,7 @@ public void handle(String pathInContext, Request request, httpResponse.flushBuffer(); - final boolean wantFailure = httpRequest - .getHeader("X-FAIL-TRANSFER") != null; + final boolean wantFailure = httpRequest.getHeader("X-FAIL-TRANSFER") != null; final boolean wantSlow = httpRequest.getHeader("X-SLOW") != null; OutputStream os = httpResponse.getOutputStream(); @@ -104,8 +101,7 @@ public int getByteCount() { } // simple stream copy just to "consume". It closes streams. - public static void copy(InputStream in, OutputStream out) - throws IOException { + public static void copy(InputStream in, OutputStream out) throws IOException { byte[] buf = new byte[1024]; int len; while ((len = in.read(buf)) > 0) { @@ -122,163 +118,148 @@ public AbstractHandler configureHandler() throws Exception { public AsyncHttpClientConfig getAsyncHttpClientConfig() { // for this test brevity's sake, we are limiting to 1 retries - return new AsyncHttpClientConfig.Builder().setMaxRequestRetry(0) - .setRequestTimeoutInMs(10000).build(); + return new AsyncHttpClientConfig.Builder().setMaxRequestRetry(0).setRequestTimeoutInMs(10000).build(); } @Test(groups = { "standalone", "default_provider" }) - public void deferredSimple() throws IOException, ExecutionException, - TimeoutException, InterruptedException { + public void deferredSimple() throws IOException, ExecutionException, TimeoutException, InterruptedException { AsyncHttpClient client = getAsyncHttpClient(getAsyncHttpClientConfig()); - AsyncHttpClient.BoundRequestBuilder r = client - .prepareGet("http://127.0.0.1/" + port1 + "/deferredSimple"); - - CountingOutputStream cos = new CountingOutputStream(); - BodyDeferringAsyncHandler bdah = new BodyDeferringAsyncHandler(cos); - Future f = r.execute(bdah); - Response resp = bdah.getResponse(); - assertNotNull(resp); - assertEquals(resp.getStatusCode(), HttpServletResponse.SC_OK); - assertEquals( - true, - resp.getHeader("content-length").equals( - String.valueOf(HALF_GIG))); - // we got headers only, it's probably not all yet here (we have BIG file - // downloading) - assertEquals(true, HALF_GIG >= cos.getByteCount()); - - // now be polite and wait for body arrival too (otherwise we would be - // dropping the "line" on server) - f.get(); - // it all should be here now - assertEquals(true, HALF_GIG == cos.getByteCount()); - client.close(); + try { + AsyncHttpClient.BoundRequestBuilder r = client.prepareGet("http://127.0.0.1/" + port1 + "/deferredSimple"); + + CountingOutputStream cos = new CountingOutputStream(); + BodyDeferringAsyncHandler bdah = new BodyDeferringAsyncHandler(cos); + Future f = r.execute(bdah); + Response resp = bdah.getResponse(); + assertNotNull(resp); + assertEquals(resp.getStatusCode(), HttpServletResponse.SC_OK); + assertEquals(true, resp.getHeader("content-length").equals(String.valueOf(HALF_GIG))); + // we got headers only, it's probably not all yet here (we have BIG file + // downloading) + assertEquals(true, HALF_GIG >= cos.getByteCount()); + + // now be polite and wait for body arrival too (otherwise we would be + // dropping the "line" on server) + f.get(); + // it all should be here now + assertEquals(true, HALF_GIG == cos.getByteCount()); + } finally { + client.close(); + } } @Test(groups = { "standalone", "default_provider" }, enabled = false) - public void deferredSimpleWithFailure() throws IOException, - ExecutionException, TimeoutException, InterruptedException { + public void deferredSimpleWithFailure() throws IOException, ExecutionException, TimeoutException, InterruptedException { AsyncHttpClient client = getAsyncHttpClient(getAsyncHttpClientConfig()); - AsyncHttpClient.BoundRequestBuilder r = client.prepareGet( - "http://127.0.0.1/" + port1 + "/deferredSimpleWithFailure") - .addHeader("X-FAIL-TRANSFER", Boolean.TRUE.toString()); - - CountingOutputStream cos = new CountingOutputStream(); - BodyDeferringAsyncHandler bdah = new BodyDeferringAsyncHandler(cos); - Future f = r.execute(bdah); - Response resp = bdah.getResponse(); - assertNotNull(resp); - assertEquals(resp.getStatusCode(), HttpServletResponse.SC_OK); - assertEquals( - true, - resp.getHeader("content-length").equals( - String.valueOf(HALF_GIG))); - // we got headers only, it's probably not all yet here (we have BIG file - // downloading) - assertEquals(true, HALF_GIG >= cos.getByteCount()); - - // now be polite and wait for body arrival too (otherwise we would be - // dropping the "line" on server) try { - f.get(); - Assert.fail("get() should fail with IOException!"); - } catch (Exception e) { - // good + AsyncHttpClient.BoundRequestBuilder r = client.prepareGet("http://127.0.0.1/" + port1 + "/deferredSimpleWithFailure").addHeader("X-FAIL-TRANSFER", Boolean.TRUE.toString()); + + CountingOutputStream cos = new CountingOutputStream(); + BodyDeferringAsyncHandler bdah = new BodyDeferringAsyncHandler(cos); + Future f = r.execute(bdah); + Response resp = bdah.getResponse(); + assertNotNull(resp); + assertEquals(resp.getStatusCode(), HttpServletResponse.SC_OK); + assertEquals(true, resp.getHeader("content-length").equals(String.valueOf(HALF_GIG))); + // we got headers only, it's probably not all yet here (we have BIG file + // downloading) + assertEquals(true, HALF_GIG >= cos.getByteCount()); + + // now be polite and wait for body arrival too (otherwise we would be + // dropping the "line" on server) + try { + f.get(); + Assert.fail("get() should fail with IOException!"); + } catch (Exception e) { + // good + } + // it's incomplete, there was an error + assertEquals(false, HALF_GIG == cos.getByteCount()); + } finally { + client.close(); } - // it's incomplete, there was an error - assertEquals(false, HALF_GIG == cos.getByteCount()); - client.close(); } @Test(groups = { "standalone", "default_provider" }) - public void deferredInputStreamTrick() throws IOException, - ExecutionException, TimeoutException, InterruptedException { + public void deferredInputStreamTrick() throws IOException, ExecutionException, TimeoutException, InterruptedException { AsyncHttpClient client = getAsyncHttpClient(getAsyncHttpClientConfig()); - AsyncHttpClient.BoundRequestBuilder r = client - .prepareGet("http://127.0.0.1/" + port1 - + "/deferredInputStreamTrick"); - - PipedOutputStream pos = new PipedOutputStream(); - PipedInputStream pis = new PipedInputStream(pos); - BodyDeferringAsyncHandler bdah = new BodyDeferringAsyncHandler(pos); - - Future f = r.execute(bdah); - - BodyDeferringInputStream is = new BodyDeferringInputStream(f, bdah, pis); - - Response resp = is.getAsapResponse(); - assertNotNull(resp); - assertEquals(resp.getStatusCode(), HttpServletResponse.SC_OK); - assertEquals( - true, - resp.getHeader("content-length").equals( - String.valueOf(HALF_GIG))); - // "consume" the body, but our code needs input stream - CountingOutputStream cos = new CountingOutputStream(); - copy(is, cos); - - // now we don't need to be polite, since consuming and closing - // BodyDeferringInputStream does all. - // it all should be here now - assertEquals(true, HALF_GIG == cos.getByteCount()); - client.close(); + try { + AsyncHttpClient.BoundRequestBuilder r = client.prepareGet("http://127.0.0.1/" + port1 + "/deferredInputStreamTrick"); + + PipedOutputStream pos = new PipedOutputStream(); + PipedInputStream pis = new PipedInputStream(pos); + BodyDeferringAsyncHandler bdah = new BodyDeferringAsyncHandler(pos); + + Future f = r.execute(bdah); + + BodyDeferringInputStream is = new BodyDeferringInputStream(f, bdah, pis); + + Response resp = is.getAsapResponse(); + assertNotNull(resp); + assertEquals(resp.getStatusCode(), HttpServletResponse.SC_OK); + assertEquals(true, resp.getHeader("content-length").equals(String.valueOf(HALF_GIG))); + // "consume" the body, but our code needs input stream + CountingOutputStream cos = new CountingOutputStream(); + copy(is, cos); + + // now we don't need to be polite, since consuming and closing + // BodyDeferringInputStream does all. + // it all should be here now + assertEquals(true, HALF_GIG == cos.getByteCount()); + } finally { + client.close(); + } } @Test(groups = { "standalone", "default_provider" }) - public void deferredInputStreamTrickWithFailure() throws IOException, - ExecutionException, TimeoutException, InterruptedException { + public void deferredInputStreamTrickWithFailure() throws IOException, ExecutionException, TimeoutException, InterruptedException { AsyncHttpClient client = getAsyncHttpClient(getAsyncHttpClientConfig()); - AsyncHttpClient.BoundRequestBuilder r = client.prepareGet( - "http://127.0.0.1/" + port1 - + "/deferredInputStreamTrickWithFailure").addHeader( - "X-FAIL-TRANSFER", Boolean.TRUE.toString()); - - PipedOutputStream pos = new PipedOutputStream(); - PipedInputStream pis = new PipedInputStream(pos); - BodyDeferringAsyncHandler bdah = new BodyDeferringAsyncHandler(pos); - - Future f = r.execute(bdah); - - BodyDeferringInputStream is = new BodyDeferringInputStream(f, bdah, pis); - - Response resp = is.getAsapResponse(); - assertNotNull(resp); - assertEquals(resp.getStatusCode(), HttpServletResponse.SC_OK); - assertEquals( - true, - resp.getHeader("content-length").equals( - String.valueOf(HALF_GIG))); - // "consume" the body, but our code needs input stream - CountingOutputStream cos = new CountingOutputStream(); try { - copy(is, cos); - Assert.fail("InputStream consumption should fail with IOException!"); - } catch (IOException e) { - // good! + AsyncHttpClient.BoundRequestBuilder r = client.prepareGet("http://127.0.0.1/" + port1 + "/deferredInputStreamTrickWithFailure").addHeader("X-FAIL-TRANSFER", Boolean.TRUE.toString()); + + PipedOutputStream pos = new PipedOutputStream(); + PipedInputStream pis = new PipedInputStream(pos); + BodyDeferringAsyncHandler bdah = new BodyDeferringAsyncHandler(pos); + + Future f = r.execute(bdah); + + BodyDeferringInputStream is = new BodyDeferringInputStream(f, bdah, pis); + + Response resp = is.getAsapResponse(); + assertNotNull(resp); + assertEquals(resp.getStatusCode(), HttpServletResponse.SC_OK); + assertEquals(true, resp.getHeader("content-length").equals(String.valueOf(HALF_GIG))); + // "consume" the body, but our code needs input stream + CountingOutputStream cos = new CountingOutputStream(); + try { + copy(is, cos); + Assert.fail("InputStream consumption should fail with IOException!"); + } catch (IOException e) { + // good! + } + } finally { + client.close(); } - client.close(); } @Test(groups = { "standalone", "default_provider" }) - public void testConnectionRefused() throws IOException, ExecutionException, - TimeoutException, InterruptedException { - int newPortWithoutAnyoneListening = findFreePort(); + public void testConnectionRefused() throws IOException, ExecutionException, TimeoutException, InterruptedException { AsyncHttpClient client = getAsyncHttpClient(getAsyncHttpClientConfig()); - AsyncHttpClient.BoundRequestBuilder r = client - .prepareGet("http://127.0.0.1/" + newPortWithoutAnyoneListening - + "/testConnectionRefused"); - - CountingOutputStream cos = new CountingOutputStream(); - BodyDeferringAsyncHandler bdah = new BodyDeferringAsyncHandler(cos); - r.execute(bdah); try { - bdah.getResponse(); - Assert.fail("IOException should be thrown here!"); - } catch (IOException e) { - // good + int newPortWithoutAnyoneListening = findFreePort(); + AsyncHttpClient.BoundRequestBuilder r = client.prepareGet("http://127.0.0.1/" + newPortWithoutAnyoneListening + "/testConnectionRefused"); + + CountingOutputStream cos = new CountingOutputStream(); + BodyDeferringAsyncHandler bdah = new BodyDeferringAsyncHandler(cos); + r.execute(bdah); + try { + bdah.getResponse(); + Assert.fail("IOException should be thrown here!"); + } catch (IOException e) { + // good + } + } finally { + client.close(); } - - client.close(); } - } diff --git a/src/test/java/com/ning/http/client/async/ByteBufferCapacityTest.java b/src/test/java/com/ning/http/client/async/ByteBufferCapacityTest.java index ea8e7134fb..b32caf72ce 100644 --- a/src/test/java/com/ning/http/client/async/ByteBufferCapacityTest.java +++ b/src/test/java/com/ning/http/client/async/ByteBufferCapacityTest.java @@ -12,15 +12,10 @@ */ package com.ning.http.client.async; -import com.ning.http.client.AsyncHttpClient; -import com.ning.http.client.HttpResponseBodyPart; -import com.ning.http.client.Response; -import org.eclipse.jetty.server.handler.AbstractHandler; -import org.testng.annotations.Test; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.fail; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; @@ -28,21 +23,25 @@ import java.io.OutputStream; import java.util.Enumeration; import java.util.UUID; -import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; -import static org.testng.Assert.*; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.eclipse.jetty.server.handler.AbstractHandler; +import org.testng.annotations.Test; + +import com.ning.http.client.AsyncHttpClient; +import com.ning.http.client.HttpResponseBodyPart; +import com.ning.http.client.Response; public abstract class ByteBufferCapacityTest extends AbstractBasicTest { - private static final File TMP = new File(System.getProperty("java.io.tmpdir"), "ahc-tests-" - + UUID.randomUUID().toString().substring(0, 8)); + private static final File TMP = new File(System.getProperty("java.io.tmpdir"), "ahc-tests-" + UUID.randomUUID().toString().substring(0, 8)); private class BasicHandler extends AbstractHandler { - public void handle(String s, - org.eclipse.jetty.server.Request r, - HttpServletRequest httpRequest, - HttpServletResponse httpResponse) throws IOException, ServletException { + public void handle(String s, org.eclipse.jetty.server.Request r, HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws IOException, ServletException { Enumeration e = httpRequest.getHeaderNames(); String param; @@ -76,44 +75,43 @@ public AbstractHandler configureHandler() throws Exception { return new BasicHandler(); } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void basicByteBufferTest() throws Throwable { AsyncHttpClient c = getAsyncHttpClient(null); - final AtomicBoolean completed = new AtomicBoolean(false); - - byte[] bytes = "RatherLargeFileRatherLargeFileRatherLargeFileRatherLargeFile".getBytes("UTF-16"); - long repeats = (1024 * 100 * 10 / bytes.length) + 1; - File largeFile = createTempFile(bytes, (int) repeats); - final AtomicInteger byteReceived = new AtomicInteger(); - try { - Response response = c.preparePut(getTargetUrl()).setBody(largeFile) - .execute(new AsyncCompletionHandlerAdapter() { - /* @Override */ - public STATE onBodyPartReceived(final HttpResponseBodyPart content) throws Exception { - byteReceived.addAndGet(content.getBodyByteBuffer().capacity()); - return super.onBodyPartReceived(content); - } - - }).get(); - - assertNotNull(response); - assertEquals(response.getStatusCode(), 200); - assertEquals(byteReceived.get(), largeFile.length()); - assertEquals(response.getResponseBody().length(), largeFile.length()); - - } catch (IOException ex) { - fail("Should have timed out"); + byte[] bytes = "RatherLargeFileRatherLargeFileRatherLargeFileRatherLargeFile".getBytes("UTF-16"); + long repeats = (1024 * 100 * 10 / bytes.length) + 1; + File largeFile = createTempFile(bytes, (int) repeats); + final AtomicInteger byteReceived = new AtomicInteger(); + + try { + Response response = c.preparePut(getTargetUrl()).setBody(largeFile).execute(new AsyncCompletionHandlerAdapter() { + /* @Override */ + public STATE onBodyPartReceived(final HttpResponseBodyPart content) throws Exception { + byteReceived.addAndGet(content.getBodyByteBuffer().capacity()); + return super.onBodyPartReceived(content); + } + + }).get(); + + assertNotNull(response); + assertEquals(response.getStatusCode(), 200); + assertEquals(byteReceived.get(), largeFile.length()); + assertEquals(response.getResponseBody().length(), largeFile.length()); + + } catch (IOException ex) { + fail("Should have timed out"); + } + } finally { + c.close(); } - c.close(); } public String getTargetUrl() { return String.format("http://127.0.0.1:%d/foo/test", port1); } - public static File createTempFile(byte[] pattern, int repeat) - throws IOException { + public static File createTempFile(byte[] pattern, int repeat) throws IOException { TMP.mkdirs(); TMP.deleteOnExit(); File tmpFile = File.createTempFile("tmpfile-", ".data", TMP); @@ -122,8 +120,7 @@ public static File createTempFile(byte[] pattern, int repeat) return tmpFile; } - public static void write(byte[] pattern, int repeat, File file) - throws IOException { + public static void write(byte[] pattern, int repeat, File file) throws IOException { file.deleteOnExit(); file.getParentFile().mkdirs(); FileOutputStream out = null; @@ -132,8 +129,7 @@ public static void write(byte[] pattern, int repeat, File file) for (int i = 0; i < repeat; i++) { out.write(pattern); } - } - finally { + } finally { if (out != null) { out.close(); } diff --git a/src/test/java/com/ning/http/client/async/ChunkingTest.java b/src/test/java/com/ning/http/client/async/ChunkingTest.java index 1860da24d1..9d4288e9ca 100644 --- a/src/test/java/com/ning/http/client/async/ChunkingTest.java +++ b/src/test/java/com/ning/http/client/async/ChunkingTest.java @@ -35,7 +35,7 @@ /** * Test that the url fetcher is able to communicate via a proxy - * + * * @author dominict */ abstract public class ChunkingTest extends AbstractBasicTest { @@ -58,8 +58,7 @@ abstract public class ChunkingTest extends AbstractBasicTest { baos.write(buf, 0, len); } LARGE_IMAGE_BYTES = baos.toByteArray(); - } - catch (Throwable e) { + } catch (Throwable e) { LARGE_IMAGE_BYTES = new byte[265495]; Random x = new Random(); x.nextBytes(LARGE_IMAGE_BYTES); @@ -67,20 +66,17 @@ abstract public class ChunkingTest extends AbstractBasicTest { } /** - * Tests that the custom chunked stream result in success and - * content returned that is unchunked + * Tests that the custom chunked stream result in success and content returned that is unchunked */ @Test() public void testCustomChunking() throws Throwable { doTest(true); } - private void doTest(boolean customChunkedInputStream) throws Exception { AsyncHttpClient c = null; try { - AsyncHttpClientConfig.Builder bc = - new AsyncHttpClientConfig.Builder(); + AsyncHttpClientConfig.Builder bc = new AsyncHttpClientConfig.Builder(); bc.setAllowPoolingConnection(true); bc.setMaximumConnectionsPerHost(1); @@ -89,7 +85,6 @@ private void doTest(boolean customChunkedInputStream) throws Exception { bc.setRequestTimeoutInMs(1000); bc.setFollowRedirects(true); - c = getAsyncHttpClient(bc.build()); RequestBuilder builder = new RequestBuilder("POST"); @@ -120,14 +115,13 @@ private void doTest(boolean customChunkedInputStream) throws Exception { } else { assertEquals(LARGE_IMAGE_BYTES, readInputStreamToBytes(res.getResponseBodyAsStream())); } - } - catch (Exception e) { + } catch (Exception e) { fail("Exception Thrown:" + e.getMessage()); } - } - finally { - if (c != null) c.close(); + } finally { + if (c != null) + c.close(); } } @@ -143,11 +137,9 @@ private byte[] readInputStreamToBytes(InputStream stream) { } buffer.flush(); data = buffer.toByteArray(); - } - catch (Exception e) { + } catch (Exception e) { - } - finally { + } finally { try { stream.close(); } catch (Exception e2) { diff --git a/src/test/java/com/ning/http/client/async/ComplexClientTest.java b/src/test/java/com/ning/http/client/async/ComplexClientTest.java index 6b7a30ffa5..b52e9431b9 100644 --- a/src/test/java/com/ning/http/client/async/ComplexClientTest.java +++ b/src/test/java/com/ning/http/client/async/ComplexClientTest.java @@ -25,44 +25,38 @@ public abstract class ComplexClientTest extends AbstractBasicTest { - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void multipleRequestsTest() throws Throwable { AsyncHttpClient c = getAsyncHttpClient(null); + try { + String body = "hello there"; - String body = "hello there"; + // once + Response response = c.preparePost(getTargetUrl()).setBody(body).setHeader("Content-Type", "text/html").execute().get(TIMEOUT, TimeUnit.SECONDS); - // once - Response response = c.preparePost(getTargetUrl()) - .setBody(body) - .setHeader("Content-Type", "text/html") - .execute().get(TIMEOUT, TimeUnit.SECONDS); + assertEquals(response.getResponseBody(), body); - assertEquals(response.getResponseBody(), body); + // twice + response = c.preparePost(getTargetUrl()).setBody(body).setHeader("Content-Type", "text/html").execute().get(TIMEOUT, TimeUnit.SECONDS); - // twice - response = c.preparePost(getTargetUrl()) - .setBody(body) - .setHeader("Content-Type", "text/html") - .execute().get(TIMEOUT, TimeUnit.SECONDS); - - assertEquals(response.getResponseBody(), body); - c.close(); + assertEquals(response.getResponseBody(), body); + } finally { + c.close(); + } } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void urlWithoutSlashTest() throws Throwable { AsyncHttpClient c = getAsyncHttpClient(null); + try { + String body = "hello there"; - String body = "hello there"; - - // once - Response response = c.preparePost(String.format("http://127.0.0.1:%d/foo/test", port1)) - .setBody(body) - .setHeader("Content-Type", "text/html") - .execute().get(TIMEOUT, TimeUnit.SECONDS); + // once + Response response = c.preparePost(String.format("http://127.0.0.1:%d/foo/test", port1)).setBody(body).setHeader("Content-Type", "text/html").execute().get(TIMEOUT, TimeUnit.SECONDS); - assertEquals(response.getResponseBody(), body); - c.close(); + assertEquals(response.getResponseBody(), body); + } finally { + c.close(); + } } - } diff --git a/src/test/java/com/ning/http/client/async/ConnectionPoolTest.java b/src/test/java/com/ning/http/client/async/ConnectionPoolTest.java index 184992d572..1a329be84e 100644 --- a/src/test/java/com/ning/http/client/async/ConnectionPoolTest.java +++ b/src/test/java/com/ning/http/client/async/ConnectionPoolTest.java @@ -43,106 +43,97 @@ public abstract class ConnectionPoolTest extends AbstractBasicTest { protected final Logger log = LoggerFactory.getLogger(AbstractBasicTest.class); - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void testMaxTotalConnections() { - AsyncHttpClient client = getAsyncHttpClient( - new AsyncHttpClientConfig.Builder() - .setAllowPoolingConnection(true) - .setMaximumConnectionsTotal(1) - .build() - ); - - String url = getTargetUrl(); - int i; - Exception exception = null; - for (i = 0; i < 3; i++) { - try { - log.info("{} requesting url [{}]...", i, url); - Response response = client.prepareGet(url).execute().get(); - log.info("{} response [{}].", i, response); - } catch (Exception ex) { - exception = ex; + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setAllowPoolingConnection(true).setMaximumConnectionsTotal(1).build()); + try { + String url = getTargetUrl(); + int i; + Exception exception = null; + for (i = 0; i < 3; i++) { + try { + log.info("{} requesting url [{}]...", i, url); + Response response = client.prepareGet(url).execute().get(); + log.info("{} response [{}].", i, response); + } catch (Exception ex) { + exception = ex; + } } + assertNull(exception); + } finally { + client.close(); } - assertNull(exception); - client.close(); } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void testMaxTotalConnectionsException() { - AsyncHttpClient client = getAsyncHttpClient( - new AsyncHttpClientConfig.Builder() - .setAllowPoolingConnection(true) - .setMaximumConnectionsTotal(1) - .build() - ); - - String url = getTargetUrl(); - int i; - Exception exception = null; - for (i = 0; i < 20; i++) { - try { - log.info("{} requesting url [{}]...", i, url); - - if (i < 5) { - client.prepareGet(url).execute().get(); - } else { - client.prepareGet(url).execute(); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setAllowPoolingConnection(true).setMaximumConnectionsTotal(1).build()); + try { + String url = getTargetUrl(); + int i; + Exception exception = null; + for (i = 0; i < 20; i++) { + try { + log.info("{} requesting url [{}]...", i, url); + + if (i < 5) { + client.prepareGet(url).execute().get(); + } else { + client.prepareGet(url).execute(); + } + } catch (Exception ex) { + exception = ex; + break; } - } catch (Exception ex) { - exception = ex; - break; } + assertNotNull(exception); + assertNotNull(exception.getMessage()); + assertEquals(exception.getMessage(), "Too many connections 1"); + } finally { + client.close(); } - assertNotNull(exception); - assertNotNull(exception.getMessage()); - assertEquals(exception.getMessage(),"Too many connections 1"); - client.close(); } - @Test(groups = {"standalone", "default_provider", "async"}, enabled = true, invocationCount = 10, alwaysRun = true) + @Test(groups = { "standalone", "default_provider", "async" }, enabled = true, invocationCount = 10, alwaysRun = true) public void asyncDoGetKeepAliveHandlerTest_channelClosedDoesNotFail() throws Throwable { AsyncHttpClient client = getAsyncHttpClient(null); + try { + // Use a l in case the assert fail + final CountDownLatch l = new CountDownLatch(2); - // Use a l in case the assert fail - final CountDownLatch l = new CountDownLatch(2); - - final Map remoteAddresses = new - ConcurrentHashMap(); + final Map remoteAddresses = new ConcurrentHashMap(); - AsyncCompletionHandler handler = new - AsyncCompletionHandlerAdapter() { + AsyncCompletionHandler handler = new AsyncCompletionHandlerAdapter() { - @Override - public Response onCompleted(Response response) throws - Exception { - System.out.println("ON COMPLETED INVOKED " + - response.getHeader("X-KEEP-ALIVE")); - try { - assertEquals(response.getStatusCode(), 200); - remoteAddresses.put(response.getHeader("X-KEEP-ALIVE"), true); - } finally { - l.countDown(); - } - return response; + @Override + public Response onCompleted(Response response) throws Exception { + System.out.println("ON COMPLETED INVOKED " + response.getHeader("X-KEEP-ALIVE")); + try { + assertEquals(response.getStatusCode(), 200); + remoteAddresses.put(response.getHeader("X-KEEP-ALIVE"), true); + } finally { + l.countDown(); } - }; + return response; + } + }; - client.prepareGet(getTargetUrl()).execute(handler).get(); - server.stop(); - server.start(); - client.prepareGet(getTargetUrl()).execute(handler); + client.prepareGet(getTargetUrl()).execute(handler).get(); + server.stop(); + server.start(); + client.prepareGet(getTargetUrl()).execute(handler); + if (!l.await(TIMEOUT, TimeUnit.SECONDS)) { + Assert.fail("Timed out"); + } - if (!l.await(TIMEOUT, TimeUnit.SECONDS)) { - Assert.fail("Timed out"); + assertEquals(remoteAddresses.size(), 2); + } finally { + client.close(); } - - assertEquals(remoteAddresses.size(), 2); - client.close(); } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void testInvalidConnectionsPool() { ConnectionsPool cp = new ConnectionsPool() { @@ -168,25 +159,23 @@ public void destroy() { } }; - AsyncHttpClient client = getAsyncHttpClient( - new AsyncHttpClientConfig.Builder() - .setConnectionsPool(cp) - .build() - ); - - Exception exception = null; + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setConnectionsPool(cp).build()); try { - client.prepareGet(getTargetUrl()).execute().get(TIMEOUT, TimeUnit.SECONDS); - } catch (Exception ex) { - ex.printStackTrace(); - exception = ex; + Exception exception = null; + try { + client.prepareGet(getTargetUrl()).execute().get(TIMEOUT, TimeUnit.SECONDS); + } catch (Exception ex) { + ex.printStackTrace(); + exception = ex; + } + assertNotNull(exception); + assertEquals(exception.getMessage(), "Too many connections -1"); + } finally { + client.close(); } - assertNotNull(exception); - assertEquals(exception.getMessage(), "Too many connections -1"); - client.close(); } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void testValidConnectionsPool() { ConnectionsPool cp = new ConnectionsPool() { @@ -212,153 +201,150 @@ public void destroy() { } }; - AsyncHttpClient client = getAsyncHttpClient( - new AsyncHttpClientConfig.Builder() - .setConnectionsPool(cp) - .build() - ); - - Exception exception = null; + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setConnectionsPool(cp).build()); try { - client.prepareGet(getTargetUrl()).execute().get(TIMEOUT, TimeUnit.SECONDS); - } catch (Exception ex) { - ex.printStackTrace(); - exception = ex; + Exception exception = null; + try { + client.prepareGet(getTargetUrl()).execute().get(TIMEOUT, TimeUnit.SECONDS); + } catch (Exception ex) { + ex.printStackTrace(); + exception = ex; + } + assertNull(exception); + } finally { + client.close(); } - assertNull(exception); - client.close(); } - - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void multipleMaxConnectionOpenTest() throws Throwable { - AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setAllowPoolingConnection(true) - .setConnectionTimeoutInMs(5000).setMaximumConnectionsTotal(1).build(); + AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setAllowPoolingConnection(true).setConnectionTimeoutInMs(5000).setMaximumConnectionsTotal(1).build(); AsyncHttpClient c = getAsyncHttpClient(cg); + try { + String body = "hello there"; - String body = "hello there"; - - // once - Response response = c.preparePost(getTargetUrl()) - .setBody(body) - .execute().get(TIMEOUT, TimeUnit.SECONDS); + // once + Response response = c.preparePost(getTargetUrl()).setBody(body).execute().get(TIMEOUT, TimeUnit.SECONDS); - assertEquals(response.getResponseBody(), body); + assertEquals(response.getResponseBody(), body); - // twice - Exception exception = null; - try { - c.preparePost(String.format("http://127.0.0.1:%d/foo/test", port2)).setBody(body).execute().get(TIMEOUT, TimeUnit.SECONDS); - fail("Should throw exception. Too many connections issued."); - } catch (Exception ex) { - ex.printStackTrace(); - exception = ex; + // twice + Exception exception = null; + try { + c.preparePost(String.format("http://127.0.0.1:%d/foo/test", port2)).setBody(body).execute().get(TIMEOUT, TimeUnit.SECONDS); + fail("Should throw exception. Too many connections issued."); + } catch (Exception ex) { + ex.printStackTrace(); + exception = ex; + } + assertNotNull(exception); + assertEquals(exception.getMessage(), "Too many connections 1"); + } finally { + c.close(); } - assertNotNull(exception); - assertEquals(exception.getMessage(), "Too many connections 1"); - c.close(); } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void multipleMaxConnectionOpenTestWithQuery() throws Throwable { - AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setAllowPoolingConnection(true) - .setConnectionTimeoutInMs(5000).setMaximumConnectionsTotal(1).build(); + AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setAllowPoolingConnection(true).setConnectionTimeoutInMs(5000).setMaximumConnectionsTotal(1).build(); AsyncHttpClient c = getAsyncHttpClient(cg); + try { + String body = "hello there"; - String body = "hello there"; - - // once - Response response = c.preparePost(getTargetUrl() + "?foo=bar") - .setBody(body) - .execute().get(TIMEOUT, TimeUnit.SECONDS); + // once + Response response = c.preparePost(getTargetUrl() + "?foo=bar").setBody(body).execute().get(TIMEOUT, TimeUnit.SECONDS); - assertEquals(response.getResponseBody(), "foo_" + body); + assertEquals(response.getResponseBody(), "foo_" + body); - // twice - Exception exception = null; - try { - response = c.preparePost(getTargetUrl()).setBody(body).execute().get(TIMEOUT, TimeUnit.SECONDS); - } catch (Exception ex) { - ex.printStackTrace(); - exception = ex; + // twice + Exception exception = null; + try { + response = c.preparePost(getTargetUrl()).setBody(body).execute().get(TIMEOUT, TimeUnit.SECONDS); + } catch (Exception ex) { + ex.printStackTrace(); + exception = ex; + } + assertNull(exception); + assertNotNull(response); + assertEquals(response.getStatusCode(), 200); + } finally { + c.close(); } - assertNull(exception); - assertNotNull(response); - assertEquals(response.getStatusCode(), 200); - c.close(); } /** - * This test just make sure the hack used to catch disconnected channel under win7 doesn't throw any exception. - * The onComplete method must be only called once. - * - * @throws Throwable if something wrong happens. + * This test just make sure the hack used to catch disconnected channel under win7 doesn't throw any exception. The onComplete method must be only called once. + * + * @throws Throwable + * if something wrong happens. */ - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void win7DisconnectTest() throws Throwable { final AtomicInteger count = new AtomicInteger(0); AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().build()); - AsyncCompletionHandler handler = new - AsyncCompletionHandlerAdapter() { + try { + AsyncCompletionHandler handler = new AsyncCompletionHandlerAdapter() { - @Override - public Response onCompleted(Response response) throws - Exception { - - count.incrementAndGet(); - StackTraceElement e = new StackTraceElement("sun.nio.ch.SocketDispatcher", "read0", null, -1); - IOException t = new IOException(); - t.setStackTrace(new StackTraceElement[]{e}); - throw t; - } - }; + @Override + public Response onCompleted(Response response) throws Exception { - try { - client.prepareGet(getTargetUrl()).execute(handler).get(); - fail("Must have received an exception"); - } catch (ExecutionException ex) { - assertNotNull(ex); - assertNotNull(ex.getCause()); - assertEquals(ex.getCause().getCause().getClass(), IOException.class); - assertEquals(count.get(), 1); + count.incrementAndGet(); + StackTraceElement e = new StackTraceElement("sun.nio.ch.SocketDispatcher", "read0", null, -1); + IOException t = new IOException(); + t.setStackTrace(new StackTraceElement[] { e }); + throw t; + } + }; + + try { + client.prepareGet(getTargetUrl()).execute(handler).get(); + fail("Must have received an exception"); + } catch (ExecutionException ex) { + assertNotNull(ex); + assertNotNull(ex.getCause()); + assertEquals(ex.getCause().getCause().getClass(), IOException.class); + assertEquals(count.get(), 1); + } + } finally { + client.close(); } - client.close(); } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void asyncHandlerOnThrowableTest() throws Throwable { AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().build()); - final AtomicInteger count = new AtomicInteger(); - final String THIS_IS_NOT_FOR_YOU = "This is not for you"; - final CountDownLatch latch = new CountDownLatch(16); - for (int i = 0; i < 16; i++) { - client.prepareGet(getTargetUrl()).execute(new AsyncCompletionHandlerBase() { - @Override - public Response onCompleted(Response response) throws Exception { - throw new Exception(THIS_IS_NOT_FOR_YOU); - } - }); + try { + final AtomicInteger count = new AtomicInteger(); + final String THIS_IS_NOT_FOR_YOU = "This is not for you"; + final CountDownLatch latch = new CountDownLatch(16); + for (int i = 0; i < 16; i++) { + client.prepareGet(getTargetUrl()).execute(new AsyncCompletionHandlerBase() { + @Override + public Response onCompleted(Response response) throws Exception { + throw new Exception(THIS_IS_NOT_FOR_YOU); + } + }); - client.prepareGet(getTargetUrl()).execute(new AsyncCompletionHandlerBase() { - /* @Override */ - public void onThrowable(Throwable t) { - if (t.getMessage() != null && t.getMessage().equalsIgnoreCase(THIS_IS_NOT_FOR_YOU)) { - count.incrementAndGet(); + client.prepareGet(getTargetUrl()).execute(new AsyncCompletionHandlerBase() { + /* @Override */ + public void onThrowable(Throwable t) { + if (t.getMessage() != null && t.getMessage().equalsIgnoreCase(THIS_IS_NOT_FOR_YOU)) { + count.incrementAndGet(); + } } - } - @Override - public Response onCompleted(Response response) throws Exception { - latch.countDown(); - return response; - } - }); + @Override + public Response onCompleted(Response response) throws Exception { + latch.countDown(); + return response; + } + }); + } + latch.await(TIMEOUT, TimeUnit.SECONDS); + assertEquals(count.get(), 0); + } finally { + client.close(); } - latch.await(TIMEOUT, TimeUnit.SECONDS); - assertEquals(count.get(), 0); - client.close(); } - } - diff --git a/src/test/java/com/ning/http/client/async/DigestAuthTest.java b/src/test/java/com/ning/http/client/async/DigestAuthTest.java index 293139e107..66d1ce3086 100644 --- a/src/test/java/com/ning/http/client/async/DigestAuthTest.java +++ b/src/test/java/com/ning/http/client/async/DigestAuthTest.java @@ -38,7 +38,6 @@ import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.ArrayList; -import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -61,8 +60,7 @@ public void setUpGlobal() throws Exception { server = new Server(); Logger root = Logger.getRootLogger(); root.setLevel(Level.DEBUG); - root.addAppender(new ConsoleAppender( - new PatternLayout(PatternLayout.TTCC_CONVERSION_PATTERN))); + root.addAppender(new ConsoleAppender(new PatternLayout(PatternLayout.TTCC_CONVERSION_PATTERN))); port1 = findFreePort(); Connector listener = new SelectChannelConnector(); @@ -77,7 +75,7 @@ public void setUpGlobal() throws Exception { Constraint constraint = new Constraint(); constraint.setName(Constraint.__BASIC_AUTH); - constraint.setRoles(new String[]{user, admin}); + constraint.setRoles(new String[] { user, admin }); constraint.setAuthenticate(true); ConstraintMapping mapping = new ConstraintMapping(); @@ -104,10 +102,7 @@ public void setUpGlobal() throws Exception { } private class SimpleHandler extends AbstractHandler { - public void handle(String s, - Request r, - HttpServletRequest request, - HttpServletResponse response) throws IOException, ServletException { + public void handle(String s, Request r, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { response.addHeader("X-Auth", request.getHeader("Authorization")); response.setStatus(200); @@ -116,50 +111,51 @@ public void handle(String s, } } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void digestAuthTest() throws IOException, ExecutionException, TimeoutException, InterruptedException { AsyncHttpClient client = getAsyncHttpClient(null); - AsyncHttpClient.BoundRequestBuilder r = client.prepareGet("http://127.0.0.1/" + port1 + "/") - .setRealm((new Realm.RealmBuilder()).setPrincipal(user) - .setPassword(admin) - .setRealmName("MyRealm") - .setScheme(Realm.AuthScheme.DIGEST).build()); - - Future f = r.execute(); - Response resp = f.get(60, TimeUnit.SECONDS); - assertNotNull(resp); - assertEquals(resp.getStatusCode(), HttpServletResponse.SC_OK); - assertNotNull(resp.getHeader("X-Auth")); - client.close(); + try { + AsyncHttpClient.BoundRequestBuilder r = client.prepareGet("http://127.0.0.1/" + port1 + "/").setRealm((new Realm.RealmBuilder()).setPrincipal(user).setPassword(admin).setRealmName("MyRealm").setScheme(Realm.AuthScheme.DIGEST).build()); + + Future f = r.execute(); + Response resp = f.get(60, TimeUnit.SECONDS); + assertNotNull(resp); + assertEquals(resp.getStatusCode(), HttpServletResponse.SC_OK); + assertNotNull(resp.getHeader("X-Auth")); + } finally { + client.close(); + } } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void digestAuthTestWithoutScheme() throws IOException, ExecutionException, TimeoutException, InterruptedException { AsyncHttpClient client = getAsyncHttpClient(null); - AsyncHttpClient.BoundRequestBuilder r = client.prepareGet("http://127.0.0.1/" + port1 + "/") - .setRealm((new Realm.RealmBuilder()).setPrincipal(user) - .setPassword(admin) - .setRealmName("MyRealm").build()); - - Future f = r.execute(); - Response resp = f.get(60, TimeUnit.SECONDS); - assertNotNull(resp); - assertEquals(resp.getStatusCode(), HttpServletResponse.SC_OK); - assertNotNull(resp.getHeader("X-Auth")); - client.close(); + try { + AsyncHttpClient.BoundRequestBuilder r = client.prepareGet("http://127.0.0.1/" + port1 + "/").setRealm((new Realm.RealmBuilder()).setPrincipal(user).setPassword(admin).setRealmName("MyRealm").build()); + + Future f = r.execute(); + Response resp = f.get(60, TimeUnit.SECONDS); + assertNotNull(resp); + assertEquals(resp.getStatusCode(), HttpServletResponse.SC_OK); + assertNotNull(resp.getHeader("X-Auth")); + } finally { + client.close(); + } } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void digestAuthNegativeTest() throws IOException, ExecutionException, TimeoutException, InterruptedException { AsyncHttpClient client = getAsyncHttpClient(null); - AsyncHttpClient.BoundRequestBuilder r = client.prepareGet("http://127.0.0.1/" + port1 + "/") - .setRealm((new Realm.RealmBuilder()).setPrincipal("fake").setPassword(admin).setScheme(Realm.AuthScheme.DIGEST).build()); - - Future f = r.execute(); - Response resp = f.get(20, TimeUnit.SECONDS); - assertNotNull(resp); - assertEquals(resp.getStatusCode(), 401); - client.close(); + try { + AsyncHttpClient.BoundRequestBuilder r = client.prepareGet("http://127.0.0.1/" + port1 + "/").setRealm((new Realm.RealmBuilder()).setPrincipal("fake").setPassword(admin).setScheme(Realm.AuthScheme.DIGEST).build()); + + Future f = r.execute(); + Response resp = f.get(20, TimeUnit.SECONDS); + assertNotNull(resp); + assertEquals(resp.getStatusCode(), 401); + } finally { + client.close(); + } } @Override diff --git a/src/test/java/com/ning/http/client/async/EmptyBodyTest.java b/src/test/java/com/ning/http/client/async/EmptyBodyTest.java index d687a6cb26..ccec37a180 100644 --- a/src/test/java/com/ning/http/client/async/EmptyBodyTest.java +++ b/src/test/java/com/ning/http/client/async/EmptyBodyTest.java @@ -15,19 +15,12 @@ */ package com.ning.http.client.async; -import com.ning.http.client.AsyncHandler; -import com.ning.http.client.AsyncHttpClient; -import com.ning.http.client.HttpResponseBodyPart; -import com.ning.http.client.HttpResponseHeaders; -import com.ning.http.client.HttpResponseStatus; -import com.ning.http.client.Response; -import org.eclipse.jetty.server.Request; -import org.eclipse.jetty.server.handler.AbstractHandler; -import org.testng.annotations.Test; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; +import static org.testng.Assert.fail; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.InputStream; import java.util.concurrent.CountDownLatch; @@ -36,31 +29,34 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertFalse; -import static org.testng.Assert.assertTrue; -import static org.testng.Assert.assertNotNull; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; -import static org.testng.Assert.fail; +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.handler.AbstractHandler; +import org.testng.annotations.Test; + +import com.ning.http.client.AsyncHandler; +import com.ning.http.client.AsyncHttpClient; +import com.ning.http.client.HttpResponseBodyPart; +import com.ning.http.client.HttpResponseHeaders; +import com.ning.http.client.HttpResponseStatus; +import com.ning.http.client.Response; /** * Tests case where response doesn't have body. - * + * * @author Hubert Iwaniuk */ public abstract class EmptyBodyTest extends AbstractBasicTest { private class NoBodyResponseHandler extends AbstractHandler { - public void handle( - String s, - Request request, - HttpServletRequest req, - HttpServletResponse resp) - throws IOException, ServletException { + public void handle(String s, Request request, HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException { if (!req.getMethod().equalsIgnoreCase("PUT")) { resp.setStatus(HttpServletResponse.SC_OK); } else { - resp.setStatus(204); + resp.setStatus(204); } request.setHandled(true); } @@ -71,72 +67,77 @@ public AbstractHandler configureHandler() throws Exception { return new NoBodyResponseHandler(); } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void testEmptyBody() throws IOException { AsyncHttpClient ahc = getAsyncHttpClient(null); - final AtomicBoolean err = new AtomicBoolean(false); - final LinkedBlockingQueue queue = new LinkedBlockingQueue(); - final AtomicBoolean status = new AtomicBoolean(false); - final AtomicInteger headers = new AtomicInteger(0); - final CountDownLatch latch = new CountDownLatch(1); - ahc.executeRequest(ahc.prepareGet(getTargetUrl()).build(), new AsyncHandler() { - public void onThrowable(Throwable t) { - fail("Got throwable.", t); - err.set(true); - } + try { + final AtomicBoolean err = new AtomicBoolean(false); + final LinkedBlockingQueue queue = new LinkedBlockingQueue(); + final AtomicBoolean status = new AtomicBoolean(false); + final AtomicInteger headers = new AtomicInteger(0); + final CountDownLatch latch = new CountDownLatch(1); + ahc.executeRequest(ahc.prepareGet(getTargetUrl()).build(), new AsyncHandler() { + public void onThrowable(Throwable t) { + fail("Got throwable.", t); + err.set(true); + } - public STATE onBodyPartReceived(HttpResponseBodyPart e) throws Exception { - String s = new String(e.getBodyPartBytes()); - log.info("got part: {}", s); - if (s.isEmpty()) { - //noinspection ThrowableInstanceNeverThrown - log.warn("Sampling stacktrace.", - new Throwable("trace that, we should not get called for empty body.")); + public STATE onBodyPartReceived(HttpResponseBodyPart e) throws Exception { + String s = new String(e.getBodyPartBytes()); + log.info("got part: {}", s); + if (s.isEmpty()) { + // noinspection ThrowableInstanceNeverThrown + log.warn("Sampling stacktrace.", new Throwable("trace that, we should not get called for empty body.")); + } + queue.put(s); + return STATE.CONTINUE; } - queue.put(s); - return STATE.CONTINUE; - } - public STATE onStatusReceived(HttpResponseStatus e) throws Exception { - status.set(true); - return AsyncHandler.STATE.CONTINUE; - } + public STATE onStatusReceived(HttpResponseStatus e) throws Exception { + status.set(true); + return AsyncHandler.STATE.CONTINUE; + } - public STATE onHeadersReceived(HttpResponseHeaders e) throws Exception { - if (headers.incrementAndGet() == 2) { - throw new Exception("Analyze this."); + public STATE onHeadersReceived(HttpResponseHeaders e) throws Exception { + if (headers.incrementAndGet() == 2) { + throw new Exception("Analyze this."); + } + return STATE.CONTINUE; } - return STATE.CONTINUE; - } - public Object onCompleted() throws Exception { - latch.countDown(); - return null; + public Object onCompleted() throws Exception { + latch.countDown(); + return null; + } + }); + try { + assertTrue(latch.await(1, TimeUnit.SECONDS), "Latch failed."); + } catch (InterruptedException e) { + fail("Interrupted.", e); } - }); - try { - assertTrue(latch.await(1, TimeUnit.SECONDS), "Latch failed."); - } catch (InterruptedException e) { - fail("Interrupted.", e); + assertFalse(err.get()); + assertEquals(queue.size(), 0); + assertTrue(status.get()); + assertEquals(headers.get(), 1); + } finally { + ahc.close(); } - assertFalse(err.get()); - assertEquals(queue.size(), 0); - assertTrue(status.get()); - assertEquals(headers.get(), 1); - ahc.close(); } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void testPutEmptyBody() throws Throwable { AsyncHttpClient ahc = getAsyncHttpClient(null); - Response response = ahc.preparePut(getTargetUrl()).setBody("String").execute().get(); + try { + Response response = ahc.preparePut(getTargetUrl()).setBody("String").execute().get(); - assertNotNull(response); - assertEquals(response.getStatusCode(), 204); - assertEquals(response.getResponseBody(), ""); - assertTrue(InputStream.class.isAssignableFrom(response.getResponseBodyAsStream().getClass())); - assertEquals(response.getResponseBodyAsStream().read(), -1); + assertNotNull(response); + assertEquals(response.getStatusCode(), 204); + assertEquals(response.getResponseBody(), ""); + assertTrue(InputStream.class.isAssignableFrom(response.getResponseBodyAsStream().getClass())); + assertEquals(response.getResponseBodyAsStream().read(), -1); - ahc.close(); + } finally { + ahc.close(); + } } } diff --git a/src/test/java/com/ning/http/client/async/ErrorResponseTest.java b/src/test/java/com/ning/http/client/async/ErrorResponseTest.java index 0613c27ef7..c3b527736a 100644 --- a/src/test/java/com/ning/http/client/async/ErrorResponseTest.java +++ b/src/test/java/com/ning/http/client/async/ErrorResponseTest.java @@ -16,34 +16,35 @@ */ package com.ning.http.client.async; -import com.ning.http.client.AsyncHttpClient; -import com.ning.http.client.Response; -import org.eclipse.jetty.server.Request; -import org.eclipse.jetty.server.handler.AbstractHandler; -import org.testng.annotations.Test; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.OutputStream; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertNotNull; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.handler.AbstractHandler; +import org.testng.annotations.Test; + +import com.ning.http.client.AsyncHttpClient; +import com.ning.http.client.Response; /** * Tests to reproduce issues with handling of error responses - * + * * @author Tatu Saloranta */ public abstract class ErrorResponseTest extends AbstractBasicTest { final static String BAD_REQUEST_STR = "Very Bad Request! No cookies."; private static class ErrorHandler extends AbstractHandler { - public void handle(String s, Request r, - HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { + public void handle(String s, Request r, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { try { Thread.sleep(210L); } catch (InterruptedException e) { @@ -61,18 +62,18 @@ public AbstractHandler configureHandler() throws Exception { return new ErrorHandler(); } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void testQueryParameters() throws Exception { AsyncHttpClient client = getAsyncHttpClient(null); - Future f = client - .prepareGet("http://127.0.0.1/" + port1 + "/foo") - .addHeader("Accepts", "*/*") - .execute(); - Response resp = f.get(3, TimeUnit.SECONDS); - assertNotNull(resp); - assertEquals(resp.getStatusCode(), 400); - String respStr = resp.getResponseBody(); - assertEquals(BAD_REQUEST_STR, respStr); - client.close(); + try { + Future f = client.prepareGet("http://127.0.0.1/" + port1 + "/foo").addHeader("Accepts", "*/*").execute(); + Response resp = f.get(3, TimeUnit.SECONDS); + assertNotNull(resp); + assertEquals(resp.getStatusCode(), 400); + String respStr = resp.getResponseBody(); + assertEquals(BAD_REQUEST_STR, respStr); + } finally { + client.close(); + } } } diff --git a/src/test/java/com/ning/http/client/async/Expect100ContinueTest.java b/src/test/java/com/ning/http/client/async/Expect100ContinueTest.java index 8ebb82d34c..d0fd1f32d9 100644 --- a/src/test/java/com/ning/http/client/async/Expect100ContinueTest.java +++ b/src/test/java/com/ning/http/client/async/Expect100ContinueTest.java @@ -15,22 +15,24 @@ */ package com.ning.http.client.async; -import com.ning.http.client.AsyncHttpClient; -import com.ning.http.client.Response; -import org.eclipse.jetty.server.Request; -import org.eclipse.jetty.server.handler.AbstractHandler; -import org.testng.annotations.Test; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; import java.io.File; import java.io.IOException; import java.net.URL; import java.util.concurrent.Future; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertNotNull; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.handler.AbstractHandler; +import org.testng.annotations.Test; + +import com.ning.http.client.AsyncHttpClient; +import com.ning.http.client.Response; /** * Test the Expect: 100-Continue. @@ -38,10 +40,7 @@ public abstract class Expect100ContinueTest extends AbstractBasicTest { private class ZeroCopyHandler extends AbstractHandler { - public void handle(String s, - Request r, - HttpServletRequest httpRequest, - HttpServletResponse httpResponse) throws IOException, ServletException { + public void handle(String s, Request r, HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws IOException, ServletException { int size = 10 * 1024; if (httpRequest.getContentLength() > 0) { @@ -58,26 +57,26 @@ public void handle(String s, } } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void Expect100Continue() throws Throwable { AsyncHttpClient client = getAsyncHttpClient(null); + try { + ClassLoader cl = getClass().getClassLoader(); + URL url = cl.getResource("SimpleTextFile.txt"); + File file = new File(url.toURI()); - ClassLoader cl = getClass().getClassLoader(); - URL url = cl.getResource("SimpleTextFile.txt"); - File file = new File(url.toURI()); - - Future f = client.preparePut("http://127.0.0.1/" + port1 + "/").setHeader("Expect", "100-continue").setBody(file).execute(); - Response resp = f.get(); - assertNotNull(resp); - assertEquals(resp.getStatusCode(), HttpServletResponse.SC_OK); - assertEquals(resp.getResponseBody(), "This is a simple test file"); - client.close(); - + Future f = client.preparePut("http://127.0.0.1/" + port1 + "/").setHeader("Expect", "100-continue").setBody(file).execute(); + Response resp = f.get(); + assertNotNull(resp); + assertEquals(resp.getStatusCode(), HttpServletResponse.SC_OK); + assertEquals(resp.getResponseBody(), "This is a simple test file"); + } finally { + client.close(); + } } @Override public AbstractHandler configureHandler() throws Exception { return new ZeroCopyHandler(); } - } diff --git a/src/test/java/com/ning/http/client/async/FilePartLargeFileTest.java b/src/test/java/com/ning/http/client/async/FilePartLargeFileTest.java index 87dd3aa377..0f27acb0a2 100644 --- a/src/test/java/com/ning/http/client/async/FilePartLargeFileTest.java +++ b/src/test/java/com/ning/http/client/async/FilePartLargeFileTest.java @@ -12,66 +12,70 @@ */ package com.ning.http.client.async; -import com.ning.http.client.AsyncHttpClient; -import com.ning.http.client.AsyncHttpClient.BoundRequestBuilder; -import com.ning.http.client.AsyncHttpClientConfig; -import com.ning.http.client.FilePart; -import com.ning.http.client.Response; -import org.eclipse.jetty.server.Request; -import org.eclipse.jetty.server.handler.AbstractHandler; -import org.testng.Assert; -import org.testng.annotations.AfterMethod; -import org.testng.annotations.Test; +import static org.testng.FileAssert.fail; -import javax.servlet.ServletException; -import javax.servlet.ServletInputStream; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.net.URL; import java.util.UUID; -import static org.testng.FileAssert.fail; +import javax.servlet.ServletException; +import javax.servlet.ServletInputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; -public abstract class FilePartLargeFileTest - extends AbstractBasicTest { +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.handler.AbstractHandler; +import org.testng.Assert; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.Test; + +import com.ning.http.client.AsyncHttpClient; +import com.ning.http.client.AsyncHttpClient.BoundRequestBuilder; +import com.ning.http.client.AsyncHttpClientConfig; +import com.ning.http.client.FilePart; +import com.ning.http.client.Response; + +public abstract class FilePartLargeFileTest extends AbstractBasicTest { private File largeFile; - @Test(groups = {"standalone", "default_provider"}, enabled = true) - public void testPutImageFile() - throws Exception { + @Test(groups = { "standalone", "default_provider" }, enabled = true) + public void testPutImageFile() throws Exception { largeFile = getTestFile(); AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder().setRequestTimeoutInMs(100 * 6000).build(); AsyncHttpClient client = getAsyncHttpClient(config); - BoundRequestBuilder rb = client.preparePut(getTargetUrl()); - - rb.addBodyPart(new FilePart("test", largeFile, "application/octet-stream" , "UTF-8")); + try { + BoundRequestBuilder rb = client.preparePut(getTargetUrl()); - Response response = rb.execute().get(); - Assert.assertEquals(200, response.getStatusCode()); + rb.addBodyPart(new FilePart("test", largeFile, "application/octet-stream", "UTF-8")); - client.close(); + Response response = rb.execute().get(); + Assert.assertEquals(200, response.getStatusCode()); + } finally { + client.close(); + } } - @Test(groups = {"standalone", "default_provider"}, enabled = true) - public void testPutLargeTextFile() - throws Exception { + @Test(groups = { "standalone", "default_provider" }, enabled = true) + public void testPutLargeTextFile() throws Exception { byte[] bytes = "RatherLargeFileRatherLargeFileRatherLargeFileRatherLargeFile".getBytes("UTF-16"); long repeats = (1024 * 1024 / bytes.length) + 1; largeFile = createTempFile(bytes, (int) repeats); AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder().build(); AsyncHttpClient client = getAsyncHttpClient(config); - BoundRequestBuilder rb = client.preparePut(getTargetUrl()); + try { + BoundRequestBuilder rb = client.preparePut(getTargetUrl()); - rb.addBodyPart(new FilePart("test", largeFile, "application/octet-stream" , "UTF-8")); + rb.addBodyPart(new FilePart("test", largeFile, "application/octet-stream", "UTF-8")); - Response response = rb.execute().get(); - Assert.assertEquals(200, response.getStatusCode()); - client.close(); + Response response = rb.execute().get(); + Assert.assertEquals(200, response.getStatusCode()); + } finally { + client.close(); + } } private static File getTestFile() { @@ -96,12 +100,10 @@ public void after() { } @Override - public AbstractHandler configureHandler() - throws Exception { + public AbstractHandler configureHandler() throws Exception { return new AbstractHandler() { - public void handle(String arg0, Request arg1, HttpServletRequest req, HttpServletResponse resp) - throws IOException, ServletException { + public void handle(String arg0, Request arg1, HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException { ServletInputStream in = req.getInputStream(); byte[] b = new byte[8192]; @@ -125,11 +127,9 @@ public void handle(String arg0, Request arg1, HttpServletRequest req, HttpServle }; } - private static final File TMP = new File(System.getProperty("java.io.tmpdir"), "ahc-tests-" - + UUID.randomUUID().toString().substring(0, 8)); + private static final File TMP = new File(System.getProperty("java.io.tmpdir"), "ahc-tests-" + UUID.randomUUID().toString().substring(0, 8)); - public static File createTempFile(byte[] pattern, int repeat) - throws IOException { + public static File createTempFile(byte[] pattern, int repeat) throws IOException { TMP.mkdirs(); TMP.deleteOnExit(); File tmpFile = File.createTempFile("tmpfile-", ".data", TMP); @@ -139,8 +139,7 @@ public static File createTempFile(byte[] pattern, int repeat) return tmpFile; } - public static void write(byte[] pattern, int repeat, File file) - throws IOException { + public static void write(byte[] pattern, int repeat, File file) throws IOException { file.deleteOnExit(); file.getParentFile().mkdirs(); FileOutputStream out = null; @@ -149,8 +148,7 @@ public static void write(byte[] pattern, int repeat, File file) for (int i = 0; i < repeat; i++) { out.write(pattern); } - } - finally { + } finally { if (out != null) { out.close(); } diff --git a/src/test/java/com/ning/http/client/async/FilterTest.java b/src/test/java/com/ning/http/client/async/FilterTest.java index 6932087dac..99b21033f2 100644 --- a/src/test/java/com/ning/http/client/async/FilterTest.java +++ b/src/test/java/com/ning/http/client/async/FilterTest.java @@ -42,10 +42,7 @@ public abstract class FilterTest extends AbstractBasicTest { private class BasicHandler extends AbstractHandler { - public void handle(String s, - org.eclipse.jetty.server.Request r, - HttpServletRequest httpRequest, - HttpServletResponse httpResponse) throws IOException, ServletException { + public void handle(String s, org.eclipse.jetty.server.Request r, HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws IOException, ServletException { Enumeration e = httpRequest.getHeaderNames(); String param; @@ -65,63 +62,65 @@ public AbstractHandler configureHandler() throws Exception { return new BasicHandler(); } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void basicTest() throws Throwable { AsyncHttpClientConfig.Builder b = new AsyncHttpClientConfig.Builder(); b.addRequestFilter(new ThrottleRequestFilter(100)); AsyncHttpClient c = getAsyncHttpClient(b.build()); - - Response response = c.preparePost(getTargetUrl()) - .execute().get(); - assertNotNull(response); - assertEquals(response.getStatusCode(), 200); - c.close(); + try { + Response response = c.preparePost(getTargetUrl()).execute().get(); + assertNotNull(response); + assertEquals(response.getStatusCode(), 200); + } finally { + c.close(); + } } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void loadThrottleTest() throws Throwable { AsyncHttpClientConfig.Builder b = new AsyncHttpClientConfig.Builder(); b.addRequestFilter(new ThrottleRequestFilter(10)); AsyncHttpClient c = getAsyncHttpClient(b.build()); + try { + List> futures = new ArrayList>(); + for (int i = 0; i < 200; i++) { + futures.add(c.preparePost(getTargetUrl()).execute()); + } - List> futures = new ArrayList>(); - for (int i = 0; i < 200; i++) { - futures.add(c.preparePost(getTargetUrl()).execute()); - } - - for (Future f : futures) { - Response r = f.get(); - assertNotNull(f.get()); - assertEquals(r.getStatusCode(), 200); + for (Future f : futures) { + Response r = f.get(); + assertNotNull(f.get()); + assertEquals(r.getStatusCode(), 200); + } + } finally { + c.close(); } - - c.close(); } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void maxConnectionsText() throws Throwable { AsyncHttpClientConfig.Builder b = new AsyncHttpClientConfig.Builder(); b.addRequestFilter(new ThrottleRequestFilter(0, 1000)); AsyncHttpClient c = getAsyncHttpClient(b.build()); try { - Response response = c.preparePost(getTargetUrl()) - .execute().get(); + c.preparePost(getTargetUrl()).execute().get(); fail("Should have timed out"); } catch (IOException ex) { assertNotNull(ex); assertEquals(ex.getCause().getClass(), FilterException.class); + } finally { + c.close(); } - c.close(); } public String getTargetUrl() { return String.format("http://127.0.0.1:%d/foo/test", port1); } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void basicResponseFilterTest() throws Throwable { AsyncHttpClientConfig.Builder b = new AsyncHttpClientConfig.Builder(); b.addResponseFilter(new ResponseFilter() { @@ -134,18 +133,18 @@ public FilterContext filter(FilterContext ctx) throws FilterException { AsyncHttpClient c = getAsyncHttpClient(b.build()); try { - Response response = c.preparePost(getTargetUrl()) - .execute().get(); + Response response = c.preparePost(getTargetUrl()).execute().get(); assertNotNull(response); assertEquals(response.getStatusCode(), 200); } catch (IOException ex) { fail("Should have timed out"); + } finally { + c.close(); } - c.close(); } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void replayResponseFilterTest() throws Throwable { AsyncHttpClientConfig.Builder b = new AsyncHttpClientConfig.Builder(); final AtomicBoolean replay = new AtomicBoolean(true); @@ -165,19 +164,19 @@ public FilterContext filter(FilterContext ctx) throws FilterException { AsyncHttpClient c = getAsyncHttpClient(b.build()); try { - Response response = c.preparePost(getTargetUrl()) - .execute().get(); + Response response = c.preparePost(getTargetUrl()).execute().get(); assertNotNull(response); assertEquals(response.getStatusCode(), 200); assertEquals(response.getHeader("X-Replay"), "true"); } catch (IOException ex) { fail("Should have timed out"); + } finally { + c.close(); } - c.close(); } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void replayStatusCodeResponseFilterTest() throws Throwable { AsyncHttpClientConfig.Builder b = new AsyncHttpClientConfig.Builder(); final AtomicBoolean replay = new AtomicBoolean(true); @@ -197,19 +196,19 @@ public FilterContext filter(FilterContext ctx) throws FilterException { AsyncHttpClient c = getAsyncHttpClient(b.build()); try { - Response response = c.preparePost(getTargetUrl()) - .execute().get(); + Response response = c.preparePost(getTargetUrl()).execute().get(); assertNotNull(response); assertEquals(response.getStatusCode(), 200); assertEquals(response.getHeader("X-Replay"), "true"); } catch (IOException ex) { fail("Should have timed out"); + } finally { + c.close(); } - c.close(); } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void replayHeaderResponseFilterTest() throws Throwable { AsyncHttpClientConfig.Builder b = new AsyncHttpClientConfig.Builder(); final AtomicBoolean replay = new AtomicBoolean(true); @@ -218,16 +217,10 @@ public void replayHeaderResponseFilterTest() throws Throwable { public FilterContext filter(FilterContext ctx) throws FilterException { - if (ctx.getResponseHeaders() != null - && ctx.getResponseHeaders().getHeaders().getFirstValue("Ping").equals("Pong") - && replay.getAndSet(false)) { + if (ctx.getResponseHeaders() != null && ctx.getResponseHeaders().getHeaders().getFirstValue("Ping").equals("Pong") && replay.getAndSet(false)) { Request request = new RequestBuilder(ctx.getRequest()).addHeader("Ping", "Pong").build(); - return new FilterContext.FilterContextBuilder() - .asyncHandler(ctx.getAsyncHandler()) - .request(request) - .replayRequest(true) - .build(); + return new FilterContext.FilterContextBuilder().asyncHandler(ctx.getAsyncHandler()).request(request).replayRequest(true).build(); } return ctx; } @@ -236,15 +229,15 @@ public FilterContext filter(FilterContext ctx) throws FilterException { AsyncHttpClient c = getAsyncHttpClient(b.build()); try { - Response response = c.preparePost(getTargetUrl()).addHeader("Ping", "Pong") - .execute().get(); + Response response = c.preparePost(getTargetUrl()).addHeader("Ping", "Pong").execute().get(); assertNotNull(response); assertEquals(response.getStatusCode(), 200); assertEquals(response.getHeader("Ping"), "Pong"); } catch (IOException ex) { fail("Should have timed out"); + } finally { + c.close(); } - c.close(); } } diff --git a/src/test/java/com/ning/http/client/async/FollowingThreadTest.java b/src/test/java/com/ning/http/client/async/FollowingThreadTest.java index b8de801eb9..82d6c6d95e 100644 --- a/src/test/java/com/ning/http/client/async/FollowingThreadTest.java +++ b/src/test/java/com/ning/http/client/async/FollowingThreadTest.java @@ -30,7 +30,6 @@ import java.util.concurrent.Executors; import java.util.concurrent.TimeoutException; - /** * Simple stress test for exercising the follow redirect. */ @@ -38,59 +37,62 @@ public abstract class FollowingThreadTest extends AbstractBasicTest { private final static int COUNT = 10; - @Test(timeOut = 30 * 1000, groups = {"online", "default_provider", "scalability"}) + @Test(timeOut = 30 * 1000, groups = { "online", "default_provider", "scalability" }) public void testFollowRedirect() throws IOException, ExecutionException, TimeoutException, InterruptedException { final CountDownLatch countDown = new CountDownLatch(COUNT); ExecutorService pool = Executors.newCachedThreadPool(); - for (int i = 0; i < COUNT; i++) { - pool.submit(new Runnable() { - - private int status; - - public void run() { - final CountDownLatch l = new CountDownLatch(1); - final AsyncHttpClient ahc = getAsyncHttpClient( - new AsyncHttpClientConfig.Builder().setFollowRedirects(true).build()); - try { - ahc.prepareGet("http://www.google.com/").execute(new AsyncHandler() { - - public void onThrowable(Throwable t) { - t.printStackTrace(); - } - - public STATE onBodyPartReceived(HttpResponseBodyPart bodyPart) throws Exception { - System.out.println(new String(bodyPart.getBodyPartBytes())); - return STATE.CONTINUE; - } - - public STATE onStatusReceived(HttpResponseStatus responseStatus) throws Exception { - status = responseStatus.getStatusCode(); - System.out.println(responseStatus.getStatusText()); - return STATE.CONTINUE; - } - - public STATE onHeadersReceived(HttpResponseHeaders headers) throws Exception { - return STATE.CONTINUE; - } - - public Integer onCompleted() throws Exception { - l.countDown(); - return status; - } - }); - - l.await(); - } catch (Exception e) { - e.printStackTrace(); - } finally { - ahc.close(); - countDown.countDown(); + try { + for (int i = 0; i < COUNT; i++) { + pool.submit(new Runnable() { + + private int status; + + public void run() { + final CountDownLatch l = new CountDownLatch(1); + final AsyncHttpClient ahc = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setFollowRedirects(true).build()); + try { + ahc.prepareGet("http://www.google.com/").execute(new AsyncHandler() { + + public void onThrowable(Throwable t) { + t.printStackTrace(); + } + + public STATE onBodyPartReceived(HttpResponseBodyPart bodyPart) throws Exception { + System.out.println(new String(bodyPart.getBodyPartBytes())); + return STATE.CONTINUE; + } + + public STATE onStatusReceived(HttpResponseStatus responseStatus) throws Exception { + status = responseStatus.getStatusCode(); + System.out.println(responseStatus.getStatusText()); + return STATE.CONTINUE; + } + + public STATE onHeadersReceived(HttpResponseHeaders headers) throws Exception { + return STATE.CONTINUE; + } + + public Integer onCompleted() throws Exception { + l.countDown(); + return status; + } + }); + + l.await(); + } catch (Exception e) { + e.printStackTrace(); + } finally { + ahc.close(); + countDown.countDown(); + } } - } - }); + }); + } + countDown.await(); + } finally { + pool.shutdown(); } - countDown.await(); } } \ No newline at end of file diff --git a/src/test/java/com/ning/http/client/async/Head302Test.java b/src/test/java/com/ning/http/client/async/Head302Test.java index c84f827dce..b3603688e8 100644 --- a/src/test/java/com/ning/http/client/async/Head302Test.java +++ b/src/test/java/com/ning/http/client/async/Head302Test.java @@ -15,19 +15,6 @@ */ package com.ning.http.client.async; -import com.ning.http.client.AsyncCompletionHandlerBase; -import com.ning.http.client.AsyncHttpClient; -import com.ning.http.client.Request; -import com.ning.http.client.RequestBuilder; -import com.ning.http.client.Response; -import org.eclipse.jetty.server.handler.AbstractHandler; -import org.omg.CORBA.TIMEOUT; -import org.testng.Assert; -import org.testng.annotations.Test; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.concurrent.BrokenBarrierException; import java.util.concurrent.CountDownLatch; @@ -35,9 +22,23 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.eclipse.jetty.server.handler.AbstractHandler; +import org.testng.Assert; +import org.testng.annotations.Test; + +import com.ning.http.client.AsyncCompletionHandlerBase; +import com.ning.http.client.AsyncHttpClient; +import com.ning.http.client.Request; +import com.ning.http.client.RequestBuilder; +import com.ning.http.client.Response; + /** * Tests HEAD request that gets 302 response. - * + * * @author Hubert Iwaniuk */ public abstract class Head302Test extends AbstractBasicTest { @@ -45,10 +46,7 @@ public abstract class Head302Test extends AbstractBasicTest { * Handler that does Found (302) in response to HEAD method. */ private class Head302handler extends AbstractHandler { - public void handle(String s, - org.eclipse.jetty.server.Request r, - HttpServletRequest request, - HttpServletResponse response) throws IOException, ServletException { + public void handle(String s, org.eclipse.jetty.server.Request r, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { if ("HEAD".equalsIgnoreCase(request.getMethod())) { if (request.getPathInfo().endsWith("_moved")) { response.setStatus(HttpServletResponse.SC_OK); @@ -62,24 +60,27 @@ public void handle(String s, } } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void testHEAD302() throws IOException, BrokenBarrierException, InterruptedException, ExecutionException, TimeoutException { AsyncHttpClient client = getAsyncHttpClient(null); - final CountDownLatch l = new CountDownLatch(1); - Request request = new RequestBuilder("HEAD").setUrl("http://127.0.0.1/" + port1 + "/Test").build(); + try { + final CountDownLatch l = new CountDownLatch(1); + Request request = new RequestBuilder("HEAD").setUrl("http://127.0.0.1/" + port1 + "/Test").build(); - client.executeRequest(request, new AsyncCompletionHandlerBase() { - @Override - public Response onCompleted(Response response) throws Exception { - l.countDown(); - return super.onCompleted(response); - } - }).get(3, TimeUnit.SECONDS); + client.executeRequest(request, new AsyncCompletionHandlerBase() { + @Override + public Response onCompleted(Response response) throws Exception { + l.countDown(); + return super.onCompleted(response); + } + }).get(3, TimeUnit.SECONDS); - if (!l.await(TIMEOUT, TimeUnit.SECONDS)) { - Assert.fail("Timeout out"); + if (!l.await(TIMEOUT, TimeUnit.SECONDS)) { + Assert.fail("Timeout out"); + } + } finally { + client.close(); } - client.close(); } @Override diff --git a/src/test/java/com/ning/http/client/async/HostnameVerifierTest.java b/src/test/java/com/ning/http/client/async/HostnameVerifierTest.java index ca0a4f7c9d..6ee99cb0d8 100644 --- a/src/test/java/com/ning/http/client/async/HostnameVerifierTest.java +++ b/src/test/java/com/ning/http/client/async/HostnameVerifierTest.java @@ -54,10 +54,7 @@ public abstract class HostnameVerifierTest extends AbstractBasicTest { public static class EchoHandler extends AbstractHandler { /* @Override */ - public void handle(String pathInContext, - Request r, - HttpServletRequest httpRequest, - HttpServletResponse httpResponse) throws ServletException, IOException { + public void handle(String pathInContext, Request r, HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws ServletException, IOException { httpResponse.setContentType("text/html; charset=utf-8"); Enumeration e = httpRequest.getHeaderNames(); @@ -113,7 +110,7 @@ public void handle(String pathInContext, byte[] bytes = new byte[size]; int pos = 0; if (bytes.length > 0) { - //noinspection ResultOfMethodCallIgnored + // noinspection ResultOfMethodCallIgnored int read = 0; while (read != -1) { read = httpRequest.getInputStream().read(bytes, pos, bytes.length - pos); @@ -197,76 +194,84 @@ public void setUpGlobal() throws Exception { log.info("Local HTTP server started successfully"); } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void positiveHostnameVerifierTest() throws Throwable { final AsyncHttpClient client = getAsyncHttpClient(new Builder().setHostnameVerifier(new PositiveHostVerifier()).setSSLContext(createSSLContext()).build()); + try { + ClassLoader cl = getClass().getClassLoader(); + // override system properties + URL url = cl.getResource("SimpleTextFile.txt"); + File file = new File(url.toURI()); - ClassLoader cl = getClass().getClassLoader(); - // override system properties - URL url = cl.getResource("SimpleTextFile.txt"); - File file = new File(url.toURI()); - - Future f = client.preparePost(getTargetUrl()).setBody(file).setHeader("Content-Type", "text/html").execute(); - Response resp = f.get(); - assertNotNull(resp); - assertEquals(resp.getStatusCode(), HttpServletResponse.SC_OK); - assertEquals(resp.getResponseBody(), "This is a simple test file"); - client.close(); + Future f = client.preparePost(getTargetUrl()).setBody(file).setHeader("Content-Type", "text/html").execute(); + Response resp = f.get(); + assertNotNull(resp); + assertEquals(resp.getStatusCode(), HttpServletResponse.SC_OK); + assertEquals(resp.getResponseBody(), "This is a simple test file"); + } finally { + client.close(); + } } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void negativeHostnameVerifierTest() throws Throwable { final AsyncHttpClient client = getAsyncHttpClient(new Builder().setHostnameVerifier(new NegativeHostVerifier()).setSSLContext(createSSLContext()).build()); - - ClassLoader cl = getClass().getClassLoader(); - // override system properties - URL url = cl.getResource("SimpleTextFile.txt"); - File file = new File(url.toURI()); - try { - Future f = client.preparePost(getTargetUrl()).setBody(file).setHeader("Content-Type", "text/html").execute(); - } catch (ConnectException ex) { - assertEquals(ConnectException.class, ex.getClass()); + ClassLoader cl = getClass().getClassLoader(); + // override system properties + URL url = cl.getResource("SimpleTextFile.txt"); + File file = new File(url.toURI()); + + try { + client.preparePost(getTargetUrl()).setBody(file).setHeader("Content-Type", "text/html").execute(); + } catch (ConnectException ex) { + assertEquals(ConnectException.class, ex.getClass()); + } + } finally { + client.close(); } - client.close(); } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void remoteIDHostnameVerifierTest() throws Throwable { final AsyncHttpClient client = getAsyncHttpClient(new Builder().setHostnameVerifier(new CheckHost("bouette")).setSSLContext(createSSLContext()).build()); - - ClassLoader cl = getClass().getClassLoader(); - // override system properties - URL url = cl.getResource("SimpleTextFile.txt"); - File file = new File(url.toURI()); - try { - Future f = client.preparePost(getTargetUrl()).setBody(file).setHeader("Content-Type", "text/html").execute(); - } catch (ConnectException ex) { - assertEquals(ConnectException.class, ex.getClass()); + ClassLoader cl = getClass().getClassLoader(); + // override system properties + URL url = cl.getResource("SimpleTextFile.txt"); + File file = new File(url.toURI()); + + try { + client.preparePost(getTargetUrl()).setBody(file).setHeader("Content-Type", "text/html").execute(); + } catch (ConnectException ex) { + assertEquals(ConnectException.class, ex.getClass()); + } + } finally { + client.close(); } - client.close(); } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void remotePosHostnameVerifierTest() throws Throwable { final AsyncHttpClient client = getAsyncHttpClient(new Builder().setHostnameVerifier(new CheckHost("localhost")).setSSLContext(createSSLContext()).build()); - - ClassLoader cl = getClass().getClassLoader(); - // override system properties - URL url = cl.getResource("SimpleTextFile.txt"); - File file = new File(url.toURI()); - try { - Future f = client.preparePost(getTargetUrl()).setBody(file).setHeader("Content-Type", "text/html").execute(); - } catch (ConnectException ex) { - assertEquals(ConnectException.class, ex.getClass()); + ClassLoader cl = getClass().getClassLoader(); + // override system properties + URL url = cl.getResource("SimpleTextFile.txt"); + File file = new File(url.toURI()); + + try { + client.preparePost(getTargetUrl()).setBody(file).setHeader("Content-Type", "text/html").execute(); + } catch (ConnectException ex) { + assertEquals(ConnectException.class, ex.getClass()); + } + } finally { + client.close(); } - client.close(); } public static class PositiveHostVerifier implements HostnameVerifier { @@ -315,7 +320,7 @@ private static SSLContext createSSLContext() { // Initialize the SSLContext to work with our key managers. KeyManager[] keyManagers = kmf.getKeyManagers(); - TrustManager[] trustManagers = new TrustManager[]{DUMMY_TRUST_MANAGER}; + TrustManager[] trustManagers = new TrustManager[] { DUMMY_TRUST_MANAGER }; SecureRandom secureRandom = new SecureRandom(); SSLContext sslContext = SSLContext.getInstance("TLS"); @@ -333,17 +338,14 @@ public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; } - public void checkClientTrusted( - X509Certificate[] chain, String authType) throws CertificateException { + public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { } - public void checkServerTrusted( - X509Certificate[] chain, String authType) throws CertificateException { + public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { if (!TRUST_SERVER_CERT.get()) { throw new CertificateException("Server certificate not trusted."); } } }; - } diff --git a/src/test/java/com/ning/http/client/async/HttpToHttpsRedirectTest.java b/src/test/java/com/ning/http/client/async/HttpToHttpsRedirectTest.java index 7cd04b99bc..b12b08ad84 100644 --- a/src/test/java/com/ning/http/client/async/HttpToHttpsRedirectTest.java +++ b/src/test/java/com/ning/http/client/async/HttpToHttpsRedirectTest.java @@ -45,11 +45,7 @@ public abstract class HttpToHttpsRedirectTest extends AbstractBasicTest { private class Relative302Handler extends AbstractHandler { - - public void handle(String s, - Request r, - HttpServletRequest httpRequest, - HttpServletResponse httpResponse) throws IOException, ServletException { + public void handle(String s, Request r, HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws IOException, ServletException { String param; httpResponse.setContentType("text/html; charset=utf-8"); @@ -120,33 +116,14 @@ public void setUpGlobal() throws Exception { log.info("Local HTTP server started successfully"); } - private String getBaseUrl(URI uri) { - String url = uri.toString(); - int port = uri.getPort(); - if (port == -1) { - port = getPort(uri); - url = url.substring(0, url.length() - 1) + ":" + port; - } - return url.substring(0, url.lastIndexOf(":") + String.valueOf(port).length() + 1); - } - - private static int getPort(URI uri) { - int port = uri.getPort(); - if (port == -1) - port = uri.getScheme().equals("http") ? 80 : 443; - return port; - } - - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void httpToHttpsRedirect() throws Throwable { isSet.getAndSet(false); AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setMaximumNumberOfRedirects(5).setFollowRedirects(true).build(); AsyncHttpClient c = getAsyncHttpClient(cg); - Response response = c.prepareGet(getTargetUrl()) - .setHeader("X-redirect", getTargetUrl2()) - .execute().get(); + Response response = c.prepareGet(getTargetUrl()).setHeader("X-redirect", getTargetUrl2()).execute().get(); assertNotNull(response); assertEquals(response.getStatusCode(), 200); assertEquals(response.getHeader("X-httpToHttps"), "PASS"); @@ -157,43 +134,41 @@ public String getTargetUrl2() { return String.format("https://127.0.0.1:%d/foo/test", port2); } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void httpToHttpsProperConfig() throws Throwable { isSet.getAndSet(false); AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setMaximumNumberOfRedirects(5).setFollowRedirects(true).build(); AsyncHttpClient c = getAsyncHttpClient(cg); - - Response response = c.prepareGet(getTargetUrl()) - .setHeader("X-redirect", getTargetUrl2() + "/test2") - .execute().get(); - assertNotNull(response); - assertEquals(response.getStatusCode(), 200); - assertEquals(response.getHeader("X-httpToHttps"), "PASS"); - - // Test if the internal channel is downgraded to clean http. - response = c.prepareGet(getTargetUrl()) - .setHeader("X-redirect", getTargetUrl2() + "/foo2") - .execute().get(); - assertNotNull(response); - assertEquals(response.getStatusCode(), 200); - assertEquals(response.getHeader("X-httpToHttps"), "PASS"); - c.close(); + try { + Response response = c.prepareGet(getTargetUrl()).setHeader("X-redirect", getTargetUrl2() + "/test2").execute().get(); + assertNotNull(response); + assertEquals(response.getStatusCode(), 200); + assertEquals(response.getHeader("X-httpToHttps"), "PASS"); + + // Test if the internal channel is downgraded to clean http. + response = c.prepareGet(getTargetUrl()).setHeader("X-redirect", getTargetUrl2() + "/foo2").execute().get(); + assertNotNull(response); + assertEquals(response.getStatusCode(), 200); + assertEquals(response.getHeader("X-httpToHttps"), "PASS"); + } finally { + c.close(); + } } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void relativeLocationUrl() throws Throwable { isSet.getAndSet(false); AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setMaximumNumberOfRedirects(5).setFollowRedirects(true).build(); AsyncHttpClient c = getAsyncHttpClient(cg); - - Response response = c.prepareGet(getTargetUrl()) - .setHeader("X-redirect", "/foo/test") - .execute().get(); - assertNotNull(response); - assertEquals(response.getStatusCode(), 302); - assertEquals(response.getUri().toString(), getTargetUrl()); - c.close(); + try { + Response response = c.prepareGet(getTargetUrl()).setHeader("X-redirect", "/foo/test").execute().get(); + assertNotNull(response); + assertEquals(response.getStatusCode(), 302); + assertEquals(response.getUri().toString(), getTargetUrl()); + } finally { + c.close(); + } } } diff --git a/src/test/java/com/ning/http/client/async/InputStreamTest.java b/src/test/java/com/ning/http/client/async/InputStreamTest.java index 70ceb4b48e..f6d8c395ae 100644 --- a/src/test/java/com/ning/http/client/async/InputStreamTest.java +++ b/src/test/java/com/ning/http/client/async/InputStreamTest.java @@ -36,10 +36,7 @@ public abstract class InputStreamTest extends AbstractBasicTest { private class InputStreamHandler extends AbstractHandler { - public void handle(String s, - Request r, - HttpServletRequest request, - HttpServletResponse response) throws IOException, ServletException { + public void handle(String s, Request r, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { if ("POST".equalsIgnoreCase(request.getMethod())) { byte[] b = new byte[3]; request.getInputStream().read(b, 0, 3); @@ -54,43 +51,46 @@ public void handle(String s, } } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void testInvalidInputStream() throws IOException, ExecutionException, TimeoutException, InterruptedException { AsyncHttpClient c = getAsyncHttpClient(null); - FluentCaseInsensitiveStringsMap h = new FluentCaseInsensitiveStringsMap(); - h.add("Content-Type", "application/x-www-form-urlencoded"); + try { + FluentCaseInsensitiveStringsMap h = new FluentCaseInsensitiveStringsMap(); + h.add("Content-Type", "application/x-www-form-urlencoded"); - InputStream is = new InputStream() { + InputStream is = new InputStream() { - public int readAllowed; + public int readAllowed; - @Override - public int available() { - return 1; // Fake - } - - @Override - public int read() throws IOException { - int fakeCount = readAllowed++; - if (fakeCount == 0) { - return (int) 'a'; - } else if (fakeCount == 1) { - return (int) 'b'; - } else if (fakeCount == 2) { - return (int) 'c'; - } else { - return -1; + @Override + public int available() { + return 1; // Fake } - } - }; + @Override + public int read() throws IOException { + int fakeCount = readAllowed++; + if (fakeCount == 0) { + return (int) 'a'; + } else if (fakeCount == 1) { + return (int) 'b'; + } else if (fakeCount == 2) { + return (int) 'c'; + } else { + return -1; + } - Response resp = c.preparePost(getTargetUrl()).setHeaders(h).setBody(is).execute().get(); - assertNotNull(resp); - assertEquals(resp.getStatusCode(), HttpServletResponse.SC_OK); - assertEquals(resp.getHeader("X-Param"), "abc"); - c.close(); + } + }; + + Response resp = c.preparePost(getTargetUrl()).setHeaders(h).setBody(is).execute().get(); + assertNotNull(resp); + assertEquals(resp.getStatusCode(), HttpServletResponse.SC_OK); + assertEquals(resp.getHeader("X-Param"), "abc"); + } finally { + c.close(); + } } @Override diff --git a/src/test/java/com/ning/http/client/async/ListenableFutureTest.java b/src/test/java/com/ning/http/client/async/ListenableFutureTest.java index 6de42566a9..f80168bc50 100644 --- a/src/test/java/com/ning/http/client/async/ListenableFutureTest.java +++ b/src/test/java/com/ning/http/client/async/ListenableFutureTest.java @@ -27,28 +27,31 @@ public abstract class ListenableFutureTest extends AbstractBasicTest { - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void testListenableFuture() throws Throwable { final AtomicInteger statusCode = new AtomicInteger(500); AsyncHttpClient ahc = getAsyncHttpClient(null); - final CountDownLatch latch = new CountDownLatch(1); - final ListenableFuture future = ahc.prepareGet(getTargetUrl()).execute(); - future.addListener(new Runnable(){ + try { + final CountDownLatch latch = new CountDownLatch(1); + final ListenableFuture future = ahc.prepareGet(getTargetUrl()).execute(); + future.addListener(new Runnable() { - public void run() { - try { - statusCode.set(future.get().getStatusCode()); - latch.countDown(); - } catch (InterruptedException e) { - e.printStackTrace(); - } catch (ExecutionException e) { - e.printStackTrace(); + public void run() { + try { + statusCode.set(future.get().getStatusCode()); + latch.countDown(); + } catch (InterruptedException e) { + e.printStackTrace(); + } catch (ExecutionException e) { + e.printStackTrace(); + } } - } - }, Executors.newFixedThreadPool(1)); + }, Executors.newFixedThreadPool(1)); - latch.await(10, TimeUnit.SECONDS); - assertEquals(statusCode.get(), 200); - ahc.close(); + latch.await(10, TimeUnit.SECONDS); + assertEquals(statusCode.get(), 200); + } finally { + ahc.close(); + } } } diff --git a/src/test/java/com/ning/http/client/async/MaxConnectionsInThreads.java b/src/test/java/com/ning/http/client/async/MaxConnectionsInThreads.java index 01484c610d..405ef9b76d 100644 --- a/src/test/java/com/ning/http/client/async/MaxConnectionsInThreads.java +++ b/src/test/java/com/ning/http/client/async/MaxConnectionsInThreads.java @@ -43,96 +43,79 @@ abstract public class MaxConnectionsInThreads extends AbstractBasicTest { private static URI servletEndpointUri; - @Test(groups = {"online", "default_provider"}) + @Test(groups = { "online", "default_provider" }) public void testMaxConnectionsWithinThreads() { - String[] urls = new String[]{ - servletEndpointUri.toString(), - servletEndpointUri.toString()}; - - - final AsyncHttpClient client = - getAsyncHttpClient(new AsyncHttpClientConfig.Builder() - .setConnectionTimeoutInMs(1000) - .setRequestTimeoutInMs(5000) - .setAllowPoolingConnection(true) - .setMaximumConnectionsTotal(1) - .setMaximumConnectionsPerHost(1) - .build()); - - - final Boolean[] caughtError = new Boolean[]{Boolean.FALSE}; - List ts = new ArrayList(); - for (int i = 0; i < urls.length; i++) { - final String url = urls[i]; - Thread t = new Thread() { - public void run() { - try { - client.prepareGet(url).execute(); - } catch (IOException e) { - // assert that 2nd request fails, because maxTotalConnections=1 - // System.out.println(i); - caughtError[0] = true; - System.err.println("============"); - e.printStackTrace(); - System.err.println("============"); + String[] urls = new String[] { servletEndpointUri.toString(), servletEndpointUri.toString() }; + final AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setConnectionTimeoutInMs(1000).setRequestTimeoutInMs(5000).setAllowPoolingConnection(true).setMaximumConnectionsTotal(1).setMaximumConnectionsPerHost(1).build()); + + try { + final Boolean[] caughtError = new Boolean[] { Boolean.FALSE }; + List ts = new ArrayList(); + for (int i = 0; i < urls.length; i++) { + final String url = urls[i]; + Thread t = new Thread() { + public void run() { + try { + client.prepareGet(url).execute(); + } catch (IOException e) { + // assert that 2nd request fails, because maxTotalConnections=1 + // System.out.println(i); + caughtError[0] = true; + System.err.println("============"); + e.printStackTrace(); + System.err.println("============"); + + } } + }; + t.start(); + ts.add(t); + } + + for (Thread t : ts) { + try { + t.join(); + } catch (InterruptedException e) { + e.printStackTrace(); } - }; - t.start(); - ts.add(t); - } + } - for (Thread t : ts) { + // Let the threads finish try { - t.join(); - } catch (InterruptedException e) { - // TODO Auto-generated catch block - e.printStackTrace(); + Thread.sleep(4500); + } catch (InterruptedException e1) { + e1.printStackTrace(); } - } - - // Let the threads finish - try { - Thread.sleep(4500); - } catch (InterruptedException e1) { - // TODO Auto-generated catch block - e1.printStackTrace(); - } - - assertTrue("Max Connections should have been reached", caughtError[0]); - - - boolean errorInNotThread = false; - for (int i = 0; i < urls.length; i++) { - final String url = urls[i]; + assertTrue("Max Connections should have been reached", caughtError[0]); + + boolean errorInNotThread = false; + for (int i = 0; i < urls.length; i++) { + final String url = urls[i]; + try { + client.prepareGet(url).execute(); + // client.prepareGet(url).execute(); + } catch (IOException e) { + // assert that 2nd request fails, because maxTotalConnections=1 + // System.out.println(i); + errorInNotThread = true; + System.err.println("============"); + e.printStackTrace(); + System.err.println("============"); + } + } + // Let the request finish try { - client.prepareGet(url).execute(); - // client.prepareGet(url).execute(); - } catch (IOException e) { - // assert that 2nd request fails, because maxTotalConnections=1 - // System.out.println(i); - errorInNotThread = true; - System.err.println("============"); - e.printStackTrace(); - System.err.println("============"); + Thread.sleep(2500); + } catch (InterruptedException e1) { + e1.printStackTrace(); } + assertTrue("Max Connections should have been reached", errorInNotThread); + } finally { + client.close(); } - // Let the request finish - try { - Thread.sleep(2500); - } catch (InterruptedException e1) { - // TODO Auto-generated catch block - e1.printStackTrace(); - } - assertTrue("Max Connections should have been reached", errorInNotThread); - - - client.close(); - - } @Override @@ -149,7 +132,6 @@ public void setUpGlobal() throws Exception { server.addConnector(listener); - ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS); context.setContextPath("/"); @@ -185,8 +167,7 @@ public void service(HttpServletRequest req, HttpServletResponse res) throws Serv try { sleepTime = Integer.parseInt(req.getParameter("timeout")); - } - catch (NumberFormatException e) { + } catch (NumberFormatException e) { sleepTime = DEFAULT_TIMEOUT; } @@ -200,8 +181,7 @@ public void service(HttpServletRequest req, HttpServletResponse res) throws Serv System.out.println("Servlet is awake for"); System.out.println("======================================="); System.out.flush(); - } - catch (Exception e) { + } catch (Exception e) { } @@ -209,10 +189,12 @@ public void service(HttpServletRequest req, HttpServletResponse res) throws Serv byte[] retVal = "1".getBytes(); OutputStream os = res.getOutputStream(); - - res.setContentLength(retVal.length); - os.write(retVal); - os.close(); + try { + res.setContentLength(retVal.length); + os.write(retVal); + } finally { + os.close(); + } } } } diff --git a/src/test/java/com/ning/http/client/async/MaxTotalConnectionTest.java b/src/test/java/com/ning/http/client/async/MaxTotalConnectionTest.java index ad47d1ceac..307d38937b 100644 --- a/src/test/java/com/ning/http/client/async/MaxTotalConnectionTest.java +++ b/src/test/java/com/ning/http/client/async/MaxTotalConnectionTest.java @@ -1,18 +1,18 @@ /* -* Copyright 2010 Ning, Inc. -* -* Ning licenses this file to you under the Apache License, version 2.0 -* (the "License"); you may not use this file except in compliance with the -* License. You may obtain a copy of the License at: -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -* License for the specific language governing permissions and limitations -* under the License. -*/ + * Copyright 2010 Ning, Inc. + * + * Ning licenses this file to you under the Apache License, version 2.0 + * (the "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ package com.ning.http.client.async; import com.ning.http.client.AsyncHttpClient; @@ -32,21 +32,11 @@ public abstract class MaxTotalConnectionTest extends AbstractBasicTest { protected final Logger log = LoggerFactory.getLogger(AbstractBasicTest.class); - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void testMaxTotalConnectionsExceedingException() { - String[] urls = new String[]{ - "http://google.com/", - "http://github.com/"}; + String[] urls = new String[] { "http://google.com/", "http://github.com/" }; - AsyncHttpClient client = getAsyncHttpClient( - new AsyncHttpClientConfig.Builder() - .setConnectionTimeoutInMs(1000) - .setRequestTimeoutInMs(5000) - .setAllowPoolingConnection(false) - .setMaximumConnectionsTotal(1) - .setMaximumConnectionsPerHost(1) - .build() - ); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setConnectionTimeoutInMs(1000).setRequestTimeoutInMs(5000).setAllowPoolingConnection(false).setMaximumConnectionsTotal(1).setMaximumConnectionsPerHost(1).build()); boolean caughtError = false; for (int i = 0; i < urls.length; i++) { @@ -64,92 +54,72 @@ public void testMaxTotalConnectionsExceedingException() { @Test public void testMaxTotalConnections() { - String[] urls = new String[]{ - "http://google.com/", - "http://lenta.ru/"}; - - AsyncHttpClient client = getAsyncHttpClient( - new AsyncHttpClientConfig.Builder() - .setConnectionTimeoutInMs(1000) - .setRequestTimeoutInMs(5000) - .setAllowPoolingConnection(false) - .setMaximumConnectionsTotal(2) - .setMaximumConnectionsPerHost(1) - .build() - ); - - for (String url : urls) { - try { - client.prepareGet(url).execute(); - } catch (IOException e) { - Assert.fail("Smth wrong with connections handling!"); + String[] urls = new String[] { "http://google.com/", "http://lenta.ru/" }; + + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setConnectionTimeoutInMs(1000).setRequestTimeoutInMs(5000).setAllowPoolingConnection(false).setMaximumConnectionsTotal(2).setMaximumConnectionsPerHost(1).build()); + try { + for (String url : urls) { + try { + client.prepareGet(url).execute(); + } catch (IOException e) { + Assert.fail("Smth wrong with connections handling!"); + } } + } finally { + client.close(); } - client.close(); } - /** - * JFA: Disable this test for 1.2.0 release as it can easily fail because a request may complete - * before the second one is made, hence failing. The issue occurs frequently on Linux. + * JFA: Disable this test for 1.2.0 release as it can easily fail because a request may complete before the second one is made, hence failing. The issue occurs frequently on Linux. */ @Test(enabled = false) public void testMaxTotalConnectionsCorrectExceptionHandling() { - String[] urls = new String[]{ - "http://google.com/", - "http://github.com/"}; - - AsyncHttpClient client = getAsyncHttpClient( - new AsyncHttpClientConfig.Builder() - .setConnectionTimeoutInMs(1000) - .setRequestTimeoutInMs(5000) - .setAllowPoolingConnection(false) - .setMaximumConnectionsTotal(1) - .setMaximumConnectionsPerHost(1) - .build() - ); - - List futures = new ArrayList(); - boolean caughtError = false; - for (int i = 0; i < urls.length; i++) { - try { - Future future = client.prepareGet(urls[i]).execute(); - if (future != null) { - futures.add(future); + String[] urls = new String[] { "http://google.com/", "http://github.com/" }; + + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setConnectionTimeoutInMs(1000).setRequestTimeoutInMs(5000).setAllowPoolingConnection(false).setMaximumConnectionsTotal(1).setMaximumConnectionsPerHost(1).build()); + try { + List futures = new ArrayList(); + boolean caughtError = false; + for (int i = 0; i < urls.length; i++) { + try { + Future future = client.prepareGet(urls[i]).execute(); + if (future != null) { + futures.add(future); + } + } catch (IOException e) { + // assert that 2nd request fails, because maxTotalConnections=1 + Assert.assertEquals(i, 1); + caughtError = true; } - } catch (IOException e) { - // assert that 2nd request fails, because maxTotalConnections=1 - Assert.assertEquals(i, 1); - caughtError = true; } - } - Assert.assertTrue(caughtError); - - // get results of executed requests - for (Future future : futures) { - try { - Object res = future.get(); - } catch (InterruptedException e) { - log.error("Error!", e); - } catch (ExecutionException e) { - log.error("Error!", e); + Assert.assertTrue(caughtError); + + // get results of executed requests + for (Future future : futures) { + try { + Object res = future.get(); + } catch (InterruptedException e) { + log.error("Error!", e); + } catch (ExecutionException e) { + log.error("Error!", e); + } } - } - // try to execute once again, expecting that 1 connection is released - caughtError = false; - for (int i = 0; i < urls.length; i++) { - try { - client.prepareGet(urls[i]).execute(); - } catch (IOException e) { - // assert that 2nd request fails, because maxTotalConnections=1 - Assert.assertEquals(i, 1); - caughtError = true; + // try to execute once again, expecting that 1 connection is released + caughtError = false; + for (int i = 0; i < urls.length; i++) { + try { + client.prepareGet(urls[i]).execute(); + } catch (IOException e) { + // assert that 2nd request fails, because maxTotalConnections=1 + Assert.assertEquals(i, 1); + caughtError = true; + } } + Assert.assertTrue(caughtError); + } finally { + client.close(); } - Assert.assertTrue(caughtError); - client.close(); } } - - diff --git a/src/test/java/com/ning/http/client/async/MultipartUploadTest.java b/src/test/java/com/ning/http/client/async/MultipartUploadTest.java index 580af9ba03..991983e8ca 100644 --- a/src/test/java/com/ning/http/client/async/MultipartUploadTest.java +++ b/src/test/java/com/ning/http/client/async/MultipartUploadTest.java @@ -70,7 +70,7 @@ public abstract class MultipartUploadTest extends AbstractBasicTest { private String BASE_URL; private String servletEndpointRedirectUrl; - public static byte GZIPTEXT[] = new byte[]{31, -117, 8, 8, 11, 43, 79, 75, 0, 3, 104, 101, 108, 108, 111, 46, 116, 120, 116, 0, -53, 72, -51, -55, -55, -25, 2, 0, 32, 48, 58, 54, 6, 0, 0, 0}; + public static byte GZIPTEXT[] = new byte[] { 31, -117, 8, 8, 11, 43, 79, 75, 0, 3, 104, 101, 108, 108, 111, 46, 116, 120, 116, 0, -53, 72, -51, -55, -55, -25, 2, 0, 32, 48, 58, 54, 6, 0, 0, 0 }; @BeforeClass public void setUp() throws Exception { @@ -130,7 +130,7 @@ private File getClasspathFile(String file) throws FileNotFoundException { /** * Tests that the streaming of a file works. */ - @Test (enabled = true) + @Test(enabled = true) public void testSendingSmallFilesAndByteArray() { String expectedContents = "filecontent: hello"; String expectedContents2 = "gzipcontent: hello"; @@ -155,7 +155,6 @@ public void testSendingSmallFilesAndByteArray() { fail("unable to find " + testResource2); } - File testResource3File = null; try { testResource3File = getClasspathFile(testResource3); @@ -179,7 +178,6 @@ public void testSendingSmallFilesAndByteArray() { gzipped.add(true); gzipped.add(false); - boolean tmpFileCreated = false; File tmpFile = null; FileOutputStream os = null; @@ -193,7 +191,6 @@ public void testSendingSmallFilesAndByteArray() { expected.add(expectedContents); gzipped.add(false); - } catch (FileNotFoundException e1) { // TODO Auto-generated catch block e1.printStackTrace(); @@ -210,13 +207,10 @@ public void testSendingSmallFilesAndByteArray() { fail("Unable to test ByteArrayMultiPart, as unable to write to filesystem the tmp test content"); } - - AsyncHttpClientConfig.Builder bc = - new AsyncHttpClientConfig.Builder(); + AsyncHttpClientConfig.Builder bc = new AsyncHttpClientConfig.Builder(); bc.setFollowRedirects(true); - AsyncHttpClient c = new AsyncHttpClient(bc.build()); try { @@ -232,8 +226,7 @@ public void testSendingSmallFilesAndByteArray() { builder.addBodyPart(new StringPart("Height", "shrimplike", AsyncHttpProviderUtils.DEFAULT_CHARSET)); builder.addBodyPart(new StringPart("Hair", "ridiculous", AsyncHttpProviderUtils.DEFAULT_CHARSET)); - builder.addBodyPart(new ByteArrayPart("file4", "bytearray.txt", expectedContents.getBytes("UTF-8") ,"text/plain", "UTF-8")); - + builder.addBodyPart(new ByteArrayPart("file4", "bytearray.txt", expectedContents.getBytes("UTF-8"), "text/plain", "UTF-8")); com.ning.http.client.Request r = builder.build(); @@ -243,26 +236,24 @@ public void testSendingSmallFilesAndByteArray() { testSentFile(expected, testFiles, res, gzipped); - c.close(); } catch (Exception e) { e.printStackTrace(); fail("Download Exception"); } finally { + c.close(); FileUtils.deleteQuietly(tmpFile); } } - /** * Test that the files were sent, based on the response from the servlet - * + * * @param expectedContents * @param sourceFiles * @param r * @param deflate */ - private void testSentFile(List expectedContents, List sourceFiles, - Response r, List deflate) { + private void testSentFile(List expectedContents, List sourceFiles, Response r, List deflate) { String content = null; try { content = r.getResponseBody(); @@ -283,11 +274,10 @@ private void testSentFile(List expectedContents, List sourceFiles, String[] responseFiles = tmpFiles.split(","); assertNotNull(responseFiles); - assertEquals( sourceFiles.size(), responseFiles.length); - + assertEquals(sourceFiles.size(), responseFiles.length); System.out.println(Arrays.toString(responseFiles)); - //assertTrue("File should exist: " + tmpFile.getAbsolutePath(),tmpFile.exists()); + // assertTrue("File should exist: " + tmpFile.getAbsolutePath(),tmpFile.exists()); int i = 0; for (File sourceFile : sourceFiles) { @@ -315,7 +305,6 @@ private void testSentFile(List expectedContents, List sourceFiles, IOUtils.closeQuietly(instream); } - tmp = new File(responseFiles[i].trim()); System.out.println("=============================="); System.out.println(tmp.getAbsolutePath()); @@ -323,7 +312,6 @@ private void testSentFile(List expectedContents, List sourceFiles, System.out.flush(); assertTrue(tmp.exists()); - instream = new FileInputStream(tmp); ByteArrayOutputStream baos2 = new ByteArrayOutputStream(); byte[] buf = new byte[8092]; @@ -359,7 +347,8 @@ private void testSentFile(List expectedContents, List sourceFiles, e.printStackTrace(); fail("Download Exception"); } finally { - if (tmp != null) FileUtils.deleteQuietly(tmp); + if (tmp != null) + FileUtils.deleteQuietly(tmp); IOUtils.closeQuietly(instream); i++; } @@ -368,7 +357,7 @@ private void testSentFile(List expectedContents, List sourceFiles, /** * Takes the content that is being passed to it, and streams to a file on disk - * + * * @author dominict */ public static class MockMultipartUploadServlet extends HttpServlet { @@ -379,7 +368,6 @@ public static class MockMultipartUploadServlet extends HttpServlet { private int filesProcessed = 0; private int stringsProcessed = 0; - public MockMultipartUploadServlet() { } @@ -411,8 +399,7 @@ public int getStringsProcessed() { } @Override - public void service(HttpServletRequest request, HttpServletResponse response) - throws ServletException, IOException { + public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // Check that we have a file upload request boolean isMultipart = ServletFileUpload.isMultipartContent(request); if (isMultipart) { @@ -430,12 +417,10 @@ public void service(HttpServletRequest request, HttpServletResponse response) stream = item.openStream(); if (item.isFormField()) { - System.out.println("Form field " + name + " with value " - + Streams.asString(stream) + " detected."); + System.out.println("Form field " + name + " with value " + Streams.asString(stream) + " detected."); incrementStringsProcessed(); } else { - System.out.println("File field " + name + " with file name " - + item.getName() + " detected."); + System.out.println("File field " + name + " with file name " + item.getName() + " detected."); // Process the input stream OutputStream os = null; try { @@ -480,5 +465,4 @@ public void service(HttpServletRequest request, HttpServletResponse response) } - } diff --git a/src/test/java/com/ning/http/client/async/MultipleHeaderTest.java b/src/test/java/com/ning/http/client/async/MultipleHeaderTest.java index 6bf0b416b9..1e13f6ecc5 100644 --- a/src/test/java/com/ning/http/client/async/MultipleHeaderTest.java +++ b/src/test/java/com/ning/http/client/async/MultipleHeaderTest.java @@ -43,116 +43,118 @@ /** * @author Hubert Iwaniuk */ -public abstract class MultipleHeaderTest extends AbstractBasicTest{ +public abstract class MultipleHeaderTest extends AbstractBasicTest { private ExecutorService executorService; private ServerSocket serverSocket; private Future voidFuture; - @Test(groups = {"standalone", "default_provider"}) - public void testMultipleOtherHeaders() - throws IOException, ExecutionException, TimeoutException, InterruptedException { - final String[] xffHeaders = new String[]{null, null}; + @Test(groups = { "standalone", "default_provider" }) + public void testMultipleOtherHeaders() throws IOException, ExecutionException, TimeoutException, InterruptedException { + final String[] xffHeaders = new String[] { null, null }; AsyncHttpClient ahc = getAsyncHttpClient(null); - Request req = new RequestBuilder("GET").setUrl("http://localhost/" + port1 + "/MultiOther").build(); - final CountDownLatch latch = new CountDownLatch(1); - ahc.executeRequest(req, new AsyncHandler() { - public void onThrowable(Throwable t) { - t.printStackTrace(System.out); - } + try { + Request req = new RequestBuilder("GET").setUrl("http://localhost/" + port1 + "/MultiOther").build(); + final CountDownLatch latch = new CountDownLatch(1); + ahc.executeRequest(req, new AsyncHandler() { + public void onThrowable(Throwable t) { + t.printStackTrace(System.out); + } - public STATE onBodyPartReceived(HttpResponseBodyPart objectHttpResponseBodyPart) throws Exception { - return STATE.CONTINUE; - } + public STATE onBodyPartReceived(HttpResponseBodyPart objectHttpResponseBodyPart) throws Exception { + return STATE.CONTINUE; + } - public STATE onStatusReceived(HttpResponseStatus objectHttpResponseStatus) throws Exception { - return STATE.CONTINUE; - } + public STATE onStatusReceived(HttpResponseStatus objectHttpResponseStatus) throws Exception { + return STATE.CONTINUE; + } - public STATE onHeadersReceived(HttpResponseHeaders response) throws Exception { - int i = 0; - for (String header : response.getHeaders().get("X-Forwarded-For")) { - xffHeaders[i++] = header; + public STATE onHeadersReceived(HttpResponseHeaders response) throws Exception { + int i = 0; + for (String header : response.getHeaders().get("X-Forwarded-For")) { + xffHeaders[i++] = header; + } + latch.countDown(); + return STATE.CONTINUE; } - latch.countDown(); - return STATE.CONTINUE; - } - public Void onCompleted() throws Exception { - return null; - } - }).get(3, TimeUnit.SECONDS); + public Void onCompleted() throws Exception { + return null; + } + }).get(3, TimeUnit.SECONDS); - if (!latch.await(2, TimeUnit.SECONDS)) { - Assert.fail("Time out"); - } - Assert.assertNotNull(xffHeaders[0]); - Assert.assertNotNull(xffHeaders[1]); - try { - Assert.assertEquals(xffHeaders[0], "abc"); - Assert.assertEquals(xffHeaders[1], "def"); - } catch (AssertionError ex) { - Assert.assertEquals(xffHeaders[1], "abc"); - Assert.assertEquals(xffHeaders[0], "def"); + if (!latch.await(2, TimeUnit.SECONDS)) { + Assert.fail("Time out"); + } + Assert.assertNotNull(xffHeaders[0]); + Assert.assertNotNull(xffHeaders[1]); + try { + Assert.assertEquals(xffHeaders[0], "abc"); + Assert.assertEquals(xffHeaders[1], "def"); + } catch (AssertionError ex) { + Assert.assertEquals(xffHeaders[1], "abc"); + Assert.assertEquals(xffHeaders[0], "def"); + } + } finally { + ahc.close(); } - ahc.close(); } - - @Test(groups = {"standalone", "default_provider"}) - public void testMultipleEntityHeaders() - throws IOException, ExecutionException, TimeoutException, InterruptedException { - final String[] clHeaders = new String[]{null, null}; + @Test(groups = { "standalone", "default_provider" }) + public void testMultipleEntityHeaders() throws IOException, ExecutionException, TimeoutException, InterruptedException { + final String[] clHeaders = new String[] { null, null }; AsyncHttpClient ahc = getAsyncHttpClient(null); - Request req = new RequestBuilder("GET").setUrl("http://localhost/" + port1 + "/MultiEnt").build(); - final CountDownLatch latch = new CountDownLatch(1); - ahc.executeRequest(req, new AsyncHandler() { - public void onThrowable(Throwable t) { - t.printStackTrace(System.out); - } + try { + Request req = new RequestBuilder("GET").setUrl("http://localhost/" + port1 + "/MultiEnt").build(); + final CountDownLatch latch = new CountDownLatch(1); + ahc.executeRequest(req, new AsyncHandler() { + public void onThrowable(Throwable t) { + t.printStackTrace(System.out); + } - public STATE onBodyPartReceived(HttpResponseBodyPart objectHttpResponseBodyPart) throws Exception { - return STATE.CONTINUE; - } + public STATE onBodyPartReceived(HttpResponseBodyPart objectHttpResponseBodyPart) throws Exception { + return STATE.CONTINUE; + } - public STATE onStatusReceived(HttpResponseStatus objectHttpResponseStatus) throws Exception { - return STATE.CONTINUE; - } + public STATE onStatusReceived(HttpResponseStatus objectHttpResponseStatus) throws Exception { + return STATE.CONTINUE; + } - public STATE onHeadersReceived(HttpResponseHeaders response) throws Exception { - try { - int i = 0; - for (String header : response.getHeaders().get("Content-Length")) { - clHeaders[i++] = header; + public STATE onHeadersReceived(HttpResponseHeaders response) throws Exception { + try { + int i = 0; + for (String header : response.getHeaders().get("Content-Length")) { + clHeaders[i++] = header; + } + } finally { + latch.countDown(); } - } finally { - latch.countDown(); + return STATE.CONTINUE; } - return STATE.CONTINUE; - } - public Void onCompleted() throws Exception { - return null; - } - }).get(3, TimeUnit.SECONDS); - - if (!latch.await(2, TimeUnit.SECONDS)) { - Assert.fail("Time out"); - } - Assert.assertNotNull(clHeaders[0]); - Assert.assertNotNull(clHeaders[1]); + public Void onCompleted() throws Exception { + return null; + } + }).get(3, TimeUnit.SECONDS); - // We can predict the order - try { - Assert.assertEquals(clHeaders[0], "2"); - Assert.assertEquals(clHeaders[1], "1"); - } catch (Throwable ex) { - Assert.assertEquals(clHeaders[0], "1"); - Assert.assertEquals(clHeaders[1], "2"); + if (!latch.await(2, TimeUnit.SECONDS)) { + Assert.fail("Time out"); + } + Assert.assertNotNull(clHeaders[0]); + Assert.assertNotNull(clHeaders[1]); + + // We can predict the order + try { + Assert.assertEquals(clHeaders[0], "2"); + Assert.assertEquals(clHeaders[1], "1"); + } catch (Throwable ex) { + Assert.assertEquals(clHeaders[0], "1"); + Assert.assertEquals(clHeaders[1], "2"); + } + } finally { + ahc.close(); } - ahc.close(); - } @BeforeClass(alwaysRun = true) @@ -174,23 +176,12 @@ public Void call() throws Exception { socket.shutdownInput(); if (req.endsWith("MultiEnt")) { OutputStreamWriter outputStreamWriter = new OutputStreamWriter(socket.getOutputStream()); - outputStreamWriter.append("HTTP/1.0 200 OK\n" + - "Connection: close\n" + - "Content-Type: text/plain; charset=iso-8859-1\n" + - "Content-Length: 2\n" + - "Content-Length: 1\n" + - "\n0\n"); + outputStreamWriter.append("HTTP/1.0 200 OK\n" + "Connection: close\n" + "Content-Type: text/plain; charset=iso-8859-1\n" + "Content-Length: 2\n" + "Content-Length: 1\n" + "\n0\n"); outputStreamWriter.flush(); socket.shutdownOutput(); } else if (req.endsWith("MultiOther")) { OutputStreamWriter outputStreamWriter = new OutputStreamWriter(socket.getOutputStream()); - outputStreamWriter.append("HTTP/1.0 200 OK\n" + - "Connection: close\n" + - "Content-Type: text/plain; charset=iso-8859-1\n" + - "Content-Length: 1\n" + - "X-Forwarded-For: abc\n" + - "X-Forwarded-For: def\n" + - "\n0\n"); + outputStreamWriter.append("HTTP/1.0 200 OK\n" + "Connection: close\n" + "Content-Type: text/plain; charset=iso-8859-1\n" + "Content-Length: 1\n" + "X-Forwarded-For: abc\n" + "X-Forwarded-For: def\n" + "\n0\n"); outputStreamWriter.flush(); socket.shutdownOutput(); } diff --git a/src/test/java/com/ning/http/client/async/NoNullResponseTest.java b/src/test/java/com/ning/http/client/async/NoNullResponseTest.java index 2dcb653225..587b29cabc 100644 --- a/src/test/java/com/ning/http/client/async/NoNullResponseTest.java +++ b/src/test/java/com/ning/http/client/async/NoNullResponseTest.java @@ -33,40 +33,35 @@ public abstract class NoNullResponseTest extends AbstractBasicTest { private static final String VERISIGN_HTTPS_URL = "https://www.verisign.com/"; - @Test(invocationCount = 4, groups = {"online", "default_provider"}) + @Test(invocationCount = 4, groups = { "online", "default_provider" }) public void multipleSslRequestsWithDelayAndKeepAlive() throws Throwable { final AsyncHttpClient client = create(); - final BoundRequestBuilder builder = client.prepareGet(VERISIGN_HTTPS_URL); - final Response response1 = builder.execute().get(); - Thread.sleep(5000); - final Response response2 = builder.execute().get(); - if (response2 != null) { - System.out.println("Success (2nd response was not null)."); - } else { - System.out.println("Failed (2nd response was null)."); + try { + final BoundRequestBuilder builder = client.prepareGet(VERISIGN_HTTPS_URL); + final Response response1 = builder.execute().get(); + Thread.sleep(5000); + final Response response2 = builder.execute().get(); + if (response2 != null) { + System.out.println("Success (2nd response was not null)."); + } else { + System.out.println("Failed (2nd response was null)."); + } + Assert.assertNotNull(response1); + Assert.assertNotNull(response2); + } finally { + client.close(); } - Assert.assertNotNull(response1); - Assert.assertNotNull(response2); - client.close(); } private AsyncHttpClient create() throws GeneralSecurityException { - final AsyncHttpClientConfig.Builder configBuilder = new AsyncHttpClientConfig.Builder() - .setCompressionEnabled(true) - .setFollowRedirects(true) - .setSSLContext(getSSLContext()) - .setAllowPoolingConnection(true) - .setConnectionTimeoutInMs(10000) - .setIdleConnectionInPoolTimeoutInMs(60000) - .setRequestTimeoutInMs(10000) - .setMaximumConnectionsPerHost(-1) - .setMaximumConnectionsTotal(-1); + final AsyncHttpClientConfig.Builder configBuilder = new AsyncHttpClientConfig.Builder().setCompressionEnabled(true).setFollowRedirects(true).setSSLContext(getSSLContext()).setAllowPoolingConnection(true).setConnectionTimeoutInMs(10000) + .setIdleConnectionInPoolTimeoutInMs(60000).setRequestTimeoutInMs(10000).setMaximumConnectionsPerHost(-1).setMaximumConnectionsTotal(-1); return getAsyncHttpClient(configBuilder.build()); } private SSLContext getSSLContext() throws GeneralSecurityException { final SSLContext sslContext = SSLContext.getInstance("TLS"); - sslContext.init(null, new TrustManager[]{new MockTrustManager()}, null); + sslContext.init(null, new TrustManager[] { new MockTrustManager() }, null); return sslContext; } diff --git a/src/test/java/com/ning/http/client/async/NonAsciiContentLengthTest.java b/src/test/java/com/ning/http/client/async/NonAsciiContentLengthTest.java index 80acc7942f..cebeb26e2c 100644 --- a/src/test/java/com/ning/http/client/async/NonAsciiContentLengthTest.java +++ b/src/test/java/com/ning/http/client/async/NonAsciiContentLengthTest.java @@ -36,61 +36,62 @@ public abstract class NonAsciiContentLengthTest extends AbstractBasicTest { + public void setUpServer() throws Exception { + server = new Server(); + port1 = findFreePort(); + Connector listener = new SelectChannelConnector(); - public void setUpServer() throws Exception { - server = new Server(); - port1 = findFreePort(); - Connector listener = new SelectChannelConnector(); + listener.setHost("127.0.0.1"); + listener.setPort(port1); + server.addConnector(listener); + server.setHandler(new AbstractHandler() { - listener.setHost("127.0.0.1"); - listener.setPort(port1); - server.addConnector(listener); - server.setHandler(new AbstractHandler() { + public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { + int MAX_BODY_SIZE = 1024; // Can only handle bodies of up to 1024 bytes. + byte[] b = new byte[MAX_BODY_SIZE]; + int offset = 0; + int numBytesRead; + ServletInputStream is = request.getInputStream(); + try { + while ((numBytesRead = is.read(b, offset, MAX_BODY_SIZE - offset)) != -1) { + offset += numBytesRead; + } + } finally { + is.close(); + } + assertEquals(request.getContentLength(), offset); + response.setStatus(200); + response.setCharacterEncoding(request.getCharacterEncoding()); + response.setContentLength(request.getContentLength()); + ServletOutputStream os = response.getOutputStream(); + try { + os.write(b, 0, offset); + } finally { + os.close(); + } + } + }); + server.start(); + } - public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) - throws IOException, ServletException { - int MAX_BODY_SIZE = 1024; //Can only handle bodies of up to 1024 bytes. - byte[] b = new byte[MAX_BODY_SIZE]; - int offset = 0; - int numBytesRead; - ServletInputStream is = request.getInputStream(); - try { - while ((numBytesRead = is.read(b, offset, MAX_BODY_SIZE - offset)) != -1) { - offset += numBytesRead; - } - } finally { - is.close(); - } - assertEquals(request.getContentLength(), offset); - response.setStatus(200); - response.setCharacterEncoding(request.getCharacterEncoding()); - response.setContentLength(request.getContentLength()); - ServletOutputStream os = response.getOutputStream(); - try { - os.write(b, 0, offset); - } finally { - os.close(); - } - } - }); - server.start(); - } + @Test(groups = { "standalone", "default_provider" }) + public void testNonAsciiContentLength() throws Exception { + setUpServer(); + execute("test"); + execute("\u4E00"); // Unicode CJK ideograph for one + } - @Test(groups = { "standalone", "default_provider" }) - public void testNonAsciiContentLength() throws Exception { - setUpServer(); - execute("test"); - execute("\u4E00"); // Unicode CJK ideograph for one - } - - protected void execute(String body) throws IOException, InterruptedException, ExecutionException { - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().build()); - BoundRequestBuilder r = client.preparePost(getTargetUrl()).setBody(body).setBodyEncoding("UTF-8"); - Future f = r.execute(); - Response resp = f.get(); - assertEquals(resp.getStatusCode(), 200); - assertEquals(body, resp.getResponseBody("UTF-8")); - client.close(); - } + protected void execute(String body) throws IOException, InterruptedException, ExecutionException { + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().build()); + try { + BoundRequestBuilder r = client.preparePost(getTargetUrl()).setBody(body).setBodyEncoding("UTF-8"); + Future f = r.execute(); + Response resp = f.get(); + assertEquals(resp.getStatusCode(), 200); + assertEquals(body, resp.getResponseBody("UTF-8")); + } finally { + client.close(); + } + } } diff --git a/src/test/java/com/ning/http/client/async/ParamEncodingTest.java b/src/test/java/com/ning/http/client/async/ParamEncodingTest.java index eb742de2d1..fc84431aaf 100644 --- a/src/test/java/com/ning/http/client/async/ParamEncodingTest.java +++ b/src/test/java/com/ning/http/client/async/ParamEncodingTest.java @@ -38,10 +38,7 @@ public abstract class ParamEncodingTest extends AbstractBasicTest { private class ParamEncoding extends AbstractHandler { - public void handle(String s, - Request r, - HttpServletRequest request, - HttpServletResponse response) throws IOException, ServletException { + public void handle(String s, Request r, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { if ("POST".equalsIgnoreCase(request.getMethod())) { String p = request.getParameter("test"); if (isNonEmpty(p)) { @@ -58,20 +55,20 @@ public void handle(String s, } } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void testParameters() throws IOException, ExecutionException, TimeoutException, InterruptedException { String value = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKQLMNOPQRSTUVWXYZ1234567809`~!@#$%^&*()_+-=,.<>/?;:'\"[]{}\\| "; AsyncHttpClient client = getAsyncHttpClient(null); - Future f = client - .preparePost("http://127.0.0.1/" + port1) - .addParameter("test", value) - .execute(); - Response resp = f.get(10, TimeUnit.SECONDS); - assertNotNull(resp); - assertEquals(resp.getStatusCode(), HttpServletResponse.SC_OK); - assertEquals(resp.getHeader("X-Param"), value.trim()); - client.close(); + try { + Future f = client.preparePost("http://127.0.0.1/" + port1).addParameter("test", value).execute(); + Response resp = f.get(10, TimeUnit.SECONDS); + assertNotNull(resp); + assertEquals(resp.getStatusCode(), HttpServletResponse.SC_OK); + assertEquals(resp.getHeader("X-Param"), value.trim()); + } finally { + client.close(); + } } @Override diff --git a/src/test/java/com/ning/http/client/async/PerRequestRelative302Test.java b/src/test/java/com/ning/http/client/async/PerRequestRelative302Test.java index 756a258339..e2bc68a31a 100644 --- a/src/test/java/com/ning/http/client/async/PerRequestRelative302Test.java +++ b/src/test/java/com/ning/http/client/async/PerRequestRelative302Test.java @@ -45,11 +45,7 @@ public abstract class PerRequestRelative302Test extends AbstractBasicTest { private class Relative302Handler extends AbstractHandler { - - public void handle(String s, - Request r, - HttpServletRequest httpRequest, - HttpServletResponse httpResponse) throws IOException, ServletException { + public void handle(String s, Request r, HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws IOException, ServletException { String param; httpResponse.setContentType("text/html; charset=utf-8"); @@ -89,46 +85,42 @@ public void setUpGlobal() throws Exception { log.info("Local HTTP server started successfully"); } - @Test(groups = {"online", "default_provider"}) + @Test(groups = { "online", "default_provider" }) public void redirected302Test() throws Throwable { isSet.getAndSet(false); AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().build(); AsyncHttpClient c = getAsyncHttpClient(cg); + try { + + // once + Response response = c.prepareGet(getTargetUrl()).setFollowRedirects(true).setHeader("X-redirect", "http://www.microsoft.com/").execute().get(); + + assertNotNull(response); + assertEquals(response.getStatusCode(), 200); - // once - Response response = c.prepareGet(getTargetUrl()) - .setFollowRedirects(true) - .setHeader("X-redirect", "http://www.microsoft.com/") - .execute().get(); - - assertNotNull(response); - assertEquals(response.getStatusCode(), 200); - - String anyMicrosoftPage = "http://www.microsoft.com[^:]*:80"; - String baseUrl = getBaseUrl(response.getUri()); - - c.close(); - - assertTrue(baseUrl.matches(anyMicrosoftPage), "response does not show redirection to " + anyMicrosoftPage); + String anyMicrosoftPage = "http://www.microsoft.com[^:]*:80"; + String baseUrl = getBaseUrl(response.getUri()); + + assertTrue(baseUrl.matches(anyMicrosoftPage), "response does not show redirection to " + anyMicrosoftPage); + } finally { + c.close(); + } } - @Test(groups = {"online", "default_provider"}) + @Test(groups = { "online", "default_provider" }) public void notRedirected302Test() throws Throwable { isSet.getAndSet(false); AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setFollowRedirects(true).build(); AsyncHttpClient c = getAsyncHttpClient(cg); + try { + // once + Response response = c.prepareGet(getTargetUrl()).setFollowRedirects(false).setHeader("X-redirect", "http://www.microsoft.com/").execute().get(); - - // once - Response response = c.prepareGet(getTargetUrl()) - .setFollowRedirects(false) - .setHeader("X-redirect", "http://www.microsoft.com/") - .execute().get(); - - assertNotNull(response); - assertEquals(response.getStatusCode(), 302); - - c.close(); + assertNotNull(response); + assertEquals(response.getStatusCode(), 302); + } finally { + c.close(); + } } private String getBaseUrl(URI uri) { @@ -148,7 +140,7 @@ private static int getPort(URI uri) { return port; } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void redirected302InvalidTest() throws Throwable { isSet.getAndSet(false); AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().build(); @@ -156,33 +148,30 @@ public void redirected302InvalidTest() throws Throwable { // If the test hit a proxy, no ConnectException will be thrown and instead of 404 will be returned. try { - Response response = c.preparePost(getTargetUrl()) - .setFollowRedirects(true) - .setHeader("X-redirect", String.format("http://127.0.0.1:%d/", port2)) - .execute().get(); + Response response = c.preparePost(getTargetUrl()).setFollowRedirects(true).setHeader("X-redirect", String.format("http://127.0.0.1:%d/", port2)).execute().get(); assertNotNull(response); assertEquals(response.getStatusCode(), 404); } catch (ExecutionException ex) { assertEquals(ex.getCause().getClass(), ConnectException.class); + } finally { + c.close(); } - c.close(); } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void relativeLocationUrl() throws Throwable { isSet.getAndSet(false); AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().build(); AsyncHttpClient c = getAsyncHttpClient(cg); - - Response response = c.preparePost(getTargetUrl()) - .setFollowRedirects(true) - .setHeader("X-redirect", "/foo/test") - .execute().get(); - assertNotNull(response); - assertEquals(response.getStatusCode(), 302); - assertEquals(response.getUri().toString(), getTargetUrl()); - c.close(); + try { + Response response = c.preparePost(getTargetUrl()).setFollowRedirects(true).setHeader("X-redirect", "/foo/test").execute().get(); + assertNotNull(response); + assertEquals(response.getStatusCode(), 302); + assertEquals(response.getUri().toString(), getTargetUrl()); + } finally { + c.close(); + } } } diff --git a/src/test/java/com/ning/http/client/async/PerRequestTimeoutTest.java b/src/test/java/com/ning/http/client/async/PerRequestTimeoutTest.java index e50bee78de..72de9b9930 100644 --- a/src/test/java/com/ning/http/client/async/PerRequestTimeoutTest.java +++ b/src/test/java/com/ning/http/client/async/PerRequestTimeoutTest.java @@ -1,18 +1,18 @@ /* -* Copyright 2010 Ning, Inc. -* -* Ning licenses this file to you under the Apache License, version 2.0 -* (the "License"); you may not use this file except in compliance with the -* License. You may obtain a copy of the License at: -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -* License for the specific language governing permissions and limitations -* under the License. -*/ + * Copyright 2010 Ning, Inc. + * + * Ning licenses this file to you under the Apache License, version 2.0 + * (the "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ package com.ning.http.client.async; import com.ning.http.client.AsyncCompletionHandler; @@ -44,7 +44,7 @@ /** * Per request timeout configuration test. - * + * * @author Hubert Iwaniuk */ public abstract class PerRequestTimeoutTest extends AbstractBasicTest { @@ -95,14 +95,13 @@ public void run() { } } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void testRequestTimeout() throws IOException { AsyncHttpClient client = getAsyncHttpClient(null); PerRequestConfig requestConfig = new PerRequestConfig(); requestConfig.setRequestTimeoutInMs(100); - Future responseFuture = - client.prepareGet(getTargetUrl()).setPerRequestConfig(requestConfig).execute(); try { + Future responseFuture = client.prepareGet(getTargetUrl()).setPerRequestConfig(requestConfig).execute(); Response response = responseFuture.get(2000, TimeUnit.MILLISECONDS); assertNull(response); client.close(); @@ -113,18 +112,18 @@ public void testRequestTimeout() throws IOException { assertEquals(e.getCause().getMessage(), getExpectedTimeoutMessage()); } catch (TimeoutException e) { fail("Timeout.", e); + } finally { + client.close(); } - client.close(); } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void testGlobalDefaultPerRequestInfiniteTimeout() throws IOException { AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeoutInMs(100).build()); PerRequestConfig requestConfig = new PerRequestConfig(); requestConfig.setRequestTimeoutInMs(-1); - Future responseFuture = - client.prepareGet(getTargetUrl()).setPerRequestConfig(requestConfig).execute(); try { + Future responseFuture = client.prepareGet(getTargetUrl()).setPerRequestConfig(requestConfig).execute(); Response response = responseFuture.get(); assertNotNull(response); client.close(); @@ -133,15 +132,16 @@ public void testGlobalDefaultPerRequestInfiniteTimeout() throws IOException { } catch (ExecutionException e) { assertTrue(e.getCause() instanceof TimeoutException); assertEquals(e.getCause().getMessage(), getExpectedTimeoutMessage()); + } finally { + client.close(); } - client.close(); } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void testGlobalRequestTimeout() throws IOException { AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeoutInMs(100).build()); - Future responseFuture = client.prepareGet(getTargetUrl()).execute(); try { + Future responseFuture = client.prepareGet(getTargetUrl()).execute(); Response response = responseFuture.get(2000, TimeUnit.MILLISECONDS); assertNull(response); client.close(); @@ -152,44 +152,45 @@ public void testGlobalRequestTimeout() throws IOException { assertEquals(e.getCause().getMessage(), getExpectedTimeoutMessage()); } catch (TimeoutException e) { fail("Timeout.", e); + } finally { + client.close(); } - client.close(); } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void testGlobalIdleTimeout() throws IOException { - final long times[] = new long[]{-1, -1}; + final long times[] = new long[] { -1, -1 }; AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setIdleConnectionInPoolTimeoutInMs(2000).build()); - Future responseFuture = client.prepareGet(getTargetUrl()).execute(new AsyncCompletionHandler() { - @Override - public Response onCompleted(Response response) throws Exception { - return response; - } + try { + Future responseFuture = client.prepareGet(getTargetUrl()).execute(new AsyncCompletionHandler() { + @Override + public Response onCompleted(Response response) throws Exception { + return response; + } - @Override - public STATE onBodyPartReceived(HttpResponseBodyPart content) throws Exception { - times[0] = System.currentTimeMillis(); - return super.onBodyPartReceived(content); - } + @Override + public STATE onBodyPartReceived(HttpResponseBodyPart content) throws Exception { + times[0] = System.currentTimeMillis(); + return super.onBodyPartReceived(content); + } - @Override - public void onThrowable(Throwable t) { - times[1] = System.currentTimeMillis(); - super.onThrowable(t); - } - }); - try { + @Override + public void onThrowable(Throwable t) { + times[1] = System.currentTimeMillis(); + super.onThrowable(t); + } + }); Response response = responseFuture.get(); assertNotNull(response); assertEquals(response.getResponseBody(), MSG + MSG); } catch (InterruptedException e) { fail("Interrupted.", e); } catch (ExecutionException e) { - log.info(String.format("\n@%dms Last body part received\n@%dms Connection killed\n %dms difference.", - times[0], times[1], (times[1] - times[0]))); + log.info(String.format("\n@%dms Last body part received\n@%dms Connection killed\n %dms difference.", times[0], times[1], (times[1] - times[0]))); fail("Timeouted on idle.", e); + } finally { + client.close(); } - client.close(); } } diff --git a/src/test/java/com/ning/http/client/async/PostRedirectGetTest.java b/src/test/java/com/ning/http/client/async/PostRedirectGetTest.java index 658673384b..e581b9f8ab 100644 --- a/src/test/java/com/ning/http/client/async/PostRedirectGetTest.java +++ b/src/test/java/com/ning/http/client/async/PostRedirectGetTest.java @@ -35,10 +35,8 @@ public abstract class PostRedirectGetTest extends AbstractBasicTest { - // ------------------------------------------------------ Test Configuration - @Override public AbstractHandler configureHandler() throws Exception { return new PostRedirectGetHandler(); @@ -46,123 +44,111 @@ public AbstractHandler configureHandler() throws Exception { // ------------------------------------------------------------ Test Methods - @Test(groups = {"standalone", "post_redirect_get"}) + @Test(groups = { "standalone", "post_redirect_get" }) public void postRedirectGet302Test() throws Exception { doTestPositive(302); } - @Test(groups = {"standalone", "post_redirect_get"}) + @Test(groups = { "standalone", "post_redirect_get" }) public void postRedirectGet302StrictTest() throws Exception { doTestNegative(302, true); } - @Test(groups = {"standalone", "post_redirect_get"}) + @Test(groups = { "standalone", "post_redirect_get" }) public void postRedirectGet303Test() throws Exception { doTestPositive(303); } - @Test(groups = {"standalone", "post_redirect_get"}) + @Test(groups = { "standalone", "post_redirect_get" }) public void postRedirectGet301Test() throws Exception { doTestNegative(301, false); } - @Test(groups = {"standalone", "post_redirect_get"}) + @Test(groups = { "standalone", "post_redirect_get" }) public void postRedirectGet307Test() throws Exception { doTestNegative(307, false); } - // --------------------------------------------------------- Private Methods - private void doTestNegative(final int status, boolean strict) throws Exception { - AsyncHttpClient p = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setFollowRedirects(true). - setStrict302Handling(strict). - addResponseFilter(new ResponseFilter() { - @Override - public FilterContext filter(FilterContext ctx) throws FilterException { - // pass on the x-expect-get and remove the x-redirect - // headers if found in the response - ctx.getResponseHeaders().getHeaders().get("x-expect-post"); - ctx.getRequest().getHeaders().add("x-expect-post", "true"); - ctx.getRequest().getHeaders().remove("x-redirect"); - return ctx; - } - }).build()); - Request request = new RequestBuilder("POST").setUrl(getTargetUrl()) - .addParameter("q", "a b") - .addHeader("x-redirect", +status + "@" + "http://localhost/" + port1 + "/foo/bar/baz") - .addHeader("x-negative", "true") - .build(); - Future responseFuture = p.executeRequest(request, new AsyncCompletionHandler() { - + AsyncHttpClient p = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setFollowRedirects(true).setStrict302Handling(strict).addResponseFilter(new ResponseFilter() { @Override - public Integer onCompleted(Response response) throws Exception { - return response.getStatusCode(); + public FilterContext filter(FilterContext ctx) throws FilterException { + // pass on the x-expect-get and remove the x-redirect + // headers if found in the response + ctx.getResponseHeaders().getHeaders().get("x-expect-post"); + ctx.getRequest().getHeaders().add("x-expect-post", "true"); + ctx.getRequest().getHeaders().remove("x-redirect"); + return ctx; } + }).build()); + try { + Request request = new RequestBuilder("POST").setUrl(getTargetUrl()).addParameter("q", "a b").addHeader("x-redirect", +status + "@" + "http://localhost/" + port1 + "/foo/bar/baz").addHeader("x-negative", "true").build(); + Future responseFuture = p.executeRequest(request, new AsyncCompletionHandler() { + + @Override + public Integer onCompleted(Response response) throws Exception { + return response.getStatusCode(); + } - /* @Override */ - public void onThrowable(Throwable t) { - t.printStackTrace(); - Assert.fail("Unexpected exception: " + t.getMessage(), t); - } + /* @Override */ + public void onThrowable(Throwable t) { + t.printStackTrace(); + Assert.fail("Unexpected exception: " + t.getMessage(), t); + } - }); - int statusCode = responseFuture.get(); - Assert.assertEquals(statusCode, 200); - p.close(); + }); + int statusCode = responseFuture.get(); + Assert.assertEquals(statusCode, 200); + } finally { + p.close(); + } } - private void doTestPositive(final int status) throws Exception { - AsyncHttpClient p = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setFollowRedirects(true). - addResponseFilter(new ResponseFilter() { - @Override - public FilterContext filter(FilterContext ctx) throws FilterException { - // pass on the x-expect-get and remove the x-redirect - // headers if found in the response - ctx.getResponseHeaders().getHeaders().get("x-expect-get"); - ctx.getRequest().getHeaders().add("x-expect-get", "true"); - ctx.getRequest().getHeaders().remove("x-redirect"); - return ctx; - } - }).build()); - Request request = new RequestBuilder("POST").setUrl(getTargetUrl()) - .addParameter("q", "a b") - .addHeader("x-redirect", +status + "@" + "http://localhost/" + port1 + "/foo/bar/baz") - .build(); - Future responseFuture = p.executeRequest(request, new AsyncCompletionHandler() { - + AsyncHttpClient p = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setFollowRedirects(true).addResponseFilter(new ResponseFilter() { @Override - public Integer onCompleted(Response response) throws Exception { - return response.getStatusCode(); + public FilterContext filter(FilterContext ctx) throws FilterException { + // pass on the x-expect-get and remove the x-redirect + // headers if found in the response + ctx.getResponseHeaders().getHeaders().get("x-expect-get"); + ctx.getRequest().getHeaders().add("x-expect-get", "true"); + ctx.getRequest().getHeaders().remove("x-redirect"); + return ctx; } + }).build()); + try { + Request request = new RequestBuilder("POST").setUrl(getTargetUrl()).addParameter("q", "a b").addHeader("x-redirect", +status + "@" + "http://localhost/" + port1 + "/foo/bar/baz").build(); + Future responseFuture = p.executeRequest(request, new AsyncCompletionHandler() { + + @Override + public Integer onCompleted(Response response) throws Exception { + return response.getStatusCode(); + } - /* @Override */ - public void onThrowable(Throwable t) { - t.printStackTrace(); - Assert.fail("Unexpected exception: " + t.getMessage(), t); - } + /* @Override */ + public void onThrowable(Throwable t) { + t.printStackTrace(); + Assert.fail("Unexpected exception: " + t.getMessage(), t); + } - }); - int statusCode = responseFuture.get(); - Assert.assertEquals(statusCode, 200); - p.close(); + }); + int statusCode = responseFuture.get(); + Assert.assertEquals(statusCode, 200); + } finally { + p.close(); + } } - // ---------------------------------------------------------- Nested Classes - public static class PostRedirectGetHandler extends AbstractHandler { final AtomicInteger counter = new AtomicInteger(); /* @Override */ - public void handle(String pathInContext, - org.eclipse.jetty.server.Request request, - HttpServletRequest httpRequest, - HttpServletResponse httpResponse) throws IOException, ServletException { + public void handle(String pathInContext, org.eclipse.jetty.server.Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws IOException, ServletException { final boolean expectGet = (httpRequest.getHeader("x-expect-get") != null); final boolean expectPost = (httpRequest.getHeader("x-expect-post") != null); @@ -212,7 +198,6 @@ public void handle(String pathInContext, return; } - httpResponse.sendError(500); httpResponse.getOutputStream().flush(); httpResponse.getOutputStream().close(); diff --git a/src/test/java/com/ning/http/client/async/PostWithQSTest.java b/src/test/java/com/ning/http/client/async/PostWithQSTest.java index dc214579cf..39cb9e1c7b 100644 --- a/src/test/java/com/ning/http/client/async/PostWithQSTest.java +++ b/src/test/java/com/ning/http/client/async/PostWithQSTest.java @@ -41,7 +41,7 @@ /** * Tests POST request with Query String. - * + * * @author Hubert Iwaniuk */ public abstract class PostWithQSTest extends AbstractBasicTest { @@ -50,10 +50,7 @@ public abstract class PostWithQSTest extends AbstractBasicTest { * POST with QS server part. */ private class PostWithQSHandler extends AbstractHandler { - public void handle(String s, - Request r, - HttpServletRequest request, - HttpServletResponse response) throws IOException, ServletException { + public void handle(String s, Request r, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { if ("POST".equalsIgnoreCase(request.getMethod())) { String qs = request.getQueryString(); if (isNonEmpty(qs) && request.getContentLength() == 3) { @@ -74,54 +71,63 @@ public void handle(String s, } } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void postWithQS() throws IOException, ExecutionException, TimeoutException, InterruptedException { AsyncHttpClient client = getAsyncHttpClient(null); - Future f = client.preparePost("http://127.0.0.1/" + port1 + "/?a=b").setBody("abc".getBytes()).execute(); - Response resp = f.get(3, TimeUnit.SECONDS); - assertNotNull(resp); - assertEquals(resp.getStatusCode(), HttpServletResponse.SC_OK); - client.close(); + try { + Future f = client.preparePost("http://127.0.0.1/" + port1 + "/?a=b").setBody("abc".getBytes()).execute(); + Response resp = f.get(3, TimeUnit.SECONDS); + assertNotNull(resp); + assertEquals(resp.getStatusCode(), HttpServletResponse.SC_OK); + } finally { + client.close(); + } } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void postWithNulParamQS() throws IOException, ExecutionException, TimeoutException, InterruptedException { AsyncHttpClient client = getAsyncHttpClient(null); - Future f = client.preparePost("http://127.0.0.1/" + port1 + "/?a=").setBody("abc".getBytes()).execute(new AsyncCompletionHandlerBase() { + try { + Future f = client.preparePost("http://127.0.0.1/" + port1 + "/?a=").setBody("abc".getBytes()).execute(new AsyncCompletionHandlerBase() { - /* @Override */ - public STATE onStatusReceived(final HttpResponseStatus status) throws Exception { - if (!status.getUrl().toURL().toString().equals("http://127.0.0.1/" + port1 + "/?a=")) { - throw new IOException(status.getUrl().toURL().toString()); + /* @Override */ + public STATE onStatusReceived(final HttpResponseStatus status) throws Exception { + if (!status.getUrl().toURL().toString().equals("http://127.0.0.1/" + port1 + "/?a=")) { + throw new IOException(status.getUrl().toURL().toString()); + } + return super.onStatusReceived(status); } - return super.onStatusReceived(status); - } - }); - Response resp = f.get(3, TimeUnit.SECONDS); - assertNotNull(resp); - assertEquals(resp.getStatusCode(), HttpServletResponse.SC_OK); - client.close(); + }); + Response resp = f.get(3, TimeUnit.SECONDS); + assertNotNull(resp); + assertEquals(resp.getStatusCode(), HttpServletResponse.SC_OK); + } finally { + client.close(); + } } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void postWithNulParamsQS() throws IOException, ExecutionException, TimeoutException, InterruptedException { AsyncHttpClient client = getAsyncHttpClient(null); - Future f = client.preparePost("http://127.0.0.1/" + port1 + "/?a=b&c&d=e").setBody("abc".getBytes()).execute(new AsyncCompletionHandlerBase() { + try { + Future f = client.preparePost("http://127.0.0.1/" + port1 + "/?a=b&c&d=e").setBody("abc".getBytes()).execute(new AsyncCompletionHandlerBase() { - /* @Override */ - public STATE onStatusReceived(final HttpResponseStatus status) throws Exception { - if (!status.getUrl().toURL().toString().equals("http://127.0.0.1/" + port1 + "/?a=b&c=&d=e")) { - throw new IOException("failed to parse the query properly"); + /* @Override */ + public STATE onStatusReceived(final HttpResponseStatus status) throws Exception { + if (!status.getUrl().toURL().toString().equals("http://127.0.0.1/" + port1 + "/?a=b&c=&d=e")) { + throw new IOException("failed to parse the query properly"); + } + return super.onStatusReceived(status); } - return super.onStatusReceived(status); - } - }); - Response resp = f.get(3, TimeUnit.SECONDS); - assertNotNull(resp); - assertEquals(resp.getStatusCode(), HttpServletResponse.SC_OK); - client.close(); + }); + Response resp = f.get(3, TimeUnit.SECONDS); + assertNotNull(resp); + assertEquals(resp.getStatusCode(), HttpServletResponse.SC_OK); + } finally { + client.close(); + } } @Override diff --git a/src/test/java/com/ning/http/client/async/ProviderUtil.java b/src/test/java/com/ning/http/client/async/ProviderUtil.java index 70f79dc94c..17cdbe33d1 100644 --- a/src/test/java/com/ning/http/client/async/ProviderUtil.java +++ b/src/test/java/com/ning/http/client/async/ProviderUtil.java @@ -1,28 +1,28 @@ /* -* Copyright 2010 Ning, Inc. -* -* Ning licenses this file to you under the Apache License, version 2.0 -* (the "License"); you may not use this file except in compliance with the -* License. You may obtain a copy of the License at: -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -* License for the specific language governing permissions and limitations -* under the License. -*/ + * Copyright 2010 Ning, Inc. + * + * Ning licenses this file to you under the Apache License, version 2.0 + * (the "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ package com.ning.http.client.async; import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.providers.apache.ApacheAsyncHttpProvider; +import com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProvider; import com.ning.http.client.providers.jdk.JDKAsyncHttpProvider; public class ProviderUtil { - public static AsyncHttpClient nettyProvider(AsyncHttpClientConfig config) { if (config == null) { return new AsyncHttpClient(); @@ -31,6 +31,13 @@ public static AsyncHttpClient nettyProvider(AsyncHttpClientConfig config) { } } + public static AsyncHttpClient grizzlyProvider(AsyncHttpClientConfig config) { + if (config == null) { + config = new AsyncHttpClientConfig.Builder().build(); + } + return new AsyncHttpClient(new GrizzlyAsyncHttpProvider(config), config); + } + public static AsyncHttpClient apacheProvider(AsyncHttpClientConfig config) { if (config == null) { return new AsyncHttpClient(new ApacheAsyncHttpProvider(new AsyncHttpClientConfig.Builder().build())); diff --git a/src/test/java/com/ning/http/client/async/ProxyTest.java b/src/test/java/com/ning/http/client/async/ProxyTest.java index 941897ce0c..8a67a6fa7f 100644 --- a/src/test/java/com/ning/http/client/async/ProxyTest.java +++ b/src/test/java/com/ning/http/client/async/ProxyTest.java @@ -21,8 +21,6 @@ import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.ProxyServer; import com.ning.http.client.Response; -import com.ning.http.client.ProxyServer.Protocol; -import com.ning.http.util.ProxyUtils; import java.io.IOException; import java.net.ConnectException; @@ -42,15 +40,12 @@ /** * Proxy usage tests. - * + * * @author Hubert Iwaniuk */ public abstract class ProxyTest extends AbstractBasicTest { private class ProxyHandler extends AbstractHandler { - public void handle(String s, - Request r, - HttpServletRequest request, - HttpServletResponse response) throws IOException, ServletException { + public void handle(String s, Request r, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { if ("GET".equalsIgnoreCase(request.getMethod())) { response.addHeader("target", r.getUri().getPath()); response.setStatus(HttpServletResponse.SC_OK); @@ -66,73 +61,68 @@ public AbstractHandler configureHandler() throws Exception { return new ProxyHandler(); } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void testRequestLevelProxy() throws IOException, ExecutionException, TimeoutException, InterruptedException { AsyncHttpClient client = getAsyncHttpClient(null); - String target = "http://127.0.0.1:1234/"; - Future f = client - .prepareGet(target) - .setProxyServer(new ProxyServer("127.0.0.1", port1)) - .execute(); - Response resp = f.get(3, TimeUnit.SECONDS); - assertNotNull(resp); - assertEquals(resp.getStatusCode(), HttpServletResponse.SC_OK); - assertEquals(resp.getHeader("target"), "/"); - client.close(); + try { + String target = "http://127.0.0.1:1234/"; + Future f = client.prepareGet(target).setProxyServer(new ProxyServer("127.0.0.1", port1)).execute(); + Response resp = f.get(3, TimeUnit.SECONDS); + assertNotNull(resp); + assertEquals(resp.getStatusCode(), HttpServletResponse.SC_OK); + assertEquals(resp.getHeader("target"), "/"); + } finally { + client.close(); + } } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void testGlobalProxy() throws IOException, ExecutionException, TimeoutException, InterruptedException { - AsyncHttpClientConfig cfg - = new AsyncHttpClientConfig.Builder().setProxyServer(new ProxyServer("127.0.0.1", port1)).build(); + AsyncHttpClientConfig cfg = new AsyncHttpClientConfig.Builder().setProxyServer(new ProxyServer("127.0.0.1", port1)).build(); AsyncHttpClient client = getAsyncHttpClient(cfg); - String target = "http://127.0.0.1:1234/"; - Future f = client - .prepareGet(target) - .execute(); - Response resp = f.get(3, TimeUnit.SECONDS); - assertNotNull(resp); - assertEquals(resp.getStatusCode(), HttpServletResponse.SC_OK); - assertEquals(resp.getHeader("target"), "/"); - client.close(); + try { + String target = "http://127.0.0.1:1234/"; + Future f = client.prepareGet(target).execute(); + Response resp = f.get(3, TimeUnit.SECONDS); + assertNotNull(resp); + assertEquals(resp.getStatusCode(), HttpServletResponse.SC_OK); + assertEquals(resp.getHeader("target"), "/"); + } finally { + client.close(); + } } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void testBothProxies() throws IOException, ExecutionException, TimeoutException, InterruptedException { - AsyncHttpClientConfig cfg - = new AsyncHttpClientConfig.Builder().setProxyServer(new ProxyServer("127.0.0.1", port1 - 1)).build(); + AsyncHttpClientConfig cfg = new AsyncHttpClientConfig.Builder().setProxyServer(new ProxyServer("127.0.0.1", port1 - 1)).build(); AsyncHttpClient client = getAsyncHttpClient(cfg); - String target = "http://127.0.0.1:1234/"; - Future f = client - .prepareGet(target) - .setProxyServer(new ProxyServer("127.0.0.1", port1)) - .execute(); - Response resp = f.get(3, TimeUnit.SECONDS); - assertNotNull(resp); - assertEquals(resp.getStatusCode(), HttpServletResponse.SC_OK); - assertEquals(resp.getHeader("target"), "/"); - client.close(); + try { + String target = "http://127.0.0.1:1234/"; + Future f = client.prepareGet(target).setProxyServer(new ProxyServer("127.0.0.1", port1)).execute(); + Response resp = f.get(3, TimeUnit.SECONDS); + assertNotNull(resp); + assertEquals(resp.getStatusCode(), HttpServletResponse.SC_OK); + assertEquals(resp.getHeader("target"), "/"); + } finally { + client.close(); + } } - - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void testNonProxyHosts() throws IOException, ExecutionException, TimeoutException, InterruptedException { - AsyncHttpClientConfig cfg - = new AsyncHttpClientConfig.Builder().setProxyServer(new ProxyServer("127.0.0.1", port1 - 1)).build(); + AsyncHttpClientConfig cfg = new AsyncHttpClientConfig.Builder().setProxyServer(new ProxyServer("127.0.0.1", port1 - 1)).build(); AsyncHttpClient client = getAsyncHttpClient(cfg); try { String target = "http://127.0.0.1:1234/"; - client.prepareGet(target) - .setProxyServer(new ProxyServer("127.0.0.1", port1).addNonProxyHost("127.0.0.1")) - .execute().get(); + client.prepareGet(target).setProxyServer(new ProxyServer("127.0.0.1", port1).addNonProxyHost("127.0.0.1")).execute().get(); assertFalse(true); } catch (Throwable e) { assertNotNull(e.getCause()); assertEquals(e.getCause().getClass(), ConnectException.class); + } finally { + client.close(); } - - client.close(); } @Test(groups = { "standalone", "default_provider" }) @@ -150,29 +140,31 @@ public void testProxyProperties() throws IOException, ExecutionException, Timeou AsyncHttpClientConfig cfg = new AsyncHttpClientConfig.Builder().setUseProxyProperties(true).build(); AsyncHttpClient client = getAsyncHttpClient(cfg); - - String target = "http://127.0.0.1:1234/"; - Future f = client.prepareGet(target).execute(); - Response resp = f.get(3, TimeUnit.SECONDS); - assertNotNull(resp); - assertEquals(resp.getStatusCode(), HttpServletResponse.SC_OK); - assertEquals(resp.getHeader("target"), "/"); - - target = "http://localhost:1234/"; - f = client.prepareGet(target).execute(); try { - resp = f.get(3, TimeUnit.SECONDS); - fail("should not be able to connect"); - } catch (ExecutionException e) { - // ok, no proxy used + String target = "http://127.0.0.1:1234/"; + Future f = client.prepareGet(target).execute(); + Response resp = f.get(3, TimeUnit.SECONDS); + assertNotNull(resp); + assertEquals(resp.getStatusCode(), HttpServletResponse.SC_OK); + assertEquals(resp.getHeader("target"), "/"); + + target = "http://localhost:1234/"; + f = client.prepareGet(target).execute(); + try { + resp = f.get(3, TimeUnit.SECONDS); + fail("should not be able to connect"); + } catch (ExecutionException e) { + // ok, no proxy used + } + + } finally { + client.close(); } - - client.close(); } finally { System.setProperties(originalProps); } } - + @Test(groups = { "standalone", "default_provider" }) public void testIgnoreProxyPropertiesByDefault() throws IOException, ExecutionException, TimeoutException, InterruptedException { Properties originalProps = System.getProperties(); @@ -188,22 +180,24 @@ public void testIgnoreProxyPropertiesByDefault() throws IOException, ExecutionEx AsyncHttpClientConfig cfg = new AsyncHttpClientConfig.Builder().build(); AsyncHttpClient client = getAsyncHttpClient(cfg); - - String target = "http://127.0.0.1:1234/"; - Future f = client.prepareGet(target).execute(); try { - f.get(3, TimeUnit.SECONDS); - fail("should not be able to connect"); - } catch (ExecutionException e) { - // ok, no proxy used + String target = "http://127.0.0.1:1234/"; + Future f = client.prepareGet(target).execute(); + try { + f.get(3, TimeUnit.SECONDS); + fail("should not be able to connect"); + } catch (ExecutionException e) { + // ok, no proxy used + } + + } finally { + client.close(); } - - client.close(); } finally { System.setProperties(originalProps); } } - + @Test(groups = { "standalone", "default_provider" }) public void testProxyActivationProperty() throws IOException, ExecutionException, TimeoutException, InterruptedException { Properties originalProps = System.getProperties(); @@ -220,27 +214,28 @@ public void testProxyActivationProperty() throws IOException, ExecutionException AsyncHttpClientConfig cfg = new AsyncHttpClientConfig.Builder().build(); AsyncHttpClient client = getAsyncHttpClient(cfg); - - String target = "http://127.0.0.1:1234/"; - Future f = client.prepareGet(target).execute(); - Response resp = f.get(3, TimeUnit.SECONDS); - assertNotNull(resp); - assertEquals(resp.getStatusCode(), HttpServletResponse.SC_OK); - assertEquals(resp.getHeader("target"), "/"); - - target = "http://localhost:1234/"; - f = client.prepareGet(target).execute(); try { - resp = f.get(3, TimeUnit.SECONDS); - fail("should not be able to connect"); - } catch (ExecutionException e) { - // ok, no proxy used + String target = "http://127.0.0.1:1234/"; + Future f = client.prepareGet(target).execute(); + Response resp = f.get(3, TimeUnit.SECONDS); + assertNotNull(resp); + assertEquals(resp.getStatusCode(), HttpServletResponse.SC_OK); + assertEquals(resp.getHeader("target"), "/"); + + target = "http://localhost:1234/"; + f = client.prepareGet(target).execute(); + try { + resp = f.get(3, TimeUnit.SECONDS); + fail("should not be able to connect"); + } catch (ExecutionException e) { + // ok, no proxy used + } + + } finally { + client.close(); } - - client.close(); } finally { System.setProperties(originalProps); } } - } diff --git a/src/test/java/com/ning/http/client/async/ProxyyTunnellingTest.java b/src/test/java/com/ning/http/client/async/ProxyyTunnellingTest.java index 9d5bb3ed28..da2a0756f3 100644 --- a/src/test/java/com/ning/http/client/async/ProxyyTunnellingTest.java +++ b/src/test/java/com/ning/http/client/async/ProxyyTunnellingTest.java @@ -88,7 +88,7 @@ public void setUpGlobal() throws Exception { log.info("Local HTTP server started successfully"); } - @Test(groups = {"online", "default_provider"}) + @Test(groups = { "online", "default_provider" }) public void testRequestProxy() throws IOException, InterruptedException, ExecutionException, TimeoutException { AsyncHttpClientConfig.Builder b = new AsyncHttpClientConfig.Builder(); b.setFollowRedirects(true); @@ -97,28 +97,30 @@ public void testRequestProxy() throws IOException, InterruptedException, Executi AsyncHttpClientConfig config = b.build(); AsyncHttpClient asyncHttpClient = getAsyncHttpClient(config); - - RequestBuilder rb = new RequestBuilder("GET").setProxyServer(ps).setUrl(getTargetUrl2()); - Future responseFuture = asyncHttpClient.executeRequest(rb.build(), new AsyncCompletionHandlerBase() { - - public void onThrowable(Throwable t) { - t.printStackTrace(); - log.debug(t.getMessage(), t); - } - - @Override - public Response onCompleted(Response response) throws Exception { - return response; - } - }); - Response r = responseFuture.get(); - assertEquals(r.getStatusCode(), 200); - assertEquals(r.getHeader("X-Proxy-Connection"), "keep-alive"); - - asyncHttpClient.close(); + try { + RequestBuilder rb = new RequestBuilder("GET").setProxyServer(ps).setUrl(getTargetUrl2()); + Future responseFuture = asyncHttpClient.executeRequest(rb.build(), new AsyncCompletionHandlerBase() { + + public void onThrowable(Throwable t) { + t.printStackTrace(); + log.debug(t.getMessage(), t); + } + + @Override + public Response onCompleted(Response response) throws Exception { + return response; + } + }); + Response r = responseFuture.get(); + assertEquals(r.getStatusCode(), 200); + assertEquals(r.getHeader("X-Proxy-Connection"), "keep-alive"); + + } finally { + asyncHttpClient.close(); + } } - @Test(groups = {"online", "default_provider"}) + @Test(groups = { "online", "default_provider" }) public void testConfigProxy() throws IOException, InterruptedException, ExecutionException, TimeoutException { AsyncHttpClientConfig.Builder b = new AsyncHttpClientConfig.Builder(); b.setFollowRedirects(true); @@ -128,60 +130,53 @@ public void testConfigProxy() throws IOException, InterruptedException, Executio AsyncHttpClientConfig config = b.build(); AsyncHttpClient asyncHttpClient = getAsyncHttpClient(config); - - RequestBuilder rb = new RequestBuilder("GET").setUrl(getTargetUrl2()); - Future responseFuture = asyncHttpClient.executeRequest(rb.build(), new AsyncCompletionHandlerBase() { - - public void onThrowable(Throwable t) { - t.printStackTrace(); - log.debug(t.getMessage(), t); - } - - @Override - public Response onCompleted(Response response) throws Exception { - return response; - } - }); - Response r = responseFuture.get(); - assertEquals(r.getStatusCode(), 200); - assertEquals(r.getHeader("X-Proxy-Connection"), "keep-alive"); - - asyncHttpClient.close(); + try { + RequestBuilder rb = new RequestBuilder("GET").setUrl(getTargetUrl2()); + Future responseFuture = asyncHttpClient.executeRequest(rb.build(), new AsyncCompletionHandlerBase() { + + public void onThrowable(Throwable t) { + t.printStackTrace(); + log.debug(t.getMessage(), t); + } + + @Override + public Response onCompleted(Response response) throws Exception { + return response; + } + }); + Response r = responseFuture.get(); + assertEquals(r.getStatusCode(), 200); + assertEquals(r.getHeader("X-Proxy-Connection"), "keep-alive"); + } finally { + asyncHttpClient.close(); + } } - @Test(groups = {"online", "default_provider"}) + @Test(groups = { "online", "default_provider" }) public void testSimpleAHCConfigProxy() throws IOException, InterruptedException, ExecutionException, TimeoutException { - SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder() - .setProxyProtocol(ProxyServer.Protocol.HTTPS) - .setProxyHost("127.0.0.1") - .setProxyPort(port1) - .setFollowRedirects(true) - .setUrl(getTargetUrl2()) - .setHeader("Content-Type", "text/html").build(); - - StringBuffer s = new StringBuffer(); - Response r = client.get().get(); + SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setProxyProtocol(ProxyServer.Protocol.HTTPS).setProxyHost("127.0.0.1").setProxyPort(port1).setFollowRedirects(true).setUrl(getTargetUrl2()).setHeader("Content-Type", "text/html").build(); + try { + Response r = client.get().get(); - assertEquals(r.getStatusCode(), 200); - assertEquals(r.getHeader("X-Proxy-Connection"), "keep-alive"); - - client.close(); + assertEquals(r.getStatusCode(), 200); + assertEquals(r.getHeader("X-Proxy-Connection"), "keep-alive"); + } finally { + client.close(); + } } @Test(groups = { "standalone", "default_provider" }) public void testNonProxyHostsSsl() throws IOException, ExecutionException, TimeoutException, InterruptedException { AsyncHttpClient client = getAsyncHttpClient(null); - - Response resp = client.prepareGet(getTargetUrl2()).setProxyServer(new ProxyServer("127.0.0.1", port1 - 1) - .addNonProxyHost("127.0.0.1")) - .execute().get(3, TimeUnit.SECONDS); - - assertNotNull(resp); - assertEquals(resp.getStatusCode(), HttpServletResponse.SC_OK); - assertEquals(resp.getHeader("X-pathInfo"), "/foo/test"); - - client.close(); + try { + Response resp = client.prepareGet(getTargetUrl2()).setProxyServer(new ProxyServer("127.0.0.1", port1 - 1).addNonProxyHost("127.0.0.1")).execute().get(3, TimeUnit.SECONDS); + + assertNotNull(resp); + assertEquals(resp.getStatusCode(), HttpServletResponse.SC_OK); + assertEquals(resp.getHeader("X-pathInfo"), "/foo/test"); + } finally { + client.close(); + } } } - diff --git a/src/test/java/com/ning/http/client/async/PutLargeFileTest.java b/src/test/java/com/ning/http/client/async/PutLargeFileTest.java index 27cc6b61f6..d84ec3234c 100644 --- a/src/test/java/com/ning/http/client/async/PutLargeFileTest.java +++ b/src/test/java/com/ning/http/client/async/PutLargeFileTest.java @@ -34,46 +34,48 @@ /** * @author Benjamin Hanzelmann */ -public abstract class PutLargeFileTest - extends AbstractBasicTest { +public abstract class PutLargeFileTest extends AbstractBasicTest { private File largeFile; - @Test(groups = {"standalone", "default_provider"}, enabled = true) - public void testPutLargeFile() - throws Exception { + @Test(groups = { "standalone", "default_provider" }, enabled = true) + public void testPutLargeFile() throws Exception { byte[] bytes = "RatherLargeFileRatherLargeFileRatherLargeFileRatherLargeFile".getBytes("UTF-16"); long repeats = (1024 * 1024 * 100 / bytes.length) + 1; largeFile = createTempFile(bytes, (int) repeats); int timeout = (int) (largeFile.length() / 1000); AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder().setConnectionTimeoutInMs(timeout).build(); AsyncHttpClient client = getAsyncHttpClient(config); - BoundRequestBuilder rb = client.preparePut(getTargetUrl()); + try { + BoundRequestBuilder rb = client.preparePut(getTargetUrl()); - rb.setBody(largeFile); + rb.setBody(largeFile); - Response response = rb.execute().get(); - Assert.assertEquals(200, response.getStatusCode()); - client.close(); + Response response = rb.execute().get(); + Assert.assertEquals(200, response.getStatusCode()); + } finally { + client.close(); + } } - @Test(groups = {"standalone", "default_provider"}) - public void testPutSmallFile() - throws Exception { + @Test(groups = { "standalone", "default_provider" }) + public void testPutSmallFile() throws Exception { byte[] bytes = "RatherLargeFileRatherLargeFileRatherLargeFileRatherLargeFile".getBytes("UTF-16"); long repeats = (1024 / bytes.length) + 1; - int timeout = (5000); largeFile = createTempFile(bytes, (int) repeats); AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder().build(); AsyncHttpClient client = getAsyncHttpClient(config); - BoundRequestBuilder rb = client.preparePut(getTargetUrl()); + try { + BoundRequestBuilder rb = client.preparePut(getTargetUrl()); - rb.setBody(largeFile); + rb.setBody(largeFile); - Response response = rb.execute().get(); - Assert.assertEquals(200, response.getStatusCode()); - client.close(); + Response response = rb.execute().get(); + Assert.assertEquals(200, response.getStatusCode()); + } finally { + client.close(); + } } @AfterMethod @@ -82,12 +84,10 @@ public void after() { } @Override - public AbstractHandler configureHandler() - throws Exception { + public AbstractHandler configureHandler() throws Exception { return new AbstractHandler() { - public void handle(String arg0, Request arg1, HttpServletRequest req, HttpServletResponse resp) - throws IOException, ServletException { + public void handle(String arg0, Request arg1, HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException { ServletInputStream in = req.getInputStream(); byte[] b = new byte[8092]; @@ -110,11 +110,9 @@ public void handle(String arg0, Request arg1, HttpServletRequest req, HttpServle }; } - private static final File TMP = new File(System.getProperty("java.io.tmpdir"), "ahc-tests-" - + UUID.randomUUID().toString().substring(0, 8)); + private static final File TMP = new File(System.getProperty("java.io.tmpdir"), "ahc-tests-" + UUID.randomUUID().toString().substring(0, 8)); - public static File createTempFile(byte[] pattern, int repeat) - throws IOException { + public static File createTempFile(byte[] pattern, int repeat) throws IOException { TMP.mkdirs(); TMP.deleteOnExit(); File tmpFile = File.createTempFile("tmpfile-", ".data", TMP); @@ -124,8 +122,7 @@ public static File createTempFile(byte[] pattern, int repeat) return tmpFile; } - public static void write(byte[] pattern, int repeat, File file) - throws IOException { + public static void write(byte[] pattern, int repeat, File file) throws IOException { file.deleteOnExit(); file.getParentFile().mkdirs(); FileOutputStream out = null; @@ -134,12 +131,10 @@ public static void write(byte[] pattern, int repeat, File file) for (int i = 0; i < repeat; i++) { out.write(pattern); } - } - finally { + } finally { if (out != null) { out.close(); } } } - } diff --git a/src/test/java/com/ning/http/client/async/QueryParametersTest.java b/src/test/java/com/ning/http/client/async/QueryParametersTest.java index da715345dd..27d796a07a 100644 --- a/src/test/java/com/ning/http/client/async/QueryParametersTest.java +++ b/src/test/java/com/ning/http/client/async/QueryParametersTest.java @@ -40,15 +40,12 @@ /** * Testing query parameters support. - * + * * @author Hubert Iwaniuk */ public abstract class QueryParametersTest extends AbstractBasicTest { private class QueryStringHandler extends AbstractHandler { - public void handle(String s, - Request r, - HttpServletRequest request, - HttpServletResponse response) throws IOException, ServletException { + public void handle(String s, Request r, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { if ("GET".equalsIgnoreCase(request.getMethod())) { String qs = request.getQueryString(); if (isNonEmpty(qs)) { @@ -72,61 +69,63 @@ public AbstractHandler configureHandler() throws Exception { return new QueryStringHandler(); } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void testQueryParameters() throws IOException, ExecutionException, TimeoutException, InterruptedException { AsyncHttpClient client = getAsyncHttpClient(null); - Future f = client - .prepareGet("http://127.0.0.1/" + port1) - .addQueryParameter("a", "1") - .addQueryParameter("b", "2") - .execute(); - Response resp = f.get(3, TimeUnit.SECONDS); - assertNotNull(resp); - assertEquals(resp.getStatusCode(), HttpServletResponse.SC_OK); - assertEquals(resp.getHeader("a"), "1"); - assertEquals(resp.getHeader("b"), "2"); - client.close(); + try { + Future f = client.prepareGet("http://127.0.0.1/" + port1).addQueryParameter("a", "1").addQueryParameter("b", "2").execute(); + Response resp = f.get(3, TimeUnit.SECONDS); + assertNotNull(resp); + assertEquals(resp.getStatusCode(), HttpServletResponse.SC_OK); + assertEquals(resp.getHeader("a"), "1"); + assertEquals(resp.getHeader("b"), "2"); + } finally { + client.close(); + } } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void testUrlRequestParametersEncoding() throws IOException, ExecutionException, InterruptedException { String URL = getTargetUrl() + "?q="; String REQUEST_PARAM = "github github \ngithub"; AsyncHttpClient client = getAsyncHttpClient(null); - String requestUrl2 = URL + URLEncoder.encode(REQUEST_PARAM, "UTF-8"); - LoggerFactory.getLogger(QueryParametersTest.class).info("Executing request [{}] ...", requestUrl2); - Response response = client.prepareGet(requestUrl2).execute().get(); - String s = URLDecoder.decode(response.getHeader("q"), "UTF-8"); - assertEquals(s, REQUEST_PARAM); - client.close(); + try { + String requestUrl2 = URL + URLEncoder.encode(REQUEST_PARAM, "UTF-8"); + LoggerFactory.getLogger(QueryParametersTest.class).info("Executing request [{}] ...", requestUrl2); + Response response = client.prepareGet(requestUrl2).execute().get(); + String s = URLDecoder.decode(response.getHeader("q"), "UTF-8"); + assertEquals(s, REQUEST_PARAM); + } finally { + client.close(); + } } - - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void urlWithColonTest_Netty() throws Throwable { AsyncHttpClient c = getAsyncHttpClient(null); - String query = "test:colon:"; - Response response = c.prepareGet(String.format("http://127.0.0.1:%d/foo/test/colon?q=%s", port1, query)) - .setHeader("Content-Type", "text/html") - .execute().get(TIMEOUT, TimeUnit.SECONDS); + try { + String query = "test:colon:"; + Response response = c.prepareGet(String.format("http://127.0.0.1:%d/foo/test/colon?q=%s", port1, query)).setHeader("Content-Type", "text/html").execute().get(TIMEOUT, TimeUnit.SECONDS); - assertEquals(response.getHeader("q"), URLEncoder.encode(query, "UTF-8")); - c.close(); + assertEquals(response.getHeader("q"), URLEncoder.encode(query, "UTF-8")); + } finally { + c.close(); + } } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void urlWithColonTest_JDK() throws Throwable { AsyncHttpClient c = getAsyncHttpClient(null); + try { + String query = "test:colon:"; + Response response = c.prepareGet(String.format("http://127.0.0.1:%d/foo/test/colon?q=%s", port1, query)).setHeader("Content-Type", "text/html").execute().get(TIMEOUT, TimeUnit.SECONDS); - String query = "test:colon:"; - Response response = c.prepareGet(String.format("http://127.0.0.1:%d/foo/test/colon?q=%s", port1, query)) - .setHeader("Content-Type", "text/html") - .execute().get(TIMEOUT, TimeUnit.SECONDS); - - assertEquals(response.getHeader("q"), URLEncoder.encode(query, "UTF-8")); - c.close(); + assertEquals(response.getHeader("q"), URLEncoder.encode(query, "UTF-8")); + } finally { + c.close(); + } } } diff --git a/src/test/java/com/ning/http/client/async/RC10KTest.java b/src/test/java/com/ning/http/client/async/RC10KTest.java index d37c9d2c68..53ae5d4000 100644 --- a/src/test/java/com/ning/http/client/async/RC10KTest.java +++ b/src/test/java/com/ning/http/client/async/RC10KTest.java @@ -46,7 +46,7 @@ /** * Reverse C10K Problem test. - * + * * @author Hubert Iwaniuk */ public abstract class RC10KTest extends AbstractBasicTest { @@ -102,20 +102,22 @@ public void handle(String s, Request r, HttpServletRequest req, HttpServletRespo @Test(timeOut = 10 * 60 * 1000, groups = "scalability") public void rc10kProblem() throws IOException, ExecutionException, TimeoutException, InterruptedException { - AsyncHttpClient ahc = getAsyncHttpClient( - new AsyncHttpClientConfig.Builder().setMaximumConnectionsPerHost(C10K).setAllowPoolingConnection(true).build()); - List> resps = new ArrayList>(C10K); - int i = 0; - while (i < C10K) { - resps.add(ahc.prepareGet(String.format("http://127.0.0.1:%d/%d", ports[i % SRV_COUNT], i)).execute(new MyAsyncHandler(i++))); - } - i = 0; - for (Future fResp : resps) { - Integer resp = fResp.get(); - assertNotNull(resp); - assertEquals(resp.intValue(), i++); + AsyncHttpClient ahc = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setMaximumConnectionsPerHost(C10K).setAllowPoolingConnection(true).build()); + try { + List> resps = new ArrayList>(C10K); + int i = 0; + while (i < C10K) { + resps.add(ahc.prepareGet(String.format("http://127.0.0.1:%d/%d", ports[i % SRV_COUNT], i)).execute(new MyAsyncHandler(i++))); + } + i = 0; + for (Future fResp : resps) { + Integer resp = fResp.get(); + assertNotNull(resp); + assertEquals(resp.intValue(), i++); + } + } finally { + ahc.close(); } - ahc.close(); } private class MyAsyncHandler implements AsyncHandler { diff --git a/src/test/java/com/ning/http/client/async/RedirectConnectionUsageTest.java b/src/test/java/com/ning/http/client/async/RedirectConnectionUsageTest.java index 6cc687e49f..e8b6387164 100644 --- a/src/test/java/com/ning/http/client/async/RedirectConnectionUsageTest.java +++ b/src/test/java/com/ning/http/client/async/RedirectConnectionUsageTest.java @@ -21,7 +21,6 @@ import com.ning.http.client.ListenableFuture; import com.ning.http.client.RequestBuilder; import com.ning.http.client.Response; -import com.ning.http.client.providers.netty.NettyAsyncHttpProviderConfig; import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.nio.SelectChannelConnector; @@ -144,8 +143,6 @@ public void testGetRedirectFinalUrl() { // can hang here if (c != null) c.close(); } - - } protected abstract AsyncHttpProviderConfig getProviderConfig(); @@ -182,6 +179,4 @@ public void service(HttpServletRequest req, HttpServletResponse res) throws Serv os.close(); } } - - } diff --git a/src/test/java/com/ning/http/client/async/Relative302Test.java b/src/test/java/com/ning/http/client/async/Relative302Test.java index e8a72640b4..69b21cbc64 100644 --- a/src/test/java/com/ning/http/client/async/Relative302Test.java +++ b/src/test/java/com/ning/http/client/async/Relative302Test.java @@ -45,11 +45,7 @@ public abstract class Relative302Test extends AbstractBasicTest { private class Relative302Handler extends AbstractHandler { - - public void handle(String s, - Request r, - HttpServletRequest httpRequest, - HttpServletResponse httpResponse) throws IOException, ServletException { + public void handle(String s, Request r, HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws IOException, ServletException { String param; httpResponse.setContentType("text/html; charset=utf-8"); @@ -89,26 +85,25 @@ public void setUpGlobal() throws Exception { log.info("Local HTTP server started successfully"); } - @Test(groups = {"online", "default_provider"}) + @Test(groups = { "online", "default_provider" }) public void redirected302Test() throws Throwable { isSet.getAndSet(false); AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setFollowRedirects(true).build(); AsyncHttpClient c = getAsyncHttpClient(cg); + try { + // once + Response response = c.prepareGet(getTargetUrl()).setHeader("X-redirect", "http://www.google.com/").execute().get(); - // once - Response response = c.prepareGet(getTargetUrl()) - .setHeader("X-redirect", "http://www.google.com/") - .execute().get(); + assertNotNull(response); + assertEquals(response.getStatusCode(), 200); - assertNotNull(response); - assertEquals(response.getStatusCode(), 200); - - String anyGoogleSubdomain = "http://www.google.[a-z]{1,}:80"; - String baseUrl = getBaseUrl( response.getUri() ); - - assertTrue(baseUrl.matches( anyGoogleSubdomain ), "response does not show redirection to " + anyGoogleSubdomain); + String anyGoogleSubdomain = "http://www.google.[a-z]{1,}:80"; + String baseUrl = getBaseUrl(response.getUri()); - c.close(); + assertTrue(baseUrl.matches(anyGoogleSubdomain), "response does not show redirection to " + anyGoogleSubdomain); + } finally { + c.close(); + } } private String getBaseUrl(URI uri) { @@ -128,7 +123,7 @@ private static int getPort(URI uri) { return port; } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void redirected302InvalidTest() throws Throwable { isSet.getAndSet(false); AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setFollowRedirects(true).build(); @@ -136,59 +131,56 @@ public void redirected302InvalidTest() throws Throwable { // If the test hit a proxy, no ConnectException will be thrown and instead of 404 will be returned. try { - Response response = c.prepareGet(getTargetUrl()) - .setHeader("X-redirect", String.format("http://127.0.0.1:%d/", port2)) - .execute().get(); + Response response = c.prepareGet(getTargetUrl()).setHeader("X-redirect", String.format("http://127.0.0.1:%d/", port2)).execute().get(); assertNotNull(response); assertEquals(response.getStatusCode(), 404); } catch (ExecutionException ex) { assertEquals(ex.getCause().getClass(), ConnectException.class); + } finally { + c.close(); } - c.close(); } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void absolutePathRedirectTest() throws Throwable { isSet.getAndSet(false); AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setFollowRedirects(true).build(); AsyncHttpClient c = getAsyncHttpClient(cg); + try { + String redirectTarget = "/bar/test"; + String destinationUrl = new URI(getTargetUrl()).resolve(redirectTarget).toString(); + + Response response = c.prepareGet(getTargetUrl()).setHeader("X-redirect", redirectTarget).execute().get(); + assertNotNull(response); + assertEquals(response.getStatusCode(), 200); + assertEquals(response.getUri().toString(), destinationUrl); - String redirectTarget = "/bar/test"; - String destinationUrl = new URI(getTargetUrl()).resolve(redirectTarget).toString(); - - Response response = c.prepareGet(getTargetUrl()) - .setHeader("X-redirect", redirectTarget) - .execute().get(); - assertNotNull(response); - assertEquals(response.getStatusCode(), 200); - assertEquals(response.getUri().toString(), destinationUrl); - - log.debug("{} was redirected to {}", redirectTarget, destinationUrl); - - c.close(); + log.debug("{} was redirected to {}", redirectTarget, destinationUrl); + } finally { + c.close(); + } } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void relativePathRedirectTest() throws Throwable { isSet.getAndSet(false); AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setFollowRedirects(true).build(); AsyncHttpClient c = getAsyncHttpClient(cg); + try { + String redirectTarget = "bar/test1"; + String destinationUrl = new URI(getTargetUrl()).resolve(redirectTarget).toString(); - String redirectTarget = "bar/test1"; - String destinationUrl = new URI(getTargetUrl()).resolve(redirectTarget).toString(); - - Response response = c.prepareGet(getTargetUrl()) - .setHeader("X-redirect", redirectTarget) - .execute().get(); - assertNotNull(response); - assertEquals(response.getStatusCode(), 200); - assertEquals(response.getUri().toString(), destinationUrl); - - log.debug("{} was redirected to {}", redirectTarget, destinationUrl); - - c.close(); + Response response = c.prepareGet(getTargetUrl()).setHeader("X-redirect", redirectTarget).execute().get(); + assertNotNull(response); + assertEquals(response.getStatusCode(), 200); + assertEquals(response.getUri().toString(), destinationUrl); + + log.debug("{} was redirected to {}", redirectTarget, destinationUrl); + } finally { + c.close(); + } } } diff --git a/src/test/java/com/ning/http/client/async/RemoteSiteTest.java b/src/test/java/com/ning/http/client/async/RemoteSiteTest.java index 6509b57e59..3f8d12518f 100644 --- a/src/test/java/com/ning/http/client/async/RemoteSiteTest.java +++ b/src/test/java/com/ning/http/client/async/RemoteSiteTest.java @@ -41,109 +41,112 @@ * Unit tests for remote site. *

* see http://github.com/MSch/ning-async-http-client-bug/tree/master - * + * * @author Martin Schurrer */ -public abstract class RemoteSiteTest extends AbstractBasicTest{ +public abstract class RemoteSiteTest extends AbstractBasicTest { public static final String URL = "http://google.com/?q="; - public static final String REQUEST_PARAM = "github github \n" + - "github"; - - @Test(groups = {"online", "default_provider"}) + public static final String REQUEST_PARAM = "github github \n" + "github"; + + @Test(groups = { "online", "default_provider" }) public void testGoogleCom() throws Throwable { AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeoutInMs(10000).build()); - // Works - Response response = c.prepareGet("http://www.google.com/").execute().get(10,TimeUnit.SECONDS); - assertNotNull(response); - c.close(); + try { + Response response = c.prepareGet("http://www.google.com/").execute().get(10, TimeUnit.SECONDS); + assertNotNull(response); + } finally { + c.close(); + } } - @Test(groups = {"online", "default_provider"}) + @Test(groups = { "online", "default_provider" }) public void testMailGoogleCom() throws Throwable { AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeoutInMs(10000).build()); - - Response response = c.prepareGet("http://mail.google.com/").execute().get(10,TimeUnit.SECONDS); - assertNotNull(response); - assertEquals(response.getStatusCode(), 200); - c.close(); + try { + Response response = c.prepareGet("http://mail.google.com/").execute().get(10, TimeUnit.SECONDS); + assertNotNull(response); + assertEquals(response.getStatusCode(), 200); + } finally { + c.close(); + } } - @Test(groups = {"online", "default_provider"}) + @Test(groups = { "online", "default_provider" }) public void testMicrosoftCom() throws Throwable { AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeoutInMs(10000).build()); - - // Works - Response response = c.prepareGet("http://microsoft.com/").execute().get(10,TimeUnit.SECONDS); - assertNotNull(response); - assertEquals(response.getStatusCode(), 301); - c.close(); + try { + Response response = c.prepareGet("http://microsoft.com/").execute().get(10, TimeUnit.SECONDS); + assertNotNull(response); + assertEquals(response.getStatusCode(), 301); + } finally { + c.close(); + } } - @Test(groups = {"online", "default_provider"}) + @Test(groups = { "online", "default_provider" }) public void testWwwMicrosoftCom() throws Throwable { AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeoutInMs(10000).build()); - - Response response = c.prepareGet("http://www.microsoft.com/").execute().get(10,TimeUnit.SECONDS); - assertNotNull(response); - assertEquals(response.getStatusCode(), 302); - c.close(); + try { + Response response = c.prepareGet("http://www.microsoft.com/").execute().get(10, TimeUnit.SECONDS); + assertNotNull(response); + assertEquals(response.getStatusCode(), 302); + } finally { + c.close(); + } } - @Test(groups = {"online", "default_provider"}) + @Test(groups = { "online", "default_provider" }) public void testUpdateMicrosoftCom() throws Throwable { AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeoutInMs(10000).build()); - - Response response = c.prepareGet("http://update.microsoft.com/").execute().get(10,TimeUnit.SECONDS); - assertNotNull(response); - assertEquals(response.getStatusCode(), 302); - c.close(); + try { + Response response = c.prepareGet("http://update.microsoft.com/").execute().get(10, TimeUnit.SECONDS); + assertNotNull(response); + assertEquals(response.getStatusCode(), 302); + } finally { + c.close(); + } } - @Test(groups = {"online", "default_provider"}) + @Test(groups = { "online", "default_provider" }) public void testGoogleComWithTimeout() throws Throwable { AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeoutInMs(10000).build()); - - // Works - Response response = c.prepareGet("http://google.com/").execute().get(10,TimeUnit.SECONDS); - assertNotNull(response); - assertEquals(response.getStatusCode(), 301); - c.close(); + try { + Response response = c.prepareGet("http://google.com/").execute().get(10, TimeUnit.SECONDS); + assertNotNull(response); + assertEquals(response.getStatusCode(), 301); + } finally { + c.close(); + } } - @Test(groups = {"online", "default_provider"}) + @Test(groups = { "online", "default_provider" }) public void asyncStatusHEADContentLenghtTest() throws Throwable { - AsyncHttpClient p = getAsyncHttpClient( - new AsyncHttpClientConfig.Builder().setFollowRedirects(true).build()); - - final CountDownLatch l = new CountDownLatch(1); - Request request = new RequestBuilder("HEAD") - .setUrl("http://www.google.com/") - .build(); - - p.executeRequest(request, new AsyncCompletionHandlerAdapter() { - @Override - public Response onCompleted(Response response) throws Exception { - Assert.assertEquals(response.getStatusCode(), 200); - l.countDown(); - return response; + AsyncHttpClient p = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setFollowRedirects(true).build()); + try { + final CountDownLatch l = new CountDownLatch(1); + Request request = new RequestBuilder("HEAD").setUrl("http://www.google.com/").build(); + + p.executeRequest(request, new AsyncCompletionHandlerAdapter() { + @Override + public Response onCompleted(Response response) throws Exception { + Assert.assertEquals(response.getStatusCode(), 200); + l.countDown(); + return response; + } + }).get(); + + if (!l.await(5, TimeUnit.SECONDS)) { + Assert.fail("Timeout out"); } - }).get(); - - if (!l.await(5, TimeUnit.SECONDS)) { - Assert.fail("Timeout out"); + } finally { + p.close(); } - p.close(); } - @Test(groups = {"online", "default_provider"}, enabled = false) + @Test(groups = { "online", "default_provider" }, enabled = false) public void invalidStreamTest2() throws Throwable { - AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder() - .setRequestTimeoutInMs(10000) - .setFollowRedirects(true) - .setAllowPoolingConnection(false) - .setMaximumNumberOfRedirects(6) - .build(); + AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder().setRequestTimeoutInMs(10000).setFollowRedirects(true).setAllowPoolingConnection(false).setMaximumNumberOfRedirects(6).build(); AsyncHttpClient c = getAsyncHttpClient(config); try { @@ -155,134 +158,143 @@ public void invalidStreamTest2() throws Throwable { t.printStackTrace(); assertNotNull(t.getCause()); assertEquals(t.getCause().getMessage(), "invalid version format: ICY"); + } finally { + c.close(); } - c.close(); } - @Test(groups = {"online", "default_provider"}) + @Test(groups = { "online", "default_provider" }) public void asyncFullBodyProperlyRead() throws Throwable { final AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().build()); - Response r = client.prepareGet("http://www.cyberpresse.ca/").execute().get(); + try { + Response r = client.prepareGet("http://www.cyberpresse.ca/").execute().get(); - InputStream stream = r.getResponseBodyAsStream(); - int available = stream.available(); - int[] lengthWrapper = new int[1]; - byte[] bytes = AsyncHttpProviderUtils.readFully(stream, lengthWrapper); - int byteToRead = lengthWrapper[0]; + InputStream stream = r.getResponseBodyAsStream(); + int available = stream.available(); + int[] lengthWrapper = new int[1]; + AsyncHttpProviderUtils.readFully(stream, lengthWrapper); + int byteToRead = lengthWrapper[0]; - Assert.assertEquals(available, byteToRead); - client.close(); + Assert.assertEquals(available, byteToRead); + } finally { + client.close(); + } } - @Test(groups = {"online", "default_provider"}) + @Test(groups = { "online", "default_provider" }) public void testUrlRequestParametersEncoding() throws Throwable { AsyncHttpClient client = getAsyncHttpClient(null); - String requestUrl2 = URL + URLEncoder.encode(REQUEST_PARAM, "UTF-8"); - log.info(String.format("Executing request [%s] ...", requestUrl2)); - Response response = client.prepareGet(requestUrl2).execute().get(); - Assert.assertEquals(response.getStatusCode(), 301); - client.close(); + try { + String requestUrl2 = URL + URLEncoder.encode(REQUEST_PARAM, "UTF-8"); + log.info(String.format("Executing request [%s] ...", requestUrl2)); + Response response = client.prepareGet(requestUrl2).execute().get(); + Assert.assertEquals(response.getStatusCode(), 301); + } finally { + client.close(); + } } /** - * See https://issues.sonatype.org/browse/AHC-61 + * See https://issues.sonatype.org/browse/AHC-61 + * * @throws Throwable */ - @Test(groups = {"online", "default_provider"}) + @Test(groups = { "online", "default_provider" }) public void testAHC60() throws Throwable { AsyncHttpClient client = getAsyncHttpClient(null); - Response response = client.prepareGet("http://www.meetup.com/stackoverflow/Mountain-View-CA/").execute().get(); - Assert.assertEquals(response.getStatusCode(), 200); - client.close(); + try { + Response response = client.prepareGet("http://www.meetup.com/stackoverflow/Mountain-View-CA/").execute().get(); + Assert.assertEquals(response.getStatusCode(), 200); + } finally { + client.close(); + } } - @Test(groups = {"online", "default_provider"}) + @Test(groups = { "online", "default_provider" }) public void stripQueryStringTest() throws Throwable { AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setFollowRedirects(true).build(); AsyncHttpClient c = getAsyncHttpClient(cg); - Response response = c.prepareGet("http://www.freakonomics.com/?p=55846") - .execute().get(); + Response response = c.prepareGet("http://www.freakonomics.com/?p=55846").execute().get(); assertNotNull(response); assertEquals(response.getStatusCode(), 200); - c.close(); } - @Test(groups = {"online", "default_provider"}) + @Test(groups = { "online", "default_provider" }) public void stripQueryStringNegativeTest() throws Throwable { - AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder() - .setRemoveQueryParamsOnRedirect(false).setFollowRedirects(true).build(); + AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setRemoveQueryParamsOnRedirect(false).setFollowRedirects(true).build(); AsyncHttpClient c = getAsyncHttpClient(cg); + try { + Response response = c.prepareGet("http://www.freakonomics.com/?p=55846").execute().get(); - Response response = c.prepareGet("http://www.freakonomics.com/?p=55846") - .execute().get(); - - assertNotNull(response); - assertEquals(response.getStatusCode(), 301); - - - c.close(); + assertNotNull(response); + assertEquals(response.getStatusCode(), 301); + } finally { + c.close(); + } } - @Test(groups = {"online", "default_provider"}) + @Test(groups = { "online", "default_provider" }) public void evilCoookieTest() throws Throwable { AsyncHttpClient c = getAsyncHttpClient(null); - - RequestBuilder builder2 = new RequestBuilder("GET"); - builder2.setFollowRedirects(true); - builder2.setUrl("http://www.google.com/"); - builder2.addHeader("Content-Type", "text/plain"); - builder2.addCookie(new com.ning.http.client.Cookie(".google.com", "evilcookie", "test", "/", 10, false)); - com.ning.http.client.Request request2 = builder2.build(); - Response response = c.executeRequest(request2).get(); - - assertNotNull(response); - assertEquals(response.getStatusCode(), 200); - c.close(); + try { + RequestBuilder builder2 = new RequestBuilder("GET"); + builder2.setFollowRedirects(true); + builder2.setUrl("http://www.google.com/"); + builder2.addHeader("Content-Type", "text/plain"); + builder2.addCookie(new com.ning.http.client.Cookie(".google.com", "evilcookie", "test", "/", 10, false)); + com.ning.http.client.Request request2 = builder2.build(); + Response response = c.executeRequest(request2).get(); + + assertNotNull(response); + assertEquals(response.getStatusCode(), 200); + } finally { + c.close(); + } } - @Test(groups = {"online", "default_provider"}, enabled = false) + @Test(groups = { "online", "default_provider" }, enabled = false) public void testAHC62Com() throws Throwable { AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setFollowRedirects(true).build()); - // Works - Response response = c.prepareGet("http://api.crunchbase.com/v/1/financial-organization/kinsey-hills-group.js").execute(new AsyncHandler() { - - private Response.ResponseBuilder builder = new Response.ResponseBuilder(); - - public void onThrowable(Throwable t) { - t.printStackTrace(); - } - - public STATE onBodyPartReceived(HttpResponseBodyPart bodyPart) throws Exception { - System.out.println(bodyPart.getBodyPartBytes().length); - builder.accumulate(bodyPart); - - return STATE.CONTINUE; - } - - public STATE onStatusReceived(HttpResponseStatus responseStatus) throws Exception { - builder.accumulate(responseStatus); - return STATE.CONTINUE; - } - - public STATE onHeadersReceived(HttpResponseHeaders headers) throws Exception { - builder.accumulate(headers); - return STATE.CONTINUE; - } - - public Response onCompleted() throws Exception { - return builder.build(); - } - }).get(10, TimeUnit.SECONDS); - assertNotNull(response); - assertTrue(response.getResponseBody().length() >= 3870); - c.close(); + try { + Response response = c.prepareGet("http://api.crunchbase.com/v/1/financial-organization/kinsey-hills-group.js").execute(new AsyncHandler() { + + private Response.ResponseBuilder builder = new Response.ResponseBuilder(); + + public void onThrowable(Throwable t) { + t.printStackTrace(); + } + + public STATE onBodyPartReceived(HttpResponseBodyPart bodyPart) throws Exception { + System.out.println(bodyPart.getBodyPartBytes().length); + builder.accumulate(bodyPart); + + return STATE.CONTINUE; + } + + public STATE onStatusReceived(HttpResponseStatus responseStatus) throws Exception { + builder.accumulate(responseStatus); + return STATE.CONTINUE; + } + + public STATE onHeadersReceived(HttpResponseHeaders headers) throws Exception { + builder.accumulate(headers); + return STATE.CONTINUE; + } + + public Response onCompleted() throws Exception { + return builder.build(); + } + }).get(10, TimeUnit.SECONDS); + assertNotNull(response); + assertTrue(response.getResponseBody().length() >= 3870); + } finally { + c.close(); + } } - } - diff --git a/src/test/java/com/ning/http/client/async/RetryNonBlockingIssue.java b/src/test/java/com/ning/http/client/async/RetryNonBlockingIssue.java index 247fe8c2a3..86eabd4ba4 100644 --- a/src/test/java/com/ning/http/client/async/RetryNonBlockingIssue.java +++ b/src/test/java/com/ning/http/client/async/RetryNonBlockingIssue.java @@ -259,6 +259,7 @@ public void testRetryBlocking() throws IOException, InterruptedException, } } + @SuppressWarnings("serial") public class MockExceptionServlet extends HttpServlet { private Map requests = new @@ -325,7 +326,6 @@ public void service(HttpServletRequest req, HttpServletResponse res) if (error != null && error.trim().length() > 0) res.sendError(500, "servlet process was 500"); } - } } diff --git a/src/test/java/com/ning/http/client/async/RetryRequestTest.java b/src/test/java/com/ning/http/client/async/RetryRequestTest.java index 3cd92523ba..6b6ccd86bd 100644 --- a/src/test/java/com/ning/http/client/async/RetryRequestTest.java +++ b/src/test/java/com/ning/http/client/async/RetryRequestTest.java @@ -29,9 +29,7 @@ public abstract class RetryRequestTest extends AbstractBasicTest { public static class SlowAndBigHandler extends AbstractHandler { - public void handle(String pathInContext, Request request, - HttpServletRequest httpRequest, HttpServletResponse httpResponse) - throws IOException, ServletException { + public void handle(String pathInContext, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws IOException, ServletException { int load = 100; httpResponse.setStatus(200); @@ -40,7 +38,6 @@ public void handle(String pathInContext, Request request, httpResponse.flushBuffer(); - OutputStream os = httpResponse.getOutputStream(); for (int i = 0; i < load; i++) { os.write(i % 255); @@ -51,7 +48,6 @@ public void handle(String pathInContext, Request request, // nuku } - if (i > load / 10) { httpResponse.sendError(500); } @@ -71,8 +67,7 @@ public AbstractHandler configureHandler() throws Exception { return new SlowAndBigHandler(); } - - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void testMaxRetry() throws Throwable { AsyncHttpClient ahc = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setMaxRequestRetry(0).build()); try { @@ -84,8 +79,8 @@ public void testMaxRetry() throws Throwable { if (!t.getCause().getMessage().startsWith("Remotely Closed")) { fail(); } + } finally { + ahc.close(); } - - ahc.close(); } } diff --git a/src/test/java/com/ning/http/client/async/SimpleAsyncClientErrorBehaviourTest.java b/src/test/java/com/ning/http/client/async/SimpleAsyncClientErrorBehaviourTest.java index 4206f6b96d..064b472e09 100644 --- a/src/test/java/com/ning/http/client/async/SimpleAsyncClientErrorBehaviourTest.java +++ b/src/test/java/com/ning/http/client/async/SimpleAsyncClientErrorBehaviourTest.java @@ -34,60 +34,57 @@ /** * @author Benjamin Hanzelmann - * + * */ public class SimpleAsyncClientErrorBehaviourTest extends AbstractBasicTest { - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void testAccumulateErrorBody() throws Throwable { - SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setUrl(getTargetUrl() + "/nonexistent").setErrorDocumentBehaviour( ErrorDocumentBehaviour.ACCUMULATE ).build(); - - ByteArrayOutputStream o = new ByteArrayOutputStream(10); - Future future = client.get(new OutputStreamBodyConsumer(o)); - - System.out.println("waiting for response"); - Response response = future.get(); - assertEquals(response.getStatusCode(), 404); - assertEquals(o.toString(), ""); - assertTrue(response.getResponseBody().startsWith("")); - - client.close(); + SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setUrl(getTargetUrl() + "/nonexistent").setErrorDocumentBehaviour(ErrorDocumentBehaviour.ACCUMULATE).build(); + try { + ByteArrayOutputStream o = new ByteArrayOutputStream(10); + Future future = client.get(new OutputStreamBodyConsumer(o)); + + System.out.println("waiting for response"); + Response response = future.get(); + assertEquals(response.getStatusCode(), 404); + assertEquals(o.toString(), ""); + assertTrue(response.getResponseBody().startsWith("")); + } finally { + client.close(); + } } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void testOmitErrorBody() throws Throwable { - SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setUrl(getTargetUrl() + "/nonexistent").setErrorDocumentBehaviour( ErrorDocumentBehaviour.OMIT ).build(); - - ByteArrayOutputStream o = new ByteArrayOutputStream(10); - Future future = client.get(new OutputStreamBodyConsumer(o)); - - System.out.println("waiting for response"); - Response response = future.get(); - assertEquals(response.getStatusCode(), 404); - assertEquals(o.toString(), ""); - assertEquals(response.getResponseBody(), ""); - client.close(); + SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setUrl(getTargetUrl() + "/nonexistent").setErrorDocumentBehaviour(ErrorDocumentBehaviour.OMIT).build(); + try { + ByteArrayOutputStream o = new ByteArrayOutputStream(10); + Future future = client.get(new OutputStreamBodyConsumer(o)); + + System.out.println("waiting for response"); + Response response = future.get(); + assertEquals(response.getStatusCode(), 404); + assertEquals(o.toString(), ""); + assertEquals(response.getResponseBody(), ""); + } finally { + client.close(); + } } @Override - public AsyncHttpClient getAsyncHttpClient( AsyncHttpClientConfig config ) - { + public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { // disabled return null; } @Override - public AbstractHandler configureHandler() - throws Exception - { + public AbstractHandler configureHandler() throws Exception { return new AbstractHandler() { - - public void handle( String target, org.eclipse.jetty.server.Request baseRequest, - HttpServletRequest request, HttpServletResponse response ) - throws IOException, ServletException - { - response.sendError( 404 ); - baseRequest.setHandled( true ); + + public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { + response.sendError(404); + baseRequest.setHandled(true); } }; } diff --git a/src/test/java/com/ning/http/client/async/SimpleAsyncHttpClientTest.java b/src/test/java/com/ning/http/client/async/SimpleAsyncHttpClientTest.java index f981fc61b5..8039591c3b 100644 --- a/src/test/java/com/ning/http/client/async/SimpleAsyncHttpClientTest.java +++ b/src/test/java/com/ning/http/client/async/SimpleAsyncHttpClientTest.java @@ -12,7 +12,6 @@ */ package com.ning.http.client.async; -import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.ByteArrayPart; import com.ning.http.client.Response; import com.ning.http.client.SimpleAsyncHttpClient; @@ -43,67 +42,68 @@ public abstract class SimpleAsyncHttpClientTest extends AbstractBasicTest { @Test(groups = { "standalone", "default_provider" }) public void inpuStreamBodyConsumerTest() throws Throwable { - SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setIdleConnectionInPoolTimeoutInMs(100).setMaximumConnectionsTotal(50) - .setRequestTimeoutInMs(5 * 60 * 1000).setUrl(getTargetUrl()).setHeader("Content-Type", "text/html").build(); - - Future future = client.post(new InputStreamBodyGenerator(new ByteArrayInputStream(MY_MESSAGE.getBytes()))); - - System.out.println("waiting for response"); - Response response = future.get(); - assertEquals(response.getStatusCode(), 200); - assertEquals(response.getResponseBody(), MY_MESSAGE); - - client.close(); + SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setIdleConnectionInPoolTimeoutInMs(100).setMaximumConnectionsTotal(50).setRequestTimeoutInMs(5 * 60 * 1000).setUrl(getTargetUrl()).setHeader("Content-Type", "text/html").build(); + try { + Future future = client.post(new InputStreamBodyGenerator(new ByteArrayInputStream(MY_MESSAGE.getBytes()))); + + System.out.println("waiting for response"); + Response response = future.get(); + assertEquals(response.getStatusCode(), 200); + assertEquals(response.getResponseBody(), MY_MESSAGE); + } finally { + client.close(); + } } @Test(groups = { "standalone", "default_provider" }) public void StringBufferBodyConsumerTest() throws Throwable { - SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setIdleConnectionInPoolTimeoutInMs(100).setMaximumConnectionsTotal(50) - .setRequestTimeoutInMs(5 * 60 * 1000).setUrl(getTargetUrl()).setHeader("Content-Type", "text/html").build(); - - StringBuilder s = new StringBuilder(); - Future future = client.post(new InputStreamBodyGenerator(new ByteArrayInputStream(MY_MESSAGE.getBytes())), new AppendableBodyConsumer(s)); - - System.out.println("waiting for response"); - Response response = future.get(); - assertEquals(response.getStatusCode(), 200); - assertEquals(s.toString(), MY_MESSAGE); - - client.close(); + SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setIdleConnectionInPoolTimeoutInMs(100).setMaximumConnectionsTotal(50).setRequestTimeoutInMs(5 * 60 * 1000).setUrl(getTargetUrl()).setHeader("Content-Type", "text/html").build(); + try { + StringBuilder s = new StringBuilder(); + Future future = client.post(new InputStreamBodyGenerator(new ByteArrayInputStream(MY_MESSAGE.getBytes())), new AppendableBodyConsumer(s)); + + System.out.println("waiting for response"); + Response response = future.get(); + assertEquals(response.getStatusCode(), 200); + assertEquals(s.toString(), MY_MESSAGE); + } finally { + client.close(); + } } @Test(groups = { "standalone", "default_provider" }) public void ByteArrayOutputStreamBodyConsumerTest() throws Throwable { - SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setIdleConnectionInPoolTimeoutInMs(100).setMaximumConnectionsTotal(50) - .setRequestTimeoutInMs(5 * 60 * 1000).setUrl(getTargetUrl()).setHeader("Content-Type", "text/html").build(); - - ByteArrayOutputStream o = new ByteArrayOutputStream(10); - Future future = client.post(new InputStreamBodyGenerator(new ByteArrayInputStream(MY_MESSAGE.getBytes())), new OutputStreamBodyConsumer(o)); - - System.out.println("waiting for response"); - Response response = future.get(); - assertEquals(response.getStatusCode(), 200); - assertEquals(o.toString(), MY_MESSAGE); - - client.close(); + SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setIdleConnectionInPoolTimeoutInMs(100).setMaximumConnectionsTotal(50).setRequestTimeoutInMs(5 * 60 * 1000).setUrl(getTargetUrl()).setHeader("Content-Type", "text/html").build(); + try { + ByteArrayOutputStream o = new ByteArrayOutputStream(10); + Future future = client.post(new InputStreamBodyGenerator(new ByteArrayInputStream(MY_MESSAGE.getBytes())), new OutputStreamBodyConsumer(o)); + + System.out.println("waiting for response"); + Response response = future.get(); + assertEquals(response.getStatusCode(), 200); + assertEquals(o.toString(), MY_MESSAGE); + } finally { + client.close(); + } } @Test(groups = { "standalone", "default_provider" }) public void RequestByteArrayOutputStreamBodyConsumerTest() throws Throwable { SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setUrl(getTargetUrl()).build(); - - ByteArrayOutputStream o = new ByteArrayOutputStream(10); - Future future = client.post(new InputStreamBodyGenerator(new ByteArrayInputStream(MY_MESSAGE.getBytes())), new OutputStreamBodyConsumer(o)); - - System.out.println("waiting for response"); - Response response = future.get(); - assertEquals(response.getStatusCode(), 200); - assertEquals(o.toString(), MY_MESSAGE); - - client.close(); + try { + ByteArrayOutputStream o = new ByteArrayOutputStream(10); + Future future = client.post(new InputStreamBodyGenerator(new ByteArrayInputStream(MY_MESSAGE.getBytes())), new OutputStreamBodyConsumer(o)); + + System.out.println("waiting for response"); + Response response = future.get(); + assertEquals(response.getStatusCode(), 200); + assertEquals(o.toString(), MY_MESSAGE); + } finally { + client.close(); + } } /** @@ -111,53 +111,55 @@ public void RequestByteArrayOutputStreamBodyConsumerTest() throws Throwable { */ @Test(groups = { "standalone", "default_provider" }, enabled = true) public void testPutZeroBytesFileTest() throws Throwable { - System.err.println("setting up client"); - SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setIdleConnectionInPoolTimeoutInMs(100).setMaximumConnectionsTotal(50) - .setRequestTimeoutInMs(5 * 1000).setUrl(getTargetUrl() + "/testPutZeroBytesFileTest.txt").setHeader("Content-Type", "text/plain").build(); - - File tmpfile = File.createTempFile("testPutZeroBytesFile", ".tmp"); - tmpfile.deleteOnExit(); - - Future future = client.put(new FileBodyGenerator(tmpfile)); + SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setIdleConnectionInPoolTimeoutInMs(100).setMaximumConnectionsTotal(50).setRequestTimeoutInMs(5 * 1000).setUrl(getTargetUrl() + "/testPutZeroBytesFileTest.txt").setHeader("Content-Type", "text/plain") + .build(); + try { + File tmpfile = File.createTempFile("testPutZeroBytesFile", ".tmp"); + tmpfile.deleteOnExit(); - System.out.println("waiting for response"); - Response response = future.get(); + Future future = client.put(new FileBodyGenerator(tmpfile)); - tmpfile.delete(); + Response response = future.get(); - assertEquals(response.getStatusCode(), 200); + tmpfile.delete(); - client.close(); + assertEquals(response.getStatusCode(), 200); + } finally { + client.close(); + } } @Test(groups = { "standalone", "default_provider" }) public void testDerive() throws Exception { SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().build(); SimpleAsyncHttpClient derived = client.derive().build(); - - assertNotSame(derived, client); - client.close(); - derived.close(); + try { + assertNotSame(derived, client); + } finally { + client.close(); + derived.close(); + } } @Test(groups = { "standalone", "default_provider" }) public void testDeriveOverrideURL() throws Exception { SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setUrl("http://invalid.url/").build(); - ByteArrayOutputStream o = new ByteArrayOutputStream(10); - - InputStreamBodyGenerator generator = new InputStreamBodyGenerator(new ByteArrayInputStream(MY_MESSAGE.getBytes())); - OutputStreamBodyConsumer consumer = new OutputStreamBodyConsumer(o); - SimpleAsyncHttpClient derived = client.derive().setUrl(getTargetUrl()).build(); + try { + ByteArrayOutputStream o = new ByteArrayOutputStream(10); - Future future = derived.post(generator, consumer); + InputStreamBodyGenerator generator = new InputStreamBodyGenerator(new ByteArrayInputStream(MY_MESSAGE.getBytes())); + OutputStreamBodyConsumer consumer = new OutputStreamBodyConsumer(o); - Response response = future.get(); - assertEquals(response.getStatusCode(), 200); - assertEquals(o.toString(), MY_MESSAGE); + Future future = derived.post(generator, consumer); - client.close(); - derived.close(); + Response response = future.get(); + assertEquals(response.getStatusCode(), 200); + assertEquals(o.toString(), MY_MESSAGE); + } finally { + client.close(); + derived.close(); + } } @Test(groups = { "standalone", "default_provider" }) @@ -194,44 +196,47 @@ public void onBytesReceived(String url, long amount, long current, long total) { }; SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setUrl(getTargetUrl()).setHeader("Custom", "custom").setListener(listener).build(); - ByteArrayOutputStream o = new ByteArrayOutputStream(10); + try { + ByteArrayOutputStream o = new ByteArrayOutputStream(10); - InputStreamBodyGenerator generator = new InputStreamBodyGenerator(new ByteArrayInputStream(MY_MESSAGE.getBytes())); - OutputStreamBodyConsumer consumer = new OutputStreamBodyConsumer(o); + InputStreamBodyGenerator generator = new InputStreamBodyGenerator(new ByteArrayInputStream(MY_MESSAGE.getBytes())); + OutputStreamBodyConsumer consumer = new OutputStreamBodyConsumer(o); - Future future = client.post(generator, consumer); + Future future = client.post(generator, consumer); - Response response = future.get(); - client.close(); - assertEquals(response.getStatusCode(), 200); - assertEquals(o.toString(), MY_MESSAGE); + Response response = future.get(); + assertEquals(response.getStatusCode(), 200); + assertEquals(o.toString(), MY_MESSAGE); + } finally { + client.close(); + } } @Test(groups = { "standalone", "default_provider" }) public void testNullUrl() throws Exception { + SimpleAsyncHttpClient c = new SimpleAsyncHttpClient.Builder().build().derive().build(); try { - SimpleAsyncHttpClient c = new SimpleAsyncHttpClient.Builder().build().derive().build(); assertTrue(true); + } finally { c.close(); - } catch (NullPointerException ex) { - fail(); } } @Test(groups = { "standalone", "default_provider" }) public void testCloseDerivedValidMaster() throws Exception { SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setUrl(getTargetUrl()).build(); - SimpleAsyncHttpClient derived = client.derive().build(); - - derived.get().get(); - - derived.close(); + try { + SimpleAsyncHttpClient derived = client.derive().build(); + derived.get().get(); - Response response = client.get().get(); + derived.close(); - assertEquals(response.getStatusCode(), 200); + Response response = client.get().get(); - client.close(); + assertEquals(response.getStatusCode(), 200); + } finally { + client.close(); + } } @Test(groups = { "standalone", "default_provider" }) @@ -252,49 +257,49 @@ public void testCloseMasterInvalidDerived() throws Exception { @Test(groups = { "standalone", "default_provider" }) public void testMultiPartPut() throws Exception { SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setUrl(getTargetUrl() + "/multipart").build(); - - Response response = client.put(new ByteArrayPart("baPart", "fileName", "testMultiPart".getBytes("utf-8"), "application/test", "utf-8")).get(); - - String body = response.getResponseBody(); - String contentType = response.getHeader("X-Content-Type"); - - assertTrue(contentType.contains("multipart/form-data")); - - String boundary = contentType.substring(contentType.lastIndexOf("=") + 1); - - assertTrue(body.startsWith("--" + boundary)); - assertTrue(body.trim().endsWith("--" + boundary + "--")); - assertTrue(body.contains("Content-Disposition:")); - assertTrue(body.contains("Content-Type: application/test")); - assertTrue(body.contains("name=\"baPart")); - assertTrue(body.contains("filename=\"fileName")); + try { + Response response = client.put(new ByteArrayPart("baPart", "fileName", "testMultiPart".getBytes("utf-8"), "application/test", "utf-8")).get(); - client.close(); - + String body = response.getResponseBody(); + String contentType = response.getHeader("X-Content-Type"); + + assertTrue(contentType.contains("multipart/form-data")); + + String boundary = contentType.substring(contentType.lastIndexOf("=") + 1); + + assertTrue(body.startsWith("--" + boundary)); + assertTrue(body.trim().endsWith("--" + boundary + "--")); + assertTrue(body.contains("Content-Disposition:")); + assertTrue(body.contains("Content-Type: application/test")); + assertTrue(body.contains("name=\"baPart")); + assertTrue(body.contains("filename=\"fileName")); + } finally { + client.close(); + } } - + @Test(groups = { "standalone", "default_provider" }) public void testMultiPartPost() throws Exception { SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setUrl(getTargetUrl() + "/multipart").build(); - - Response response = client.post(new ByteArrayPart("baPart", "fileName", "testMultiPart".getBytes("utf-8"), "application/test", "utf-8")).get(); - - String body = response.getResponseBody(); - String contentType = response.getHeader("X-Content-Type"); - - assertTrue(contentType.contains("multipart/form-data")); - - String boundary = contentType.substring(contentType.lastIndexOf("=") + 1); - - assertTrue(body.startsWith("--" + boundary)); - assertTrue(body.trim().endsWith("--" + boundary + "--")); - assertTrue(body.contains("Content-Disposition:")); - assertTrue(body.contains("Content-Type: application/test")); - assertTrue(body.contains("name=\"baPart")); - assertTrue(body.contains("filename=\"fileName")); + try { + Response response = client.post(new ByteArrayPart("baPart", "fileName", "testMultiPart".getBytes("utf-8"), "application/test", "utf-8")).get(); - client.close(); - + String body = response.getResponseBody(); + String contentType = response.getHeader("X-Content-Type"); + + assertTrue(contentType.contains("multipart/form-data")); + + String boundary = contentType.substring(contentType.lastIndexOf("=") + 1); + + assertTrue(body.startsWith("--" + boundary)); + assertTrue(body.trim().endsWith("--" + boundary + "--")); + assertTrue(body.contains("Content-Disposition:")); + assertTrue(body.contains("Content-Type: application/test")); + assertTrue(body.contains("name=\"baPart")); + assertTrue(body.contains("filename=\"fileName")); + } finally { + client.close(); + } } } diff --git a/src/test/java/com/ning/http/client/async/TransferListenerTest.java b/src/test/java/com/ning/http/client/async/TransferListenerTest.java index e2b80690c7..894f1150dd 100644 --- a/src/test/java/com/ning/http/client/async/TransferListenerTest.java +++ b/src/test/java/com/ning/http/client/async/TransferListenerTest.java @@ -40,15 +40,11 @@ import static org.testng.Assert.fail; public abstract class TransferListenerTest extends AbstractBasicTest { - private static final File TMP = new File(System.getProperty("java.io.tmpdir"), "ahc-tests-" - + UUID.randomUUID().toString().substring(0, 8)); + private static final File TMP = new File(System.getProperty("java.io.tmpdir"), "ahc-tests-" + UUID.randomUUID().toString().substring(0, 8)); private class BasicHandler extends AbstractHandler { - public void handle(String s, - org.eclipse.jetty.server.Request r, - HttpServletRequest httpRequest, - HttpServletResponse httpResponse) throws IOException, ServletException { + public void handle(String s, org.eclipse.jetty.server.Request r, HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws IOException, ServletException { Enumeration e = httpRequest.getHeaderNames(); String param; @@ -78,10 +74,8 @@ public AbstractHandler configureHandler() throws Exception { return new BasicHandler(); } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void basicGetTest() throws Throwable { - AsyncHttpClient c = getAsyncHttpClient(null); - final AtomicReference throwable = new AtomicReference(); final AtomicReference hSent = new AtomicReference(); final AtomicReference hRead = new AtomicReference(); @@ -115,9 +109,9 @@ public void onThrowable(Throwable t) { } }); + AsyncHttpClient c = getAsyncHttpClient(null); try { - Response response = c.prepareGet(getTargetUrl()) - .execute(tl).get(); + Response response = c.prepareGet(getTargetUrl()).execute(tl).get(); assertNotNull(response); assertEquals(response.getStatusCode(), 200); @@ -127,13 +121,13 @@ public void onThrowable(Throwable t) { assertNull(throwable.get()); } catch (IOException ex) { fail("Should have timed out"); + } finally { + c.close(); } - c.close(); } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void basicPutTest() throws Throwable { - AsyncHttpClient c = getAsyncHttpClient(null); final AtomicReference throwable = new AtomicReference(); final AtomicReference hSent = new AtomicReference(); @@ -175,9 +169,9 @@ public void onThrowable(Throwable t) { } }); + AsyncHttpClient c = getAsyncHttpClient(null); try { - Response response = c.preparePut(getTargetUrl()).setBody(largeFile) - .execute(tl).get(); + Response response = c.preparePut(getTargetUrl()).setBody(largeFile).execute(tl).get(); assertNotNull(response); assertEquals(response.getStatusCode(), 200); @@ -187,13 +181,13 @@ public void onThrowable(Throwable t) { assertEquals(bbSentLenght.get(), largeFile.length()); } catch (IOException ex) { fail("Should have timed out"); + } finally { + c.close(); } - c.close(); } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void basicPutBodyTest() throws Throwable { - AsyncHttpClient c = getAsyncHttpClient(null); final AtomicReference throwable = new AtomicReference(); final AtomicReference hSent = new AtomicReference(); @@ -235,9 +229,9 @@ public void onThrowable(Throwable t) { } }); + AsyncHttpClient c = getAsyncHttpClient(null); try { - Response response = c.preparePut(getTargetUrl()).setBody(new FileBodyGenerator(largeFile)) - .execute(tl).get(); + Response response = c.preparePut(getTargetUrl()).setBody(new FileBodyGenerator(largeFile)).execute(tl).get(); assertNotNull(response); assertEquals(response.getStatusCode(), 200); @@ -247,16 +241,16 @@ public void onThrowable(Throwable t) { assertEquals(bbSentLenght.get(), largeFile.length()); } catch (IOException ex) { fail("Should have timed out"); + } finally { + c.close(); } - c.close(); } public String getTargetUrl() { return String.format("http://127.0.0.1:%d/foo/test", port1); } - public static File createTempFile(byte[] pattern, int repeat) - throws IOException { + public static File createTempFile(byte[] pattern, int repeat) throws IOException { TMP.mkdirs(); TMP.deleteOnExit(); File tmpFile = File.createTempFile("tmpfile-", ".data", TMP); @@ -265,8 +259,7 @@ public static File createTempFile(byte[] pattern, int repeat) return tmpFile; } - public static void write(byte[] pattern, int repeat, File file) - throws IOException { + public static void write(byte[] pattern, int repeat, File file) throws IOException { file.deleteOnExit(); file.getParentFile().mkdirs(); FileOutputStream out = null; @@ -275,8 +268,7 @@ public static void write(byte[] pattern, int repeat, File file) for (int i = 0; i < repeat; i++) { out.write(pattern); } - } - finally { + } finally { if (out != null) { out.close(); } diff --git a/src/test/java/com/ning/http/client/async/WebDavBasicTest.java b/src/test/java/com/ning/http/client/async/WebDavBasicTest.java index 77b69dcf67..720cd5adb5 100644 --- a/src/test/java/com/ning/http/client/async/WebDavBasicTest.java +++ b/src/test/java/com/ning/http/client/async/WebDavBasicTest.java @@ -38,7 +38,6 @@ import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertTrue; - public abstract class WebDavBasicTest extends AbstractBasicTest { public Embedded embedded; @@ -94,91 +93,100 @@ public void tearDownGlobal() throws InterruptedException, Exception { embedded.stop(); } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void mkcolWebDavTest1() throws InterruptedException, IOException, ExecutionException { AsyncHttpClient c = getAsyncHttpClient(null); - Request mkcolRequest = new RequestBuilder("MKCOL").setUrl(getTargetUrl()).build(); - Response response = c.executeRequest(mkcolRequest).get(); - - assertEquals(response.getStatusCode(), 201); - - c.close(); + try { + Request mkcolRequest = new RequestBuilder("MKCOL").setUrl(getTargetUrl()).build(); + Response response = c.executeRequest(mkcolRequest).get(); + + assertEquals(response.getStatusCode(), 201); + } finally { + c.close(); + } } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void mkcolWebDavTest2() throws InterruptedException, IOException, ExecutionException { AsyncHttpClient c = getAsyncHttpClient(null); - - Request mkcolRequest = new RequestBuilder("MKCOL").setUrl(getTargetUrl() + "/folder2").build(); - Response response = c.executeRequest(mkcolRequest).get(); - assertEquals(response.getStatusCode(), 409); - c.close(); + try { + Request mkcolRequest = new RequestBuilder("MKCOL").setUrl(getTargetUrl() + "/folder2").build(); + Response response = c.executeRequest(mkcolRequest).get(); + assertEquals(response.getStatusCode(), 409); + } finally { + c.close(); + } } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void basicPropFindWebDavTest() throws InterruptedException, IOException, ExecutionException { AsyncHttpClient c = getAsyncHttpClient(null); - Request propFindRequest = new RequestBuilder("PROPFIND").setUrl(getTargetUrl()).build(); - Response response = c.executeRequest(propFindRequest).get(); - - assertEquals(response.getStatusCode(), 404); - c.close(); + try { + Request propFindRequest = new RequestBuilder("PROPFIND").setUrl(getTargetUrl()).build(); + Response response = c.executeRequest(propFindRequest).get(); + + assertEquals(response.getStatusCode(), 404); + } finally { + c.close(); + } } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void propFindWebDavTest() throws InterruptedException, IOException, ExecutionException { AsyncHttpClient c = getAsyncHttpClient(null); - - Request mkcolRequest = new RequestBuilder("MKCOL").setUrl(getTargetUrl()).build(); - Response response = c.executeRequest(mkcolRequest).get(); - assertEquals(response.getStatusCode(), 201); - - Request putRequest = new RequestBuilder("PUT").setUrl(String.format("http://127.0.0.1:%s/folder1/Test.txt", port1)).setBody("this is a test").build(); - response = c.executeRequest(putRequest).get(); - assertEquals(response.getStatusCode(), 201); - - Request propFindRequest = new RequestBuilder("PROPFIND").setUrl(String.format("http://127.0.0.1:%s/folder1/Test.txt", port1)).build(); - response = c.executeRequest(propFindRequest).get(); - - assertEquals(response.getStatusCode(), 207); - assertTrue(response.getResponseBody().contains("HTTP/1.1 200 OK")); - c.close(); - + try { + Request mkcolRequest = new RequestBuilder("MKCOL").setUrl(getTargetUrl()).build(); + Response response = c.executeRequest(mkcolRequest).get(); + assertEquals(response.getStatusCode(), 201); + + Request putRequest = new RequestBuilder("PUT").setUrl(String.format("http://127.0.0.1:%s/folder1/Test.txt", port1)).setBody("this is a test").build(); + response = c.executeRequest(putRequest).get(); + assertEquals(response.getStatusCode(), 201); + + Request propFindRequest = new RequestBuilder("PROPFIND").setUrl(String.format("http://127.0.0.1:%s/folder1/Test.txt", port1)).build(); + response = c.executeRequest(propFindRequest).get(); + + assertEquals(response.getStatusCode(), 207); + assertTrue(response.getResponseBody().contains("HTTP/1.1 200 OK")); + } finally { + c.close(); + } } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void propFindCompletionHandlerWebDavTest() throws InterruptedException, IOException, ExecutionException { AsyncHttpClient c = getAsyncHttpClient(null); - - Request mkcolRequest = new RequestBuilder("MKCOL").setUrl(getTargetUrl()).build(); - Response response = c.executeRequest(mkcolRequest).get(); - assertEquals(response.getStatusCode(), 201); - - Request propFindRequest = new RequestBuilder("PROPFIND").setUrl(getTargetUrl()).build(); - WebDavResponse webDavResponse = c.executeRequest(propFindRequest, new WebDavCompletionHandlerBase() { - /** - * {@inheritDoc} - */ - /* @Override */ - public void onThrowable(Throwable t) { - - t.printStackTrace(); - } - - @Override - public WebDavResponse onCompleted(WebDavResponse response) throws Exception { - return response; - } - }).get(); - - assertNotNull(webDavResponse); - assertEquals(webDavResponse.getStatusCode(), 200); - c.close(); + try { + Request mkcolRequest = new RequestBuilder("MKCOL").setUrl(getTargetUrl()).build(); + Response response = c.executeRequest(mkcolRequest).get(); + assertEquals(response.getStatusCode(), 201); + + Request propFindRequest = new RequestBuilder("PROPFIND").setUrl(getTargetUrl()).build(); + WebDavResponse webDavResponse = c.executeRequest(propFindRequest, new WebDavCompletionHandlerBase() { + /** + * {@inheritDoc} + */ + /* @Override */ + public void onThrowable(Throwable t) { + + t.printStackTrace(); + } + + @Override + public WebDavResponse onCompleted(WebDavResponse response) throws Exception { + return response; + } + }).get(); + + assertNotNull(webDavResponse); + assertEquals(webDavResponse.getStatusCode(), 200); + } finally { + c.close(); + } } - } diff --git a/src/test/java/com/ning/http/client/async/ZeroCopyFileTest.java b/src/test/java/com/ning/http/client/async/ZeroCopyFileTest.java index 64efdb4c29..b5400b183e 100644 --- a/src/test/java/com/ning/http/client/async/ZeroCopyFileTest.java +++ b/src/test/java/com/ning/http/client/async/ZeroCopyFileTest.java @@ -47,10 +47,7 @@ public abstract class ZeroCopyFileTest extends AbstractBasicTest { private class ZeroCopyHandler extends AbstractHandler { - public void handle(String s, - Request r, - HttpServletRequest httpRequest, - HttpServletResponse httpResponse) throws IOException, ServletException { + public void handle(String s, Request r, HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws IOException, ServletException { int size = 10 * 1024; if (httpRequest.getContentLength() > 0) { @@ -67,59 +64,62 @@ public void handle(String s, } } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void zeroCopyPostTest() throws IOException, ExecutionException, TimeoutException, InterruptedException, URISyntaxException { AsyncHttpClient client = getAsyncHttpClient(null); + try { + ClassLoader cl = getClass().getClassLoader(); + // override system properties + URL url = cl.getResource("SimpleTextFile.txt"); + File file = new File(url.toURI()); + final AtomicBoolean headerSent = new AtomicBoolean(false); + final AtomicBoolean operationCompleted = new AtomicBoolean(false); + + Future f = client.preparePost("http://127.0.0.1/" + port1 + "/").setBody(file).execute(new AsyncCompletionHandler() { + + public STATE onHeaderWriteCompleted() { + headerSent.set(true); + return STATE.CONTINUE; + } - ClassLoader cl = getClass().getClassLoader(); - // override system properties - URL url = cl.getResource("SimpleTextFile.txt"); - File file = new File(url.toURI()); - final AtomicBoolean headerSent = new AtomicBoolean(false); - final AtomicBoolean operationCompleted = new AtomicBoolean(false); - - Future f = client.preparePost("http://127.0.0.1/" + port1 + "/").setBody(file).execute(new AsyncCompletionHandler() { - - public STATE onHeaderWriteCompleted() { - headerSent.set(true); - return STATE.CONTINUE; - } - - public STATE onContentWriteCompleted() { - operationCompleted.set(true); - return STATE.CONTINUE; - } + public STATE onContentWriteCompleted() { + operationCompleted.set(true); + return STATE.CONTINUE; + } - @Override - public Object onCompleted(Response response) throws Exception { - return response; - } - }); - Response resp = f.get(); - assertNotNull(resp); - assertEquals(resp.getStatusCode(), HttpServletResponse.SC_OK); - assertEquals(resp.getResponseBody(), "This is a simple test file"); - assertTrue(operationCompleted.get()); - assertTrue(headerSent.get()); - client.close(); + @Override + public Response onCompleted(Response response) throws Exception { + return response; + } + }); + Response resp = f.get(); + assertNotNull(resp); + assertEquals(resp.getStatusCode(), HttpServletResponse.SC_OK); + assertEquals(resp.getResponseBody(), "This is a simple test file"); + assertTrue(operationCompleted.get()); + assertTrue(headerSent.get()); + } finally { + client.close(); + } } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void zeroCopyPutTest() throws IOException, ExecutionException, TimeoutException, InterruptedException, URISyntaxException { AsyncHttpClient client = getAsyncHttpClient(null); - - ClassLoader cl = getClass().getClassLoader(); - // override system properties - URL url = cl.getResource("SimpleTextFile.txt"); - File file = new File(url.toURI()); - - Future f = client.preparePut("http://127.0.0.1/" + port1 + "/").setBody(file).execute(); - Response resp = f.get(); - assertNotNull(resp); - assertEquals(resp.getStatusCode(), HttpServletResponse.SC_OK); - assertEquals(resp.getResponseBody(), "This is a simple test file"); - client.close(); - + try { + ClassLoader cl = getClass().getClassLoader(); + // override system properties + URL url = cl.getResource("SimpleTextFile.txt"); + File file = new File(url.toURI()); + + Future f = client.preparePut("http://127.0.0.1/" + port1 + "/").setBody(file).execute(); + Response resp = f.get(); + assertNotNull(resp); + assertEquals(resp.getStatusCode(), HttpServletResponse.SC_OK); + assertEquals(resp.getResponseBody(), "This is a simple test file"); + } finally { + client.close(); + } } @Override @@ -127,92 +127,92 @@ public AbstractHandler configureHandler() throws Exception { return new ZeroCopyHandler(); } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void zeroCopyFileTest() throws IOException, ExecutionException, TimeoutException, InterruptedException, URISyntaxException { AsyncHttpClient client = getAsyncHttpClient(null); + try { + ClassLoader cl = getClass().getClassLoader(); + // override system properties + URL url = cl.getResource("SimpleTextFile.txt"); + File file = new File(url.toURI()); + + File tmp = new File(System.getProperty("java.io.tmpdir") + File.separator + "zeroCopy.txt"); + tmp.deleteOnExit(); + final FileOutputStream stream = new FileOutputStream(tmp); + Future f = client.preparePost("http://127.0.0.1/" + port1 + "/").setBody(file).execute(new AsyncHandler() { + public void onThrowable(Throwable t) { + } - ClassLoader cl = getClass().getClassLoader(); - // override system properties - URL url = cl.getResource("SimpleTextFile.txt"); - File file = new File(url.toURI()); - - File tmp = new File(System.getProperty("java.io.tmpdir") + File.separator + "zeroCopy.txt"); - tmp.deleteOnExit(); - final FileOutputStream stream = new FileOutputStream(tmp); - Future f = client.preparePost("http://127.0.0.1/" + port1 + "/").setBody(file).execute(new AsyncHandler() { - public void onThrowable(Throwable t) { - } - - public STATE onBodyPartReceived(HttpResponseBodyPart bodyPart) throws Exception { - bodyPart.writeTo(stream); - return STATE.CONTINUE; - } - - public STATE onStatusReceived(HttpResponseStatus responseStatus) throws Exception { - return STATE.CONTINUE; - } + public STATE onBodyPartReceived(HttpResponseBodyPart bodyPart) throws Exception { + bodyPart.writeTo(stream); + return STATE.CONTINUE; + } - public STATE onHeadersReceived(HttpResponseHeaders headers) throws Exception { - return STATE.CONTINUE; - } + public STATE onStatusReceived(HttpResponseStatus responseStatus) throws Exception { + return STATE.CONTINUE; + } - public Response onCompleted() throws Exception { - return null; - } - }); - Response resp = f.get(); - stream.close(); - assertNull(resp); - assertEquals(file.length(), tmp.length()); - client.close(); + public STATE onHeadersReceived(HttpResponseHeaders headers) throws Exception { + return STATE.CONTINUE; + } + public Response onCompleted() throws Exception { + return null; + } + }); + Response resp = f.get(); + stream.close(); + assertNull(resp); + assertEquals(file.length(), tmp.length()); + } finally { + client.close(); + } } - - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void zeroCopyFileWithBodyManipulationTest() throws IOException, ExecutionException, TimeoutException, InterruptedException, URISyntaxException { AsyncHttpClient client = getAsyncHttpClient(null); + try { + ClassLoader cl = getClass().getClassLoader(); + // override system properties + URL url = cl.getResource("SimpleTextFile.txt"); + File file = new File(url.toURI()); + + File tmp = new File(System.getProperty("java.io.tmpdir") + File.separator + "zeroCopy.txt"); + tmp.deleteOnExit(); + final FileOutputStream stream = new FileOutputStream(tmp); + Future f = client.preparePost("http://127.0.0.1/" + port1 + "/").setBody(file).execute(new AsyncHandler() { + public void onThrowable(Throwable t) { + } - ClassLoader cl = getClass().getClassLoader(); - // override system properties - URL url = cl.getResource("SimpleTextFile.txt"); - File file = new File(url.toURI()); - - File tmp = new File(System.getProperty("java.io.tmpdir") + File.separator + "zeroCopy.txt"); - tmp.deleteOnExit(); - final FileOutputStream stream = new FileOutputStream(tmp); - Future f = client.preparePost("http://127.0.0.1/" + port1 + "/").setBody(file).execute(new AsyncHandler() { - public void onThrowable(Throwable t) { - } + public STATE onBodyPartReceived(HttpResponseBodyPart bodyPart) throws Exception { + bodyPart.writeTo(stream); - public STATE onBodyPartReceived(HttpResponseBodyPart bodyPart) throws Exception { - bodyPart.writeTo(stream); + if (bodyPart.getBodyPartBytes().length == 0) { + return STATE.ABORT; + } - if (bodyPart.getBodyPartBytes().length == 0) { - return STATE.ABORT; + return STATE.CONTINUE; } - - return STATE.CONTINUE; - } - - public STATE onStatusReceived(HttpResponseStatus responseStatus) throws Exception { - return STATE.CONTINUE; - } - public STATE onHeadersReceived(HttpResponseHeaders headers) throws Exception { - return STATE.CONTINUE; - } + public STATE onStatusReceived(HttpResponseStatus responseStatus) throws Exception { + return STATE.CONTINUE; + } - public Response onCompleted() throws Exception { - return null; - } - }); - Response resp = f.get(); - stream.close(); - assertNull(resp); - assertEquals(file.length(), tmp.length()); - client.close(); + public STATE onHeadersReceived(HttpResponseHeaders headers) throws Exception { + return STATE.CONTINUE; + } + public Response onCompleted() throws Exception { + return null; + } + }); + Response resp = f.get(); + stream.close(); + assertNull(resp); + assertEquals(file.length(), tmp.length()); + } finally { + client.close(); + } } - } diff --git a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyAsyncProviderBasicTest.java b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyAsyncProviderBasicTest.java index c718e2e031..739bb8f4f1 100644 --- a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyAsyncProviderBasicTest.java +++ b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyAsyncProviderBasicTest.java @@ -13,46 +13,36 @@ package com.ning.http.client.async.grizzly; +import static com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProviderConfig.Property.TRANSPORT_CUSTOMIZER; + +import org.glassfish.grizzly.filterchain.FilterChainBuilder; +import org.glassfish.grizzly.nio.transport.TCPNIOTransport; +import org.glassfish.grizzly.strategies.SameThreadIOStrategy; +import org.testng.annotations.Test; + import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.AsyncHttpProviderConfig; -import com.ning.http.client.FluentCaseInsensitiveStringsMap; -import com.ning.http.client.Response; import com.ning.http.client.async.AsyncProvidersBasicTest; -import com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProvider; +import com.ning.http.client.async.ProviderUtil; import com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProviderConfig; import com.ning.http.client.providers.grizzly.TransportCustomizer; -import org.glassfish.grizzly.filterchain.FilterChainBuilder; -import org.glassfish.grizzly.nio.transport.TCPNIOTransport; -import org.glassfish.grizzly.strategies.SameThreadIOStrategy; -import org.testng.Assert; -import org.testng.annotations.Test; - -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -import static com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProviderConfig.Property.TRANSPORT_CUSTOMIZER; -import static org.testng.Assert.assertEquals; public class GrizzlyAsyncProviderBasicTest extends AsyncProvidersBasicTest { - @Override public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { - if (config == null) { - config = new AsyncHttpClientConfig.Builder().build(); - } - return new AsyncHttpClient(new GrizzlyAsyncHttpProvider(config), config); + return ProviderUtil.grizzlyProvider(config); } @Override @Test public void asyncHeaderPOSTTest() throws Throwable { - super.asyncHeaderPOSTTest(); //To change body of overridden methods use File | Settings | File Templates. + super.asyncHeaderPOSTTest(); // To change body of overridden methods use File | Settings | File Templates. } @Override - protected AsyncHttpProviderConfig getProviderConfig() { + protected AsyncHttpProviderConfig getProviderConfig() { final GrizzlyAsyncHttpProviderConfig config = new GrizzlyAsyncHttpProviderConfig(); config.addProperty(TRANSPORT_CUSTOMIZER, new TransportCustomizer() { @Override @@ -64,7 +54,7 @@ public void customize(TCPNIOTransport transport, FilterChainBuilder builder) { return config; } - @Test(groups = {"standalone", "default_provider", "async"}, enabled = false) + @Test(groups = { "standalone", "default_provider", "async" }, enabled = false) public void asyncDoPostBasicGZIPTest() throws Throwable { } } diff --git a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyAsyncStreamHandlerTest.java b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyAsyncStreamHandlerTest.java index c9bb4de004..cce3263723 100644 --- a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyAsyncStreamHandlerTest.java +++ b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyAsyncStreamHandlerTest.java @@ -16,16 +16,13 @@ import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.async.AsyncStreamHandlerTest; -import com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProvider; +import com.ning.http.client.async.ProviderUtil; public class GrizzlyAsyncStreamHandlerTest extends AsyncStreamHandlerTest { @Override public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { - if (config == null) { - config = new AsyncHttpClientConfig.Builder().build(); - } - return new AsyncHttpClient(new GrizzlyAsyncHttpProvider(config), config); + return ProviderUtil.grizzlyProvider(config); } } diff --git a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyAsyncStreamLifecycleTest.java b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyAsyncStreamLifecycleTest.java index b2d376d690..094eecb133 100644 --- a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyAsyncStreamLifecycleTest.java +++ b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyAsyncStreamLifecycleTest.java @@ -16,16 +16,13 @@ import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.async.AsyncStreamLifecycleTest; -import com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProvider; +import com.ning.http.client.async.ProviderUtil; public class GrizzlyAsyncStreamLifecycleTest extends AsyncStreamLifecycleTest { @Override public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { - if (config == null) { - config = new AsyncHttpClientConfig.Builder().build(); - } - return new AsyncHttpClient(new GrizzlyAsyncHttpProvider(config), config); + return ProviderUtil.grizzlyProvider(config); } } diff --git a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyAuthTimeoutTest.java b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyAuthTimeoutTest.java index c0224564ca..631d25c9df 100644 --- a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyAuthTimeoutTest.java +++ b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyAuthTimeoutTest.java @@ -16,17 +16,12 @@ import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.async.AuthTimeoutTest; -import com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProvider; +import com.ning.http.client.async.ProviderUtil; public class GrizzlyAuthTimeoutTest extends AuthTimeoutTest { - @Override public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { - if (config == null) { - config = new AsyncHttpClientConfig.Builder().build(); - } - return new AsyncHttpClient(new GrizzlyAsyncHttpProvider(config), config); + return ProviderUtil.grizzlyProvider(config); } - } diff --git a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyBasicAuthTest.java b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyBasicAuthTest.java index 4f0dc2634e..98323e7b28 100644 --- a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyBasicAuthTest.java +++ b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyBasicAuthTest.java @@ -16,17 +16,13 @@ import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.async.BasicAuthTest; -import com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProvider; +import com.ning.http.client.async.ProviderUtil; public class GrizzlyBasicAuthTest extends BasicAuthTest { - @Override public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { - if (config == null) { - config = new AsyncHttpClientConfig.Builder().build(); - } - return new AsyncHttpClient(new GrizzlyAsyncHttpProvider(config), config); + return ProviderUtil.grizzlyProvider(config); } } diff --git a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyBasicHttpsTest.java b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyBasicHttpsTest.java index d5e27c68f2..2ebeedc182 100644 --- a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyBasicHttpsTest.java +++ b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyBasicHttpsTest.java @@ -16,20 +16,17 @@ import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.async.BasicHttpsTest; -import com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProvider; +import com.ning.http.client.async.ProviderUtil; public class GrizzlyBasicHttpsTest extends BasicHttpsTest { @Override public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { - if (config == null) { - config = new AsyncHttpClientConfig.Builder().build(); - } - return new AsyncHttpClient(new GrizzlyAsyncHttpProvider(config), config); + return ProviderUtil.grizzlyProvider(config); } @Override public void zeroCopyPostTest() throws Throwable { - super.zeroCopyPostTest(); //To change body of overridden methods use File | Settings | File Templates. + super.zeroCopyPostTest(); // To change body of overridden methods use File | Settings | File Templates. } } diff --git a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyBodyChunkTest.java b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyBodyChunkTest.java index 643628e64f..9a58678980 100644 --- a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyBodyChunkTest.java +++ b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyBodyChunkTest.java @@ -16,16 +16,13 @@ import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.async.BodyChunkTest; -import com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProvider; +import com.ning.http.client.async.ProviderUtil; public class GrizzlyBodyChunkTest extends BodyChunkTest { @Override public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { - if (config == null) { - config = new AsyncHttpClientConfig.Builder().build(); - } - return new AsyncHttpClient(new GrizzlyAsyncHttpProvider(config), config); + return ProviderUtil.grizzlyProvider(config); } } diff --git a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyBodyDeferringAsyncHandlerTest.java b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyBodyDeferringAsyncHandlerTest.java index 889f49ad89..5b0810feea 100644 --- a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyBodyDeferringAsyncHandlerTest.java +++ b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyBodyDeferringAsyncHandlerTest.java @@ -16,15 +16,12 @@ import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.async.BodyDeferringAsyncHandlerTest; -import com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProvider; +import com.ning.http.client.async.ProviderUtil; public class GrizzlyBodyDeferringAsyncHandlerTest extends BodyDeferringAsyncHandlerTest { @Override public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { - if (config == null) { - config = new AsyncHttpClientConfig.Builder().build(); - } - return new AsyncHttpClient(new GrizzlyAsyncHttpProvider(config), config); + return ProviderUtil.grizzlyProvider(config); } } diff --git a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyByteBufferCapacityTest.java b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyByteBufferCapacityTest.java index b875ce10f4..d3522541b2 100644 --- a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyByteBufferCapacityTest.java +++ b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyByteBufferCapacityTest.java @@ -13,23 +13,21 @@ package com.ning.http.client.async.grizzly; +import org.testng.annotations.Test; + import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.async.ByteBufferCapacityTest; -import com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProvider; -import org.testng.annotations.Test; +import com.ning.http.client.async.ProviderUtil; public class GrizzlyByteBufferCapacityTest extends ByteBufferCapacityTest { @Override public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { - if (config == null) { - config = new AsyncHttpClientConfig.Builder().build(); - } - return new AsyncHttpClient(new GrizzlyAsyncHttpProvider(config), config); + return ProviderUtil.grizzlyProvider(config); } - @Test(groups = {"standalone", "default_provider"}, enabled=false) + @Test(groups = { "standalone", "default_provider" }, enabled = false) public void basicByteBufferTest() throws Throwable { } } diff --git a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyChunkingTest.java b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyChunkingTest.java index 153f80c80b..9f07b7d498 100644 --- a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyChunkingTest.java +++ b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyChunkingTest.java @@ -16,16 +16,13 @@ import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.async.ChunkingTest; -import com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProvider; +import com.ning.http.client.async.ProviderUtil; public class GrizzlyChunkingTest extends ChunkingTest { @Override public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { - if (config == null) { - config = new AsyncHttpClientConfig.Builder().build(); - } - return new AsyncHttpClient(new GrizzlyAsyncHttpProvider(config), config); + return ProviderUtil.grizzlyProvider(config); } } diff --git a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyComplexClientTest.java b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyComplexClientTest.java index 0b8b4a9d18..5a5bd7a0f0 100644 --- a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyComplexClientTest.java +++ b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyComplexClientTest.java @@ -16,16 +16,13 @@ import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.async.ComplexClientTest; -import com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProvider; +import com.ning.http.client.async.ProviderUtil; public class GrizzlyComplexClientTest extends ComplexClientTest { @Override public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { - if (config == null) { - config = new AsyncHttpClientConfig.Builder().build(); - } - return new AsyncHttpClient(new GrizzlyAsyncHttpProvider(config), config); + return ProviderUtil.grizzlyProvider(config); } } diff --git a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyConnectionPoolTest.java b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyConnectionPoolTest.java index 37395056c1..4eabd6c653 100644 --- a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyConnectionPoolTest.java +++ b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyConnectionPoolTest.java @@ -13,63 +13,61 @@ package com.ning.http.client.async.grizzly; -import com.ning.http.client.AsyncCompletionHandler; -import com.ning.http.client.AsyncHttpClient; -import com.ning.http.client.AsyncHttpClientConfig; -import com.ning.http.client.ConnectionsPool; -import com.ning.http.client.Response; -import com.ning.http.client.async.ConnectionPoolTest; -import com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProvider; -import org.glassfish.grizzly.Connection; -import org.testng.annotations.Test; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertNull; +import static org.testng.Assert.fail; import java.io.IOException; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; -import static org.testng.Assert.*; +import org.glassfish.grizzly.Connection; +import org.testng.annotations.Test; + +import com.ning.http.client.AsyncCompletionHandler; +import com.ning.http.client.AsyncHttpClient; +import com.ning.http.client.AsyncHttpClientConfig; +import com.ning.http.client.ConnectionsPool; +import com.ning.http.client.Response; +import com.ning.http.client.async.ConnectionPoolTest; +import com.ning.http.client.async.ProviderUtil; public class GrizzlyConnectionPoolTest extends ConnectionPoolTest { @Override public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { - if (config == null) { - config = new AsyncHttpClientConfig.Builder().build(); - } - return new AsyncHttpClient(new GrizzlyAsyncHttpProvider(config), config); + return ProviderUtil.grizzlyProvider(config); } @Override @Test public void testMaxTotalConnectionsException() { - AsyncHttpClient client = getAsyncHttpClient( - new AsyncHttpClientConfig.Builder() - .setAllowPoolingConnection(true) - .setMaximumConnectionsTotal(1) - .build() - ); - - String url = getTargetUrl(); - int i; - Exception exception = null; - for (i = 0; i < 20; i++) { - try { - log.info("{} requesting url [{}]...", i, url); - - if (i < 5) { - client.prepareGet(url).execute().get(); - } else { - client.prepareGet(url).execute(); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setAllowPoolingConnection(true).setMaximumConnectionsTotal(1).build()); + try { + String url = getTargetUrl(); + int i; + Exception exception = null; + for (i = 0; i < 20; i++) { + try { + log.info("{} requesting url [{}]...", i, url); + + if (i < 5) { + client.prepareGet(url).execute().get(); + } else { + client.prepareGet(url).execute(); + } + } catch (Exception ex) { + exception = ex; + break; } - } catch (Exception ex) { - exception = ex; - break; } + assertNotNull(exception); + assertNotNull(exception.getMessage()); + } finally { + client.close(); } - assertNotNull(exception); - assertNotNull(exception.getMessage()); - } @Override @@ -97,24 +95,22 @@ public void destroy() { } }; - AsyncHttpClient client = getAsyncHttpClient( - new AsyncHttpClientConfig.Builder() - .setConnectionsPool(cp) - .build() - ); - - Exception exception = null; + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setConnectionsPool(cp).build()); try { - client.prepareGet(getTargetUrl()).execute().get(TIMEOUT, TimeUnit.SECONDS); - } catch (Exception ex) { - ex.printStackTrace(); - exception = ex; + Exception exception = null; + try { + client.prepareGet(getTargetUrl()).execute().get(TIMEOUT, TimeUnit.SECONDS); + } catch (Exception ex) { + ex.printStackTrace(); + exception = ex; + } + assertNull(exception); + } finally { + client.close(); } - assertNull(exception); - client.close(); } - @Test(groups = {"standalone", "default_provider"}) + @Test(groups = { "standalone", "default_provider" }) public void testInvalidConnectionsPool() { ConnectionsPool cp = new ConnectionsPool() { @@ -140,74 +136,68 @@ public void destroy() { } }; - AsyncHttpClient client = getAsyncHttpClient( - new AsyncHttpClientConfig.Builder() - .setConnectionsPool(cp) - .build() - ); - - Exception exception = null; + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setConnectionsPool(cp).build()); try { - client.prepareGet(getTargetUrl()).execute().get(TIMEOUT, TimeUnit.SECONDS); - } catch (Exception ex) { - ex.printStackTrace(); - exception = ex; + Exception exception = null; + try { + client.prepareGet(getTargetUrl()).execute().get(TIMEOUT, TimeUnit.SECONDS); + } catch (Exception ex) { + ex.printStackTrace(); + exception = ex; + } + assertNotNull(exception); + } finally { + client.close(); } - assertNotNull(exception); - client.close(); } @Override @Test public void multipleMaxConnectionOpenTest() throws Throwable { - AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setAllowPoolingConnection(true) - .setConnectionTimeoutInMs(5000).setMaximumConnectionsTotal(1).build(); + AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setAllowPoolingConnection(true).setConnectionTimeoutInMs(5000).setMaximumConnectionsTotal(1).build(); AsyncHttpClient c = getAsyncHttpClient(cg); + try { + String body = "hello there"; - String body = "hello there"; - - // once - Response response = c.preparePost(getTargetUrl()) - .setBody(body) - .execute().get(TIMEOUT, TimeUnit.SECONDS); + // once + Response response = c.preparePost(getTargetUrl()).setBody(body).execute().get(TIMEOUT, TimeUnit.SECONDS); - assertEquals(response.getResponseBody(), body); + assertEquals(response.getResponseBody(), body); - // twice - Exception exception = null; - try { - c.preparePost(String.format("http://127.0.0.1:%d/foo/test", port2)).setBody(body).execute().get(TIMEOUT, TimeUnit.SECONDS); - fail("Should throw exception. Too many connections issued."); - } catch (Exception ex) { - ex.printStackTrace(); - exception = ex; + // twice + Exception exception = null; + try { + c.preparePost(String.format("http://127.0.0.1:%d/foo/test", port2)).setBody(body).execute().get(TIMEOUT, TimeUnit.SECONDS); + fail("Should throw exception. Too many connections issued."); + } catch (Exception ex) { + ex.printStackTrace(); + exception = ex; + } + assertNotNull(exception); + } finally { + c.close(); } - assertNotNull(exception); - c.close(); } - @Override @Test public void win7DisconnectTest() throws Throwable { final AtomicInteger count = new AtomicInteger(0); - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().build()); - AsyncCompletionHandler handler = new - AsyncCompletionHandlerAdapter() { - - @Override - public Response onCompleted(Response response) throws - Exception { - - count.incrementAndGet(); - StackTraceElement e = new StackTraceElement("sun.nio.ch.SocketDispatcher", "read0", null, -1); - IOException t = new IOException(); - t.setStackTrace(new StackTraceElement[]{e}); - throw t; - } - }; + AsyncCompletionHandler handler = new AsyncCompletionHandlerAdapter() { + @Override + public Response onCompleted(Response response) throws Exception { + + count.incrementAndGet(); + StackTraceElement e = new StackTraceElement("sun.nio.ch.SocketDispatcher", "read0", null, -1); + IOException t = new IOException(); + t.setStackTrace(new StackTraceElement[] { e }); + throw t; + } + }; + + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().build()); try { client.prepareGet(getTargetUrl()).execute(handler).get(); fail("Must have received an exception"); @@ -216,8 +206,8 @@ public Response onCompleted(Response response) throws assertNotNull(ex.getCause()); assertEquals(ex.getCause().getClass(), IOException.class); assertEquals(count.get(), 1); + } finally { + client.close(); } - client.close(); } - } diff --git a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyDigestAuthTest.java b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyDigestAuthTest.java index 95f2f8879a..77805bedf6 100644 --- a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyDigestAuthTest.java +++ b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyDigestAuthTest.java @@ -16,16 +16,13 @@ import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.async.DigestAuthTest; -import com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProvider; +import com.ning.http.client.async.ProviderUtil; public class GrizzlyDigestAuthTest extends DigestAuthTest { @Override public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { - if (config == null) { - config = new AsyncHttpClientConfig.Builder().build(); - } - return new AsyncHttpClient(new GrizzlyAsyncHttpProvider(config), config); + return ProviderUtil.grizzlyProvider(config); } } diff --git a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyEmptyBodyTest.java b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyEmptyBodyTest.java index a6a88a4239..308177d336 100644 --- a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyEmptyBodyTest.java +++ b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyEmptyBodyTest.java @@ -16,16 +16,13 @@ import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.async.EmptyBodyTest; -import com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProvider; +import com.ning.http.client.async.ProviderUtil; public class GrizzlyEmptyBodyTest extends EmptyBodyTest { @Override public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { - if (config == null) { - config = new AsyncHttpClientConfig.Builder().build(); - } - return new AsyncHttpClient(new GrizzlyAsyncHttpProvider(config), config); + return ProviderUtil.grizzlyProvider(config); } } diff --git a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyErrorResponseTest.java b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyErrorResponseTest.java index 33c0ff2e7b..5ff47a0be2 100644 --- a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyErrorResponseTest.java +++ b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyErrorResponseTest.java @@ -16,16 +16,12 @@ import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.async.ErrorResponseTest; -import com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProvider; +import com.ning.http.client.async.ProviderUtil; public class GrizzlyErrorResponseTest extends ErrorResponseTest { @Override public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { - if (config == null) { - config = new AsyncHttpClientConfig.Builder().build(); - } - return new AsyncHttpClient(new GrizzlyAsyncHttpProvider(config), config); + return ProviderUtil.grizzlyProvider(config); } - } diff --git a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyExpectContinue100Test.java b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyExpectContinue100Test.java index 09307e7185..0b8b085591 100644 --- a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyExpectContinue100Test.java +++ b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyExpectContinue100Test.java @@ -16,16 +16,12 @@ import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.async.Expect100ContinueTest; -import com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProvider; +import com.ning.http.client.async.ProviderUtil; -public class GrizzlyExpectContinue100Test extends Expect100ContinueTest{ +public class GrizzlyExpectContinue100Test extends Expect100ContinueTest { @Override public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { - if (config == null) { - config = new AsyncHttpClientConfig.Builder().build(); - } - return new AsyncHttpClient(new GrizzlyAsyncHttpProvider(config), config); + return ProviderUtil.grizzlyProvider(config); } - } diff --git a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyFilterTest.java b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyFilterTest.java index 19a7d7ce21..c6587ebb63 100644 --- a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyFilterTest.java +++ b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyFilterTest.java @@ -16,16 +16,12 @@ import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.async.FilterTest; -import com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProvider; +import com.ning.http.client.async.ProviderUtil; public class GrizzlyFilterTest extends FilterTest { @Override public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { - if (config == null) { - config = new AsyncHttpClientConfig.Builder().build(); - } - return new AsyncHttpClient(new GrizzlyAsyncHttpProvider(config), config); + return ProviderUtil.grizzlyProvider(config); } - } diff --git a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyFollowingThreadTest.java b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyFollowingThreadTest.java index 9835a67d79..74c6347ce7 100644 --- a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyFollowingThreadTest.java +++ b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyFollowingThreadTest.java @@ -16,16 +16,13 @@ import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.async.FollowingThreadTest; -import com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProvider; +import com.ning.http.client.async.ProviderUtil; public class GrizzlyFollowingThreadTest extends FollowingThreadTest { @Override public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { - if (config == null) { - config = new AsyncHttpClientConfig.Builder().build(); - } - return new AsyncHttpClient(new GrizzlyAsyncHttpProvider(config), config); + return ProviderUtil.grizzlyProvider(config); } } diff --git a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyHead302Test.java b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyHead302Test.java index a84023b1a2..70b6630f3b 100644 --- a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyHead302Test.java +++ b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyHead302Test.java @@ -16,16 +16,13 @@ import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.async.Head302Test; -import com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProvider; +import com.ning.http.client.async.ProviderUtil; public class GrizzlyHead302Test extends Head302Test { @Override public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { - if (config == null) { - config = new AsyncHttpClientConfig.Builder().build(); - } - return new AsyncHttpClient(new GrizzlyAsyncHttpProvider(config), config); + return ProviderUtil.grizzlyProvider(config); } } diff --git a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyHttpToHttpsRedirectTest.java b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyHttpToHttpsRedirectTest.java index c6ea5c47d5..c6c1351aaf 100644 --- a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyHttpToHttpsRedirectTest.java +++ b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyHttpToHttpsRedirectTest.java @@ -16,16 +16,13 @@ import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.async.HttpToHttpsRedirectTest; -import com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProvider; +import com.ning.http.client.async.ProviderUtil; public class GrizzlyHttpToHttpsRedirectTest extends HttpToHttpsRedirectTest { @Override public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { - if (config == null) { - config = new AsyncHttpClientConfig.Builder().build(); - } - return new AsyncHttpClient(new GrizzlyAsyncHttpProvider(config), config); + return ProviderUtil.grizzlyProvider(config); } } diff --git a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyIdleStateHandlerTest.java b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyIdleStateHandlerTest.java index 1096adab69..9b6500bec5 100644 --- a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyIdleStateHandlerTest.java +++ b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyIdleStateHandlerTest.java @@ -16,16 +16,13 @@ import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.async.IdleStateHandlerTest; -import com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProvider; +import com.ning.http.client.async.ProviderUtil; public class GrizzlyIdleStateHandlerTest extends IdleStateHandlerTest { @Override public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { - if (config == null) { - config = new AsyncHttpClientConfig.Builder().build(); - } - return new AsyncHttpClient(new GrizzlyAsyncHttpProvider(config), config); + return ProviderUtil.grizzlyProvider(config); } } diff --git a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyInputStreamTest.java b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyInputStreamTest.java index 6702035939..943a711aac 100644 --- a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyInputStreamTest.java +++ b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyInputStreamTest.java @@ -16,16 +16,13 @@ import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.async.InputStreamTest; -import com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProvider; +import com.ning.http.client.async.ProviderUtil; public class GrizzlyInputStreamTest extends InputStreamTest { @Override public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { - if (config == null) { - config = new AsyncHttpClientConfig.Builder().build(); - } - return new AsyncHttpClient(new GrizzlyAsyncHttpProvider(config), config); + return ProviderUtil.grizzlyProvider(config); } } diff --git a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyListenableFutureTest.java b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyListenableFutureTest.java index 285e612721..5839c271cd 100644 --- a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyListenableFutureTest.java +++ b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyListenableFutureTest.java @@ -16,16 +16,13 @@ import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.async.ListenableFutureTest; -import com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProvider; +import com.ning.http.client.async.ProviderUtil; public class GrizzlyListenableFutureTest extends ListenableFutureTest { @Override public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { - if (config == null) { - config = new AsyncHttpClientConfig.Builder().build(); - } - return new AsyncHttpClient(new GrizzlyAsyncHttpProvider(config), config); + return ProviderUtil.grizzlyProvider(config); } } diff --git a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyMaxConnectionsInThreadsTest.java b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyMaxConnectionsInThreadsTest.java index d9a95eace4..c3982b645f 100644 --- a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyMaxConnectionsInThreadsTest.java +++ b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyMaxConnectionsInThreadsTest.java @@ -16,16 +16,13 @@ import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.async.MaxConnectionsInThreads; -import com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProvider; +import com.ning.http.client.async.ProviderUtil; public class GrizzlyMaxConnectionsInThreadsTest extends MaxConnectionsInThreads { @Override public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { - if (config == null) { - config = new AsyncHttpClientConfig.Builder().build(); - } - return new AsyncHttpClient(new GrizzlyAsyncHttpProvider(config), config); + return ProviderUtil.grizzlyProvider(config); } } diff --git a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyMaxTotalConnectionTest.java b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyMaxTotalConnectionTest.java index eeb1c08bf4..7a2829c5ee 100644 --- a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyMaxTotalConnectionTest.java +++ b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyMaxTotalConnectionTest.java @@ -16,15 +16,12 @@ import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.async.MaxTotalConnectionTest; -import com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProvider; +import com.ning.http.client.async.ProviderUtil; public class GrizzlyMaxTotalConnectionTest extends MaxTotalConnectionTest { @Override public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { - if (config == null) { - config = new AsyncHttpClientConfig.Builder().build(); - } - return new AsyncHttpClient(new GrizzlyAsyncHttpProvider(config), config); + return ProviderUtil.grizzlyProvider(config); } } diff --git a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyMultipleHeaderTest.java b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyMultipleHeaderTest.java index 9635878ac9..4b58ba7440 100644 --- a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyMultipleHeaderTest.java +++ b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyMultipleHeaderTest.java @@ -16,16 +16,13 @@ import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.async.MultipleHeaderTest; -import com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProvider; +import com.ning.http.client.async.ProviderUtil; public class GrizzlyMultipleHeaderTest extends MultipleHeaderTest { @Override public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { - if (config == null) { - config = new AsyncHttpClientConfig.Builder().build(); - } - return new AsyncHttpClient(new GrizzlyAsyncHttpProvider(config), config); + return ProviderUtil.grizzlyProvider(config); } } diff --git a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyNoNullResponseTest.java b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyNoNullResponseTest.java index 2c4fac2577..63c10d687d 100644 --- a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyNoNullResponseTest.java +++ b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyNoNullResponseTest.java @@ -16,16 +16,13 @@ import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.async.NoNullResponseTest; -import com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProvider; +import com.ning.http.client.async.ProviderUtil; public class GrizzlyNoNullResponseTest extends NoNullResponseTest { @Override public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { - if (config == null) { - config = new AsyncHttpClientConfig.Builder().build(); - } - return new AsyncHttpClient(new GrizzlyAsyncHttpProvider(config), config); + return ProviderUtil.grizzlyProvider(config); } } diff --git a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyNonAsciiContentLengthTest.java b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyNonAsciiContentLengthTest.java index 9ab8b96c3b..f9342f299e 100644 --- a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyNonAsciiContentLengthTest.java +++ b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyNonAsciiContentLengthTest.java @@ -16,16 +16,13 @@ import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.async.NonAsciiContentLengthTest; -import com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProvider; +import com.ning.http.client.async.ProviderUtil; public class GrizzlyNonAsciiContentLengthTest extends NonAsciiContentLengthTest { @Override public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { - if (config == null) { - config = new AsyncHttpClientConfig.Builder().build(); - } - return new AsyncHttpClient(new GrizzlyAsyncHttpProvider(config), config); + return ProviderUtil.grizzlyProvider(config); } } diff --git a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyParamEncodingTest.java b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyParamEncodingTest.java index 98fe02b2e7..be3a764092 100644 --- a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyParamEncodingTest.java +++ b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyParamEncodingTest.java @@ -16,16 +16,13 @@ import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.async.ParamEncodingTest; -import com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProvider; +import com.ning.http.client.async.ProviderUtil; public class GrizzlyParamEncodingTest extends ParamEncodingTest { @Override public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { - if (config == null) { - config = new AsyncHttpClientConfig.Builder().build(); - } - return new AsyncHttpClient(new GrizzlyAsyncHttpProvider(config), config); + return ProviderUtil.grizzlyProvider(config); } } diff --git a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyPerRequestRelative302Test.java b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyPerRequestRelative302Test.java index e52d331e14..e22cff3d03 100644 --- a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyPerRequestRelative302Test.java +++ b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyPerRequestRelative302Test.java @@ -16,16 +16,13 @@ import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.async.PerRequestRelative302Test; -import com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProvider; +import com.ning.http.client.async.ProviderUtil; public class GrizzlyPerRequestRelative302Test extends PerRequestRelative302Test { @Override public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { - if (config == null) { - config = new AsyncHttpClientConfig.Builder().build(); - } - return new AsyncHttpClient(new GrizzlyAsyncHttpProvider(config), config); + return ProviderUtil.grizzlyProvider(config); } } diff --git a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyPerRequestTimeoutTest.java b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyPerRequestTimeoutTest.java index 0a7a16eb7e..e13d10ac42 100644 --- a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyPerRequestTimeoutTest.java +++ b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyPerRequestTimeoutTest.java @@ -16,7 +16,7 @@ import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.async.PerRequestTimeoutTest; -import com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProvider; +import com.ning.http.client.async.ProviderUtil; public class GrizzlyPerRequestTimeoutTest extends PerRequestTimeoutTest { @@ -27,10 +27,7 @@ protected String getExpectedTimeoutMessage() { @Override public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { - if (config == null) { - config = new AsyncHttpClientConfig.Builder().build(); - } - return new AsyncHttpClient(new GrizzlyAsyncHttpProvider(config), config); + return ProviderUtil.grizzlyProvider(config); } } diff --git a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyPostRedirectGetTest.java b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyPostRedirectGetTest.java index 54a6c78c24..269772a414 100644 --- a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyPostRedirectGetTest.java +++ b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyPostRedirectGetTest.java @@ -16,15 +16,12 @@ import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.async.PostRedirectGetTest; -import com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProvider; +import com.ning.http.client.async.ProviderUtil; public class GrizzlyPostRedirectGetTest extends PostRedirectGetTest { @Override public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { - if (config == null) { - config = new AsyncHttpClientConfig.Builder().build(); - } - return new AsyncHttpClient(new GrizzlyAsyncHttpProvider(config), config); + return ProviderUtil.grizzlyProvider(config); } } diff --git a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyPostWithQSTest.java b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyPostWithQSTest.java index d9dd8b19b9..140f60562c 100644 --- a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyPostWithQSTest.java +++ b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyPostWithQSTest.java @@ -16,16 +16,13 @@ import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.async.PostWithQSTest; -import com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProvider; +import com.ning.http.client.async.ProviderUtil; public class GrizzlyPostWithQSTest extends PostWithQSTest { @Override public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { - if (config == null) { - config = new AsyncHttpClientConfig.Builder().build(); - } - return new AsyncHttpClient(new GrizzlyAsyncHttpProvider(config), config); + return ProviderUtil.grizzlyProvider(config); } } diff --git a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyProxyTest.java b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyProxyTest.java index 1bfbc7f472..63ab5cc82b 100644 --- a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyProxyTest.java +++ b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyProxyTest.java @@ -15,17 +15,14 @@ import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClientConfig; +import com.ning.http.client.async.ProviderUtil; import com.ning.http.client.async.ProxyTest; -import com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProvider; public class GrizzlyProxyTest extends ProxyTest { @Override public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { - if (config == null) { - config = new AsyncHttpClientConfig.Builder().build(); - } - return new AsyncHttpClient(new GrizzlyAsyncHttpProvider(config), config); + return ProviderUtil.grizzlyProvider(config); } } diff --git a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyProxyTunnelingTest.java b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyProxyTunnelingTest.java index 9033261a2c..8f112b2af0 100644 --- a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyProxyTunnelingTest.java +++ b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyProxyTunnelingTest.java @@ -15,17 +15,14 @@ import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClientConfig; +import com.ning.http.client.async.ProviderUtil; import com.ning.http.client.async.ProxyyTunnellingTest; -import com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProvider; public class GrizzlyProxyTunnelingTest extends ProxyyTunnellingTest { @Override public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { - if (config == null) { - config = new AsyncHttpClientConfig.Builder().build(); - } - return new AsyncHttpClient(new GrizzlyAsyncHttpProvider(config), config); + return ProviderUtil.grizzlyProvider(config); } } diff --git a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyPutLargeFileTest.java b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyPutLargeFileTest.java index c26efc51fc..47c8158c40 100644 --- a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyPutLargeFileTest.java +++ b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyPutLargeFileTest.java @@ -15,17 +15,14 @@ import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClientConfig; +import com.ning.http.client.async.ProviderUtil; import com.ning.http.client.async.PutLargeFileTest; -import com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProvider; public class GrizzlyPutLargeFileTest extends PutLargeFileTest { @Override public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { - if (config == null) { - config = new AsyncHttpClientConfig.Builder().build(); - } - return new AsyncHttpClient(new GrizzlyAsyncHttpProvider(config), config); + return ProviderUtil.grizzlyProvider(config); } } diff --git a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyQueryParametersTest.java b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyQueryParametersTest.java index 8ee03ce466..6f46beba13 100644 --- a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyQueryParametersTest.java +++ b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyQueryParametersTest.java @@ -15,17 +15,14 @@ import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClientConfig; +import com.ning.http.client.async.ProviderUtil; import com.ning.http.client.async.QueryParametersTest; -import com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProvider; public class GrizzlyQueryParametersTest extends QueryParametersTest{ @Override public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { - if (config == null) { - config = new AsyncHttpClientConfig.Builder().build(); - } - return new AsyncHttpClient(new GrizzlyAsyncHttpProvider(config), config); + return ProviderUtil.grizzlyProvider(config); } } diff --git a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyRC10KTest.java b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyRC10KTest.java index 837b10c43a..fbd14d7f96 100644 --- a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyRC10KTest.java +++ b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyRC10KTest.java @@ -15,16 +15,13 @@ import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClientConfig; +import com.ning.http.client.async.ProviderUtil; import com.ning.http.client.async.RC10KTest; -import com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProvider; public class GrizzlyRC10KTest extends RC10KTest { @Override public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { - if (config == null) { - config = new AsyncHttpClientConfig.Builder().build(); - } - return new AsyncHttpClient(new GrizzlyAsyncHttpProvider(config), config); + return ProviderUtil.grizzlyProvider(config); } } diff --git a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyRedirectConnectionUsageTest.java b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyRedirectConnectionUsageTest.java index 5397cf5fa1..f70cc2c92c 100644 --- a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyRedirectConnectionUsageTest.java +++ b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyRedirectConnectionUsageTest.java @@ -13,27 +13,25 @@ package com.ning.http.client.async.grizzly; +import static com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProviderConfig.Property.TRANSPORT_CUSTOMIZER; + +import org.glassfish.grizzly.filterchain.FilterChainBuilder; +import org.glassfish.grizzly.nio.transport.TCPNIOTransport; +import org.glassfish.grizzly.strategies.SameThreadIOStrategy; + import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.AsyncHttpProviderConfig; +import com.ning.http.client.async.ProviderUtil; import com.ning.http.client.async.RedirectConnectionUsageTest; -import com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProvider; import com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProviderConfig; import com.ning.http.client.providers.grizzly.TransportCustomizer; -import org.glassfish.grizzly.filterchain.FilterChainBuilder; -import org.glassfish.grizzly.nio.transport.TCPNIOTransport; -import org.glassfish.grizzly.strategies.SameThreadIOStrategy; - -import static com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProviderConfig.Property.TRANSPORT_CUSTOMIZER; public class GrizzlyRedirectConnectionUsageTest extends RedirectConnectionUsageTest { @Override public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { - if (config == null) { - config = new AsyncHttpClientConfig.Builder().build(); - } - return new AsyncHttpClient(new GrizzlyAsyncHttpProvider(config), config); + return ProviderUtil.grizzlyProvider(config); } @Override diff --git a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyRelative302Test.java b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyRelative302Test.java index 684f758353..33d65c5af9 100644 --- a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyRelative302Test.java +++ b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyRelative302Test.java @@ -15,17 +15,14 @@ import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClientConfig; +import com.ning.http.client.async.ProviderUtil; import com.ning.http.client.async.Relative302Test; -import com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProvider; public class GrizzlyRelative302Test extends Relative302Test { @Override public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { - if (config == null) { - config = new AsyncHttpClientConfig.Builder().build(); - } - return new AsyncHttpClient(new GrizzlyAsyncHttpProvider(config), config); + return ProviderUtil.grizzlyProvider(config); } } diff --git a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyRemoteSiteTest.java b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyRemoteSiteTest.java index 23b8b217bb..21b6472715 100644 --- a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyRemoteSiteTest.java +++ b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyRemoteSiteTest.java @@ -15,17 +15,14 @@ import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClientConfig; +import com.ning.http.client.async.ProviderUtil; import com.ning.http.client.async.RemoteSiteTest; -import com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProvider; public class GrizzlyRemoteSiteTest extends RemoteSiteTest { @Override public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { - if (config == null) { - config = new AsyncHttpClientConfig.Builder().build(); - } - return new AsyncHttpClient(new GrizzlyAsyncHttpProvider(config), config); + return ProviderUtil.grizzlyProvider(config); } } diff --git a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyRetryRequestTest.java b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyRetryRequestTest.java index 20b7cca957..d89247f60a 100644 --- a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyRetryRequestTest.java +++ b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyRetryRequestTest.java @@ -15,17 +15,14 @@ import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClientConfig; +import com.ning.http.client.async.ProviderUtil; import com.ning.http.client.async.RetryRequestTest; -import com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProvider; public class GrizzlyRetryRequestTest extends RetryRequestTest { @Override public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { - if (config == null) { - config = new AsyncHttpClientConfig.Builder().build(); - } - return new AsyncHttpClient(new GrizzlyAsyncHttpProvider(config), config); + return ProviderUtil.grizzlyProvider(config); } } diff --git a/src/test/java/com/ning/http/client/async/grizzly/GrizzlySimpleAsyncHttpClientTest.java b/src/test/java/com/ning/http/client/async/grizzly/GrizzlySimpleAsyncHttpClientTest.java index 34709e2d62..ccbcfbd077 100644 --- a/src/test/java/com/ning/http/client/async/grizzly/GrizzlySimpleAsyncHttpClientTest.java +++ b/src/test/java/com/ning/http/client/async/grizzly/GrizzlySimpleAsyncHttpClientTest.java @@ -15,17 +15,14 @@ import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClientConfig; +import com.ning.http.client.async.ProviderUtil; import com.ning.http.client.async.SimpleAsyncHttpClientTest; -import com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProvider; public class GrizzlySimpleAsyncHttpClientTest extends SimpleAsyncHttpClientTest { @Override public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { - if (config == null) { - config = new AsyncHttpClientConfig.Builder().build(); - } - return new AsyncHttpClient(new GrizzlyAsyncHttpProvider(config), config); + return ProviderUtil.grizzlyProvider(config); } } diff --git a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyTransferListenerTest.java b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyTransferListenerTest.java index 90181ac0a5..3be998d25b 100644 --- a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyTransferListenerTest.java +++ b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyTransferListenerTest.java @@ -15,17 +15,14 @@ import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClientConfig; +import com.ning.http.client.async.ProviderUtil; import com.ning.http.client.async.TransferListenerTest; -import com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProvider; public class GrizzlyTransferListenerTest extends TransferListenerTest { @Override public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { - if (config == null) { - config = new AsyncHttpClientConfig.Builder().build(); - } - return new AsyncHttpClient(new GrizzlyAsyncHttpProvider(config), config); + return ProviderUtil.grizzlyProvider(config); } } diff --git a/src/test/java/com/ning/http/client/async/netty/NettyAsyncProviderBasicTest.java b/src/test/java/com/ning/http/client/async/netty/NettyAsyncProviderBasicTest.java index 4292c85f6f..bf713d309c 100644 --- a/src/test/java/com/ning/http/client/async/netty/NettyAsyncProviderBasicTest.java +++ b/src/test/java/com/ning/http/client/async/netty/NettyAsyncProviderBasicTest.java @@ -27,7 +27,7 @@ public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { } @Override - protected AsyncHttpProviderConfig getProviderConfig() { + protected AsyncHttpProviderConfig getProviderConfig() { final NettyAsyncHttpProviderConfig config = new NettyAsyncHttpProviderConfig(); config.addProperty("tcpNoDelay", true); diff --git a/src/test/java/com/ning/http/client/async/netty/NettyBodyDeferringAsyncHandlerTest.java b/src/test/java/com/ning/http/client/async/netty/NettyBodyDeferringAsyncHandlerTest.java index 8e71e559fb..45ad55e296 100644 --- a/src/test/java/com/ning/http/client/async/netty/NettyBodyDeferringAsyncHandlerTest.java +++ b/src/test/java/com/ning/http/client/async/netty/NettyBodyDeferringAsyncHandlerTest.java @@ -17,8 +17,7 @@ import com.ning.http.client.async.BodyDeferringAsyncHandlerTest; import com.ning.http.client.async.ProviderUtil; -public class NettyBodyDeferringAsyncHandlerTest extends - BodyDeferringAsyncHandlerTest { +public class NettyBodyDeferringAsyncHandlerTest extends BodyDeferringAsyncHandlerTest { @Override public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { diff --git a/src/test/java/com/ning/http/client/async/netty/NettyByteBufferCapacityTest.java b/src/test/java/com/ning/http/client/async/netty/NettyByteBufferCapacityTest.java index 0d1d9ef43b..e3c2326412 100644 --- a/src/test/java/com/ning/http/client/async/netty/NettyByteBufferCapacityTest.java +++ b/src/test/java/com/ning/http/client/async/netty/NettyByteBufferCapacityTest.java @@ -14,7 +14,6 @@ import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClientConfig; -import com.ning.http.client.async.AbstractBasicTest; import com.ning.http.client.async.ByteBufferCapacityTest; import com.ning.http.client.async.ProviderUtil; diff --git a/src/test/java/com/ning/http/client/async/netty/NettyProxyTest.java b/src/test/java/com/ning/http/client/async/netty/NettyProxyTest.java index 2a3326320a..6d6babc83a 100644 --- a/src/test/java/com/ning/http/client/async/netty/NettyProxyTest.java +++ b/src/test/java/com/ning/http/client/async/netty/NettyProxyTest.java @@ -22,7 +22,6 @@ public class NettyProxyTest extends ProxyTest { public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { return ProviderUtil.nettyProvider(config); } - } diff --git a/src/test/java/com/ning/http/client/async/netty/NettyRedirectConnectionUsageTest.java b/src/test/java/com/ning/http/client/async/netty/NettyRedirectConnectionUsageTest.java index 201b13e28a..c179b9d63d 100644 --- a/src/test/java/com/ning/http/client/async/netty/NettyRedirectConnectionUsageTest.java +++ b/src/test/java/com/ning/http/client/async/netty/NettyRedirectConnectionUsageTest.java @@ -26,7 +26,7 @@ public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { } @Override - protected AsyncHttpProviderConfig getProviderConfig() { + protected AsyncHttpProviderConfig getProviderConfig() { final NettyAsyncHttpProviderConfig config = new NettyAsyncHttpProviderConfig(); if (System.getProperty("blockingio") != null) { diff --git a/src/test/java/com/ning/http/client/async/netty/NettyZeroCopyFileTest.java b/src/test/java/com/ning/http/client/async/netty/NettyZeroCopyFileTest.java index c1cc524802..0bec536814 100644 --- a/src/test/java/com/ning/http/client/async/netty/NettyZeroCopyFileTest.java +++ b/src/test/java/com/ning/http/client/async/netty/NettyZeroCopyFileTest.java @@ -15,7 +15,6 @@ import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.async.ProviderUtil; -import com.ning.http.client.async.TransferListenerTest; import com.ning.http.client.async.ZeroCopyFileTest; public class NettyZeroCopyFileTest extends ZeroCopyFileTest { diff --git a/src/test/java/com/ning/http/client/generators/ByteArrayBodyGeneratorTest.java b/src/test/java/com/ning/http/client/generators/ByteArrayBodyGeneratorTest.java index a2c3937839..105d750751 100644 --- a/src/test/java/com/ning/http/client/generators/ByteArrayBodyGeneratorTest.java +++ b/src/test/java/com/ning/http/client/generators/ByteArrayBodyGeneratorTest.java @@ -13,16 +13,15 @@ package com.ning.http.client.generators; -import com.ning.http.client.Body; - -import org.testng.annotations.Test; +import static org.testng.Assert.assertEquals; import java.io.IOException; import java.nio.ByteBuffer; import java.util.Random; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertTrue; +import org.testng.annotations.Test; + +import com.ning.http.client.Body; /** * @author Bryan Davis bpd@keynetics.com diff --git a/src/test/java/com/ning/http/client/websocket/ByteMessageTest.java b/src/test/java/com/ning/http/client/websocket/ByteMessageTest.java index 0566cd9ad4..7cfd29b8cb 100644 --- a/src/test/java/com/ning/http/client/websocket/ByteMessageTest.java +++ b/src/test/java/com/ning/http/client/websocket/ByteMessageTest.java @@ -67,183 +67,194 @@ public org.eclipse.jetty.websocket.WebSocket doWebSocketConnect(HttpServletReque @Test public void echoByte() throws Throwable { AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().build()); - final CountDownLatch latch = new CountDownLatch(1); - final AtomicReference text = new AtomicReference(new byte[0]); + try { + final CountDownLatch latch = new CountDownLatch(1); + final AtomicReference text = new AtomicReference(new byte[0]); - WebSocket websocket = c.prepareGet(getTargetUrl()) - .execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(new WebSocketByteListener() { + WebSocket websocket = c.prepareGet(getTargetUrl()).execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(new WebSocketByteListener() { - @Override - public void onOpen(WebSocket websocket) { - } + @Override + public void onOpen(WebSocket websocket) { + } - @Override - public void onClose(WebSocket websocket) { - latch.countDown(); - } + @Override + public void onClose(WebSocket websocket) { + latch.countDown(); + } - @Override - public void onError(Throwable t) { - t.printStackTrace(); - latch.countDown(); - } + @Override + public void onError(Throwable t) { + t.printStackTrace(); + latch.countDown(); + } - @Override - public void onMessage(byte[] message) { - text.set(message); - latch.countDown(); - } + @Override + public void onMessage(byte[] message) { + text.set(message); + latch.countDown(); + } - @Override - public void onFragment(byte[] fragment, boolean last) { - } - }).build()).get(); + @Override + public void onFragment(byte[] fragment, boolean last) { + } + }).build()).get(); - websocket.sendMessage("ECHO".getBytes()); + websocket.sendMessage("ECHO".getBytes()); - latch.await(); - assertEquals(text.get(), "ECHO".getBytes()); + latch.await(); + assertEquals(text.get(), "ECHO".getBytes()); + } finally { + c.close(); + } } @Test public void echoTwoMessagesTest() throws Throwable { AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().build()); - final CountDownLatch latch = new CountDownLatch(2); - final AtomicReference text = new AtomicReference(null); + try { + final CountDownLatch latch = new CountDownLatch(2); + final AtomicReference text = new AtomicReference(null); - WebSocket websocket = c.prepareGet(getTargetUrl()) - .execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(new WebSocketByteListener() { + WebSocket websocket = c.prepareGet(getTargetUrl()).execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(new WebSocketByteListener() { - @Override - public void onOpen(WebSocket websocket) { - } + @Override + public void onOpen(WebSocket websocket) { + } - @Override - public void onClose(WebSocket websocket) { - latch.countDown(); - } + @Override + public void onClose(WebSocket websocket) { + latch.countDown(); + } - @Override - public void onError(Throwable t) { - t.printStackTrace(); - latch.countDown(); - } + @Override + public void onError(Throwable t) { + t.printStackTrace(); + latch.countDown(); + } - @Override - public void onMessage(byte[] message) { - if (text.get() == null) { - text.set(message); - } else { - byte[] n = new byte[text.get().length + message.length]; - System.arraycopy(text.get(), 0, n, 0, text.get().length); - System.arraycopy(message, 0, n, text.get().length, message.length); - text.set(n); - } - latch.countDown(); + @Override + public void onMessage(byte[] message) { + if (text.get() == null) { + text.set(message); + } else { + byte[] n = new byte[text.get().length + message.length]; + System.arraycopy(text.get(), 0, n, 0, text.get().length); + System.arraycopy(message, 0, n, text.get().length, message.length); + text.set(n); } + latch.countDown(); + } - @Override - public void onFragment(byte[] fragment, boolean last) { - } - }).build()).get(); + @Override + public void onFragment(byte[] fragment, boolean last) { + } + }).build()).get(); - websocket.sendMessage("ECHO".getBytes()).sendMessage("ECHO".getBytes()); + websocket.sendMessage("ECHO".getBytes()).sendMessage("ECHO".getBytes()); - latch.await(); - assertEquals(text.get(), "ECHOECHO".getBytes()); + latch.await(); + assertEquals(text.get(), "ECHOECHO".getBytes()); + } finally { + c.close(); + } } @Test public void echoOnOpenMessagesTest() throws Throwable { - AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().build()); + AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().build()); + try { final CountDownLatch latch = new CountDownLatch(2); final AtomicReference text = new AtomicReference(null); - WebSocket websocket = c.prepareGet(getTargetUrl()) - .execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(new WebSocketByteListener() { - - @Override - public void onOpen(WebSocket websocket) { - websocket.sendMessage("ECHO".getBytes()).sendMessage("ECHO".getBytes()); - } - - @Override - public void onClose(WebSocket websocket) { - latch.countDown(); - } - - @Override - public void onError(Throwable t) { - t.printStackTrace(); - latch.countDown(); - } - - @Override - public void onMessage(byte[] message) { - if (text.get() == null) { - text.set(message); - } else { - byte[] n = new byte[text.get().length + message.length]; - System.arraycopy(text.get(), 0, n, 0, text.get().length); - System.arraycopy(message, 0, n, text.get().length, message.length); - text.set(n); - } - latch.countDown(); - } - - @Override - public void onFragment(byte[] fragment, boolean last) { - } - }).build()).get(); + WebSocket websocket = c.prepareGet(getTargetUrl()).execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(new WebSocketByteListener() { + + @Override + public void onOpen(WebSocket websocket) { + websocket.sendMessage("ECHO".getBytes()).sendMessage("ECHO".getBytes()); + } + + @Override + public void onClose(WebSocket websocket) { + latch.countDown(); + } + + @Override + public void onError(Throwable t) { + t.printStackTrace(); + latch.countDown(); + } + + @Override + public void onMessage(byte[] message) { + if (text.get() == null) { + text.set(message); + } else { + byte[] n = new byte[text.get().length + message.length]; + System.arraycopy(text.get(), 0, n, 0, text.get().length); + System.arraycopy(message, 0, n, text.get().length, message.length); + text.set(n); + } + latch.countDown(); + } + + @Override + public void onFragment(byte[] fragment, boolean last) { + } + }).build()).get(); latch.await(); assertEquals(text.get(), "ECHOECHO".getBytes()); + } finally { + c.close(); + } } - public void echoFragments() throws Exception { AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().build()); - final CountDownLatch latch = new CountDownLatch(1); - final AtomicReference text = new AtomicReference(null); - - WebSocket websocket = c.prepareGet(getTargetUrl()) - .execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(new WebSocketByteListener() { - - @Override - public void onOpen(WebSocket websocket) { - } - - @Override - public void onClose(WebSocket websocket) { - latch.countDown(); - } - - @Override - public void onError(Throwable t) { - t.printStackTrace(); - latch.countDown(); - } - - @Override - public void onMessage(byte[] message) { - if (text.get() == null) { - text.set(message); - } else { - byte[] n = new byte[text.get().length + message.length]; - System.arraycopy(text.get(), 0, n, 0, text.get().length); - System.arraycopy(message, 0, n, text.get().length, message.length); - text.set(n); - } - latch.countDown(); - } - - @Override - public void onFragment(byte[] fragment, boolean last) { - } - }).build()).get(); - websocket.stream("ECHO".getBytes(), false); - websocket.stream("ECHO".getBytes(), true); - latch.await(); - assertEquals(text.get(), "ECHOECHO".getBytes()); + try { + final CountDownLatch latch = new CountDownLatch(1); + final AtomicReference text = new AtomicReference(null); + + WebSocket websocket = c.prepareGet(getTargetUrl()).execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(new WebSocketByteListener() { + + @Override + public void onOpen(WebSocket websocket) { + } + + @Override + public void onClose(WebSocket websocket) { + latch.countDown(); + } + + @Override + public void onError(Throwable t) { + t.printStackTrace(); + latch.countDown(); + } + + @Override + public void onMessage(byte[] message) { + if (text.get() == null) { + text.set(message); + } else { + byte[] n = new byte[text.get().length + message.length]; + System.arraycopy(text.get(), 0, n, 0, text.get().length); + System.arraycopy(message, 0, n, text.get().length, message.length); + text.set(n); + } + latch.countDown(); + } + + @Override + public void onFragment(byte[] fragment, boolean last) { + } + }).build()).get(); + websocket.stream("ECHO".getBytes(), false); + websocket.stream("ECHO".getBytes(), true); + latch.await(); + assertEquals(text.get(), "ECHOECHO".getBytes()); + } finally { + c.close(); + } } } diff --git a/src/test/java/com/ning/http/client/websocket/CloseCodeReasonMessageTest.java b/src/test/java/com/ning/http/client/websocket/CloseCodeReasonMessageTest.java index 9329973e03..02ef933ce7 100644 --- a/src/test/java/com/ning/http/client/websocket/CloseCodeReasonMessageTest.java +++ b/src/test/java/com/ning/http/client/websocket/CloseCodeReasonMessageTest.java @@ -36,35 +36,41 @@ public abstract class CloseCodeReasonMessageTest extends TextMessageTest { @Test(timeOut = 60000) public void onCloseWithCode() throws Throwable { AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().build()); - final CountDownLatch latch = new CountDownLatch(1); - final AtomicReference text = new AtomicReference(""); + try { + final CountDownLatch latch = new CountDownLatch(1); + final AtomicReference text = new AtomicReference(""); - WebSocket websocket = c.prepareGet(getTargetUrl()) - .execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(new Listener(latch, text)).build()).get(); + WebSocket websocket = c.prepareGet(getTargetUrl()).execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(new Listener(latch, text)).build()).get(); - websocket.close(); + websocket.close(); - latch.await(); - assertTrue(text.get().startsWith("1000")); + latch.await(); + assertTrue(text.get().startsWith("1000")); + } finally { + c.close(); + } } @Test(timeOut = 60000) public void onCloseWithCodeServerClose() throws Throwable { AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().build()); - final CountDownLatch latch = new CountDownLatch(1); - final AtomicReference text = new AtomicReference(""); - - c.prepareGet(getTargetUrl()) - .execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(new Listener(latch, text)).build()).get(); - - latch.await(); - final String[] parts = text.get().split(" "); - assertEquals(parts.length, 5); - assertEquals(parts[0], "1000-Idle"); - assertEquals(parts[1], "for"); - assertTrue(Integer.parseInt(parts[2].substring(0, parts[2].indexOf('m'))) > 10000); - assertEquals(parts[3], ">"); - assertEquals(parts[4], "10000ms"); + try { + final CountDownLatch latch = new CountDownLatch(1); + final AtomicReference text = new AtomicReference(""); + + c.prepareGet(getTargetUrl()).execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(new Listener(latch, text)).build()).get(); + + latch.await(); + final String[] parts = text.get().split(" "); + assertEquals(parts.length, 5); + assertEquals(parts[0], "1000-Idle"); + assertEquals(parts[1], "for"); + assertTrue(Integer.parseInt(parts[2].substring(0, parts[2].indexOf('m'))) > 10000); + assertEquals(parts[3], ">"); + assertEquals(parts[4], "10000ms"); + } finally { + c.close(); + } } public final static class Listener implements WebSocketListener, WebSocketCloseCodeReasonListener { @@ -77,11 +83,11 @@ public Listener(CountDownLatch latch, AtomicReference text) { this.text = text; } - //@Override + // @Override public void onOpen(com.ning.http.client.websocket.WebSocket websocket) { } - //@Override + // @Override public void onClose(com.ning.http.client.websocket.WebSocket websocket) { } @@ -90,7 +96,7 @@ public void onClose(WebSocket websocket, int code, String reason) { latch.countDown(); } - //@Override + // @Override public void onError(Throwable t) { t.printStackTrace(); latch.countDown(); diff --git a/src/test/java/com/ning/http/client/websocket/RedirectTest.java b/src/test/java/com/ning/http/client/websocket/RedirectTest.java index 25febcf53f..215cfce306 100644 --- a/src/test/java/com/ning/http/client/websocket/RedirectTest.java +++ b/src/test/java/com/ning/http/client/websocket/RedirectTest.java @@ -13,26 +13,25 @@ package com.ning.http.client.websocket; +import static org.testng.Assert.assertEquals; + +import java.io.IOException; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicReference; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; -import com.ning.http.client.AsyncHttpClient; -import com.ning.http.client.AsyncHttpClientConfig; -import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.Request; -import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.handler.AbstractHandler; import org.eclipse.jetty.server.handler.HandlerList; import org.eclipse.jetty.server.nio.SelectChannelConnector; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.atomic.AtomicReference; - -import static org.testng.Assert.assertEquals; +import com.ning.http.client.AsyncHttpClient; +import com.ning.http.client.AsyncHttpClientConfig; public abstract class RedirectTest extends AbstractBasicTest { @@ -50,9 +49,6 @@ public void setUpGlobal() throws Exception { addConnector(_connector); - - - port2 = findFreePort(); final SelectChannelConnector connector2 = new SelectChannelConnector(); connector2.setPort(port2); @@ -60,13 +56,13 @@ public void setUpGlobal() throws Exception { WebSocketHandler _wsHandler = getWebSocketHandler(); HandlerList list = new HandlerList(); list.addHandler(new AbstractHandler() { - @Override - public void handle(String s, Request request, HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws IOException, ServletException { - if (request.getLocalPort() == port2) { - httpServletResponse.sendRedirect(getTargetUrl()); - } - } - }); + @Override + public void handle(String s, Request request, HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws IOException, ServletException { + if (request.getLocalPort() == port2) { + httpServletResponse.sendRedirect(getTargetUrl()); + } + } + }); list.addHandler(_wsHandler); setHandler(list); @@ -89,39 +85,39 @@ public org.eclipse.jetty.websocket.WebSocket doWebSocketConnect(HttpServletReque @Test(timeOut = 60000) public void testRedirectToWSResource() throws Exception { AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setFollowRedirects(true).build()); - final CountDownLatch latch = new CountDownLatch(1); - final AtomicReference text = new AtomicReference(""); - - WebSocket websocket = c.prepareGet(getRedirectURL()) - .execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(new WebSocketListener() { - - @Override - public void onOpen(com.ning.http.client.websocket.WebSocket websocket) { - text.set("OnOpen"); - latch.countDown(); - } - - @Override - public void onClose(com.ning.http.client.websocket.WebSocket websocket) { - } - - @Override - public void onError(Throwable t) { - t.printStackTrace(); - latch.countDown(); - } - }).build()).get(); - - - latch.await(); - assertEquals(text.get(), "OnOpen"); - websocket.close(); + try { + final CountDownLatch latch = new CountDownLatch(1); + final AtomicReference text = new AtomicReference(""); + + WebSocket websocket = c.prepareGet(getRedirectURL()).execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(new WebSocketListener() { + + @Override + public void onOpen(com.ning.http.client.websocket.WebSocket websocket) { + text.set("OnOpen"); + latch.countDown(); + } + + @Override + public void onClose(com.ning.http.client.websocket.WebSocket websocket) { + } + + @Override + public void onError(Throwable t) { + t.printStackTrace(); + latch.countDown(); + } + }).build()).get(); + + latch.await(); + assertEquals(text.get(), "OnOpen"); + websocket.close(); + } finally { + c.close(); + } } - // --------------------------------------------------------- Private Methods - private String getRedirectURL() { return String.format("ws://127.0.0.1:%d/", port2); } diff --git a/src/test/java/com/ning/http/client/websocket/TextMessageTest.java b/src/test/java/com/ning/http/client/websocket/TextMessageTest.java index 2b1b154770..93657e3a09 100644 --- a/src/test/java/com/ning/http/client/websocket/TextMessageTest.java +++ b/src/test/java/com/ning/http/client/websocket/TextMessageTest.java @@ -66,321 +66,339 @@ public org.eclipse.jetty.websocket.WebSocket doWebSocketConnect(HttpServletReque }; } - - @Test(timeOut = 60000) public void onOpen() throws Throwable { AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().build()); - final CountDownLatch latch = new CountDownLatch(1); - final AtomicReference text = new AtomicReference(""); - - WebSocket websocket = c.prepareGet(getTargetUrl()) - .execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(new WebSocketListener() { + try { + final CountDownLatch latch = new CountDownLatch(1); + final AtomicReference text = new AtomicReference(""); - @Override - public void onOpen(com.ning.http.client.websocket.WebSocket websocket) { - text.set("OnOpen"); - latch.countDown(); - } + WebSocket websocket = c.prepareGet(getTargetUrl()).execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(new WebSocketListener() { - @Override - public void onClose(com.ning.http.client.websocket.WebSocket websocket) { - } + @Override + public void onOpen(com.ning.http.client.websocket.WebSocket websocket) { + text.set("OnOpen"); + latch.countDown(); + } - @Override - public void onError(Throwable t) { - t.printStackTrace(); - latch.countDown(); - } - }).build()).get(); + @Override + public void onClose(com.ning.http.client.websocket.WebSocket websocket) { + } + @Override + public void onError(Throwable t) { + t.printStackTrace(); + latch.countDown(); + } + }).build()).get(); - latch.await(); - assertEquals(text.get(), "OnOpen"); + latch.await(); + assertEquals(text.get(), "OnOpen"); + } finally { + c.close(); + } } @Test(timeOut = 60000) public void onEmptyListenerTest() throws Throwable { AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().build()); - - WebSocket websocket = null; try { - websocket = c.prepareGet(getTargetUrl()) - .execute(new WebSocketUpgradeHandler.Builder().build()).get(); - } catch (Throwable t) { - fail(); + WebSocket websocket = null; + try { + websocket = c.prepareGet(getTargetUrl()).execute(new WebSocketUpgradeHandler.Builder().build()).get(); + } catch (Throwable t) { + fail(); + } + assertTrue(websocket != null); + } finally { + c.close(); } - assertTrue(websocket != null); } @Test(timeOut = 60000) public void onFailureTest() throws Throwable { AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().build()); - final AtomicReference text = new AtomicReference(""); - - WebSocket websocket = null; - Throwable t = null; try { - websocket = c.prepareGet("ws://abcdefg") - .execute(new WebSocketUpgradeHandler.Builder().build()).get(); - } catch (Throwable t2) { - t = t2; + Throwable t = null; + try { + c.prepareGet("ws://abcdefg").execute(new WebSocketUpgradeHandler.Builder().build()).get(); + } catch (Throwable t2) { + t = t2; + } + assertTrue(t != null); + } finally { + c.close(); } - assertTrue(t != null); } @Test(timeOut = 60000) public void onTimeoutCloseTest() throws Throwable { AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().build()); - final CountDownLatch latch = new CountDownLatch(1); - final AtomicReference text = new AtomicReference(""); - - WebSocket websocket = c.prepareGet(getTargetUrl()) - .execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(new WebSocketListener() { - - @Override - public void onOpen(com.ning.http.client.websocket.WebSocket websocket) { - } - - @Override - public void onClose(com.ning.http.client.websocket.WebSocket websocket) { - text.set("OnClose"); - latch.countDown(); - } - - @Override - public void onError(Throwable t) { - t.printStackTrace(); - latch.countDown(); - } - }).build()).get(); - - latch.await(); - assertEquals(text.get(), "OnClose"); + try { + final CountDownLatch latch = new CountDownLatch(1); + final AtomicReference text = new AtomicReference(""); + + c.prepareGet(getTargetUrl()).execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(new WebSocketListener() { + + @Override + public void onOpen(com.ning.http.client.websocket.WebSocket websocket) { + } + + @Override + public void onClose(com.ning.http.client.websocket.WebSocket websocket) { + text.set("OnClose"); + latch.countDown(); + } + + @Override + public void onError(Throwable t) { + t.printStackTrace(); + latch.countDown(); + } + }).build()).get(); + + latch.await(); + assertEquals(text.get(), "OnClose"); + } finally { + c.close(); + } } @Test(timeOut = 60000) public void onClose() throws Throwable { AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().build()); - final CountDownLatch latch = new CountDownLatch(1); - final AtomicReference text = new AtomicReference(""); + try { + final CountDownLatch latch = new CountDownLatch(1); + final AtomicReference text = new AtomicReference(""); - WebSocket websocket = c.prepareGet(getTargetUrl()) - .execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(new WebSocketListener() { + WebSocket websocket = c.prepareGet(getTargetUrl()).execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(new WebSocketListener() { - @Override - public void onOpen(com.ning.http.client.websocket.WebSocket websocket) { - } + @Override + public void onOpen(com.ning.http.client.websocket.WebSocket websocket) { + } - @Override - public void onClose(com.ning.http.client.websocket.WebSocket websocket) { - text.set("OnClose"); - latch.countDown(); - } + @Override + public void onClose(com.ning.http.client.websocket.WebSocket websocket) { + text.set("OnClose"); + latch.countDown(); + } - @Override - public void onError(Throwable t) { - t.printStackTrace(); - latch.countDown(); - } - }).build()).get(); + @Override + public void onError(Throwable t) { + t.printStackTrace(); + latch.countDown(); + } + }).build()).get(); - websocket.close(); + websocket.close(); - latch.await(); - assertEquals(text.get(), "OnClose"); + latch.await(); + assertEquals(text.get(), "OnClose"); + } finally { + c.close(); + } } @Test(timeOut = 60000) public void echoText() throws Throwable { AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().build()); - final CountDownLatch latch = new CountDownLatch(1); - final AtomicReference text = new AtomicReference(""); - - WebSocket websocket = c.prepareGet(getTargetUrl()) - .execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(new WebSocketTextListener() { - - @Override - public void onMessage(String message) { - text.set(message); - latch.countDown(); - } - - @Override - public void onFragment(String fragment, boolean last) { - } - - @Override - public void onOpen(com.ning.http.client.websocket.WebSocket websocket) { - } - - @Override - public void onClose(com.ning.http.client.websocket.WebSocket websocket) { - latch.countDown(); - } - - @Override - public void onError(Throwable t) { - t.printStackTrace(); - latch.countDown(); - } - }).build()).get(); - - websocket.sendTextMessage("ECHO"); - - latch.await(); - assertEquals(text.get(), "ECHO"); + try { + final CountDownLatch latch = new CountDownLatch(1); + final AtomicReference text = new AtomicReference(""); + + WebSocket websocket = c.prepareGet(getTargetUrl()).execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(new WebSocketTextListener() { + + @Override + public void onMessage(String message) { + text.set(message); + latch.countDown(); + } + + @Override + public void onFragment(String fragment, boolean last) { + } + + @Override + public void onOpen(com.ning.http.client.websocket.WebSocket websocket) { + } + + @Override + public void onClose(com.ning.http.client.websocket.WebSocket websocket) { + latch.countDown(); + } + + @Override + public void onError(Throwable t) { + t.printStackTrace(); + latch.countDown(); + } + }).build()).get(); + + websocket.sendTextMessage("ECHO"); + + latch.await(); + assertEquals(text.get(), "ECHO"); + } finally { + c.close(); + } } @Test(timeOut = 60000) public void echoDoubleListenerText() throws Throwable { AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().build()); - final CountDownLatch latch = new CountDownLatch(2); - final AtomicReference text = new AtomicReference(""); - - WebSocket websocket = c.prepareGet(getTargetUrl()) - .execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(new WebSocketTextListener() { - - @Override - public void onMessage(String message) { - text.set(message); - latch.countDown(); - } - - @Override - public void onFragment(String fragment, boolean last) { - } - - @Override - public void onOpen(com.ning.http.client.websocket.WebSocket websocket) { - } - - @Override - public void onClose(com.ning.http.client.websocket.WebSocket websocket) { - latch.countDown(); - } - - @Override - public void onError(Throwable t) { - t.printStackTrace(); - latch.countDown(); - } - }).addWebSocketListener(new WebSocketTextListener() { - - @Override - public void onMessage(String message) { - text.set(text.get() + message); - latch.countDown(); - } - - @Override - public void onFragment(String fragment, boolean last) { - } - - @Override - public void onOpen(com.ning.http.client.websocket.WebSocket websocket) { - } - - @Override - public void onClose(com.ning.http.client.websocket.WebSocket websocket) { - latch.countDown(); - } - - @Override - public void onError(Throwable t) { - t.printStackTrace(); - latch.countDown(); - } - }).build()).get(); - - websocket.sendTextMessage("ECHO"); - - latch.await(); - assertEquals(text.get(), "ECHOECHO"); + try { + final CountDownLatch latch = new CountDownLatch(2); + final AtomicReference text = new AtomicReference(""); + + WebSocket websocket = c.prepareGet(getTargetUrl()).execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(new WebSocketTextListener() { + + @Override + public void onMessage(String message) { + text.set(message); + latch.countDown(); + } + + @Override + public void onFragment(String fragment, boolean last) { + } + + @Override + public void onOpen(com.ning.http.client.websocket.WebSocket websocket) { + } + + @Override + public void onClose(com.ning.http.client.websocket.WebSocket websocket) { + latch.countDown(); + } + + @Override + public void onError(Throwable t) { + t.printStackTrace(); + latch.countDown(); + } + }).addWebSocketListener(new WebSocketTextListener() { + + @Override + public void onMessage(String message) { + text.set(text.get() + message); + latch.countDown(); + } + + @Override + public void onFragment(String fragment, boolean last) { + } + + @Override + public void onOpen(com.ning.http.client.websocket.WebSocket websocket) { + } + + @Override + public void onClose(com.ning.http.client.websocket.WebSocket websocket) { + latch.countDown(); + } + + @Override + public void onError(Throwable t) { + t.printStackTrace(); + latch.countDown(); + } + }).build()).get(); + + websocket.sendTextMessage("ECHO"); + + latch.await(); + assertEquals(text.get(), "ECHOECHO"); + } finally { + c.close(); + } } @Test public void echoTwoMessagesTest() throws Throwable { AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().build()); - final CountDownLatch latch = new CountDownLatch(2); - final AtomicReference text = new AtomicReference(""); - - WebSocket websocket = c.prepareGet(getTargetUrl()) - .execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(new WebSocketTextListener() { - - @Override - public void onMessage(String message) { - text.set(text.get() + message); - latch.countDown(); - } - - @Override - public void onFragment(String fragment, boolean last) { - } - - boolean t = false; - - @Override - public void onOpen(com.ning.http.client.websocket.WebSocket websocket) { - websocket.sendTextMessage("ECHO").sendTextMessage("ECHO"); - } - - @Override - public void onClose(com.ning.http.client.websocket.WebSocket websocket) { - latch.countDown(); - } - - @Override - public void onError(Throwable t) { - t.printStackTrace(); - latch.countDown(); - } - }).build()).get(); - - latch.await(); - assertEquals(text.get(), "ECHOECHO"); - } + try { + final CountDownLatch latch = new CountDownLatch(2); + final AtomicReference text = new AtomicReference(""); + + WebSocket websocket = c.prepareGet(getTargetUrl()).execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(new WebSocketTextListener() { + + @Override + public void onMessage(String message) { + text.set(text.get() + message); + latch.countDown(); + } + + @Override + public void onFragment(String fragment, boolean last) { + } + boolean t = false; + + @Override + public void onOpen(com.ning.http.client.websocket.WebSocket websocket) { + websocket.sendTextMessage("ECHO").sendTextMessage("ECHO"); + } + + @Override + public void onClose(com.ning.http.client.websocket.WebSocket websocket) { + latch.countDown(); + } + + @Override + public void onError(Throwable t) { + t.printStackTrace(); + latch.countDown(); + } + }).build()).get(); + + latch.await(); + assertEquals(text.get(), "ECHOECHO"); + } finally { + c.close(); + } + } public void echoFragments() throws Throwable { AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().build()); - final CountDownLatch latch = new CountDownLatch(1); - final AtomicReference text = new AtomicReference(""); - - WebSocket websocket = c.prepareGet(getTargetUrl()) - .execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(new WebSocketTextListener() { - - @Override - public void onMessage(String message) { - text.set(message); - latch.countDown(); - } - - @Override - public void onFragment(String fragment, boolean last) { - } - - @Override - public void onOpen(com.ning.http.client.websocket.WebSocket websocket) { - } - - @Override - public void onClose(com.ning.http.client.websocket.WebSocket websocket) { - latch.countDown(); - } - - @Override - public void onError(Throwable t) { - t.printStackTrace(); - latch.countDown(); - } - }).build()).get(); - - websocket.streamText("ECHO", false); - websocket.streamText("ECHO", true); - - latch.await(); - assertEquals(text.get(), "ECHOECHO"); - } + try { + final CountDownLatch latch = new CountDownLatch(1); + final AtomicReference text = new AtomicReference(""); + + WebSocket websocket = c.prepareGet(getTargetUrl()).execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(new WebSocketTextListener() { + @Override + public void onMessage(String message) { + text.set(message); + latch.countDown(); + } + + @Override + public void onFragment(String fragment, boolean last) { + } + + @Override + public void onOpen(com.ning.http.client.websocket.WebSocket websocket) { + } + + @Override + public void onClose(com.ning.http.client.websocket.WebSocket websocket) { + latch.countDown(); + } + + @Override + public void onError(Throwable t) { + t.printStackTrace(); + latch.countDown(); + } + }).build()).get(); + + websocket.streamText("ECHO", false); + websocket.streamText("ECHO", true); + + latch.await(); + assertEquals(text.get(), "ECHOECHO"); + } finally { + c.close(); + } + } } diff --git a/src/test/java/com/ning/http/client/websocket/grizzly/GrizzlyByteMessageTest.java b/src/test/java/com/ning/http/client/websocket/grizzly/GrizzlyByteMessageTest.java index 5497ba0e6e..37b1429e3e 100644 --- a/src/test/java/com/ning/http/client/websocket/grizzly/GrizzlyByteMessageTest.java +++ b/src/test/java/com/ning/http/client/websocket/grizzly/GrizzlyByteMessageTest.java @@ -12,20 +12,17 @@ */ package com.ning.http.client.websocket.grizzly; +import org.testng.annotations.Test; + import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.async.ProviderUtil; -import com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProvider; import com.ning.http.client.websocket.ByteMessageTest; -import org.testng.annotations.Test; public class GrizzlyByteMessageTest extends ByteMessageTest { @Override public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { - if (config == null) { - config = new AsyncHttpClientConfig.Builder().build(); - } - return new AsyncHttpClient(new GrizzlyAsyncHttpProvider(config), config); + return ProviderUtil.grizzlyProvider(config); } @Test(timeOut = 60000) diff --git a/src/test/java/com/ning/http/client/websocket/grizzly/GrizzlyCloseCodeReasonMsgTest.java b/src/test/java/com/ning/http/client/websocket/grizzly/GrizzlyCloseCodeReasonMsgTest.java index c767e55080..941de2bfbc 100644 --- a/src/test/java/com/ning/http/client/websocket/grizzly/GrizzlyCloseCodeReasonMsgTest.java +++ b/src/test/java/com/ning/http/client/websocket/grizzly/GrizzlyCloseCodeReasonMsgTest.java @@ -13,25 +13,23 @@ package com.ning.http.client.websocket.grizzly; +import org.testng.annotations.Test; + import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClientConfig; -import com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProvider; +import com.ning.http.client.async.ProviderUtil; import com.ning.http.client.websocket.CloseCodeReasonMessageTest; -import org.testng.annotations.Test; public class GrizzlyCloseCodeReasonMsgTest extends CloseCodeReasonMessageTest { @Override public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { - if (config == null) { - config = new AsyncHttpClientConfig.Builder().build(); - } - return new AsyncHttpClient(new GrizzlyAsyncHttpProvider(config), config); + return ProviderUtil.grizzlyProvider(config); } @Override @Test public void onCloseWithCode() throws Throwable { - super.onCloseWithCode(); //To change body of overridden methods use File | Settings | File Templates. + super.onCloseWithCode(); // To change body of overridden methods use File | Settings | File Templates. } } diff --git a/src/test/java/com/ning/http/client/websocket/grizzly/GrizzlyRedirectTest.java b/src/test/java/com/ning/http/client/websocket/grizzly/GrizzlyRedirectTest.java index 2cdda3be98..15cd220c8b 100644 --- a/src/test/java/com/ning/http/client/websocket/grizzly/GrizzlyRedirectTest.java +++ b/src/test/java/com/ning/http/client/websocket/grizzly/GrizzlyRedirectTest.java @@ -15,16 +15,13 @@ import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClientConfig; -import com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProvider; +import com.ning.http.client.async.ProviderUtil; import com.ning.http.client.websocket.RedirectTest; public class GrizzlyRedirectTest extends RedirectTest { @Override public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { - if (config == null) { - config = new AsyncHttpClientConfig.Builder().build(); - } - return new AsyncHttpClient(new GrizzlyAsyncHttpProvider(config), config); + return ProviderUtil.grizzlyProvider(config); } } diff --git a/src/test/java/com/ning/http/client/websocket/grizzly/GrizzlyTextMessageTest.java b/src/test/java/com/ning/http/client/websocket/grizzly/GrizzlyTextMessageTest.java index bef60cb991..7499f39c31 100644 --- a/src/test/java/com/ning/http/client/websocket/grizzly/GrizzlyTextMessageTest.java +++ b/src/test/java/com/ning/http/client/websocket/grizzly/GrizzlyTextMessageTest.java @@ -12,25 +12,22 @@ */ package com.ning.http.client.websocket.grizzly; +import org.testng.annotations.Test; + import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.async.ProviderUtil; -import com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProvider; import com.ning.http.client.websocket.ByteMessageTest; -import org.testng.annotations.Test; public class GrizzlyTextMessageTest extends ByteMessageTest { @Override public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { - if (config == null) { - config = new AsyncHttpClientConfig.Builder().build(); - } - return new AsyncHttpClient(new GrizzlyAsyncHttpProvider(config), config); + return ProviderUtil.grizzlyProvider(config); } @Test(timeOut = 60000) @Override public void echoFragments() throws Exception { - super.echoFragments(); //To change body of overridden methods use File | Settings | File Templates. + super.echoFragments(); // To change body of overridden methods use File | Settings | File Templates. } } From c541ad0a07aee5e71ee95f22eb7f2d8aa9be97a5 Mon Sep 17 00:00:00 2001 From: Bongjae Chang Date: Sat, 9 Mar 2013 23:07:30 +0900 Subject: [PATCH 068/264] Backport #246 --- src/test/java/com/ning/http/client/async/Relative302Test.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/ning/http/client/async/Relative302Test.java b/src/test/java/com/ning/http/client/async/Relative302Test.java index 69b21cbc64..871b6a9ce2 100644 --- a/src/test/java/com/ning/http/client/async/Relative302Test.java +++ b/src/test/java/com/ning/http/client/async/Relative302Test.java @@ -97,7 +97,7 @@ public void redirected302Test() throws Throwable { assertNotNull(response); assertEquals(response.getStatusCode(), 200); - String anyGoogleSubdomain = "http://www.google.[a-z]{1,}:80"; + String anyGoogleSubdomain = "http://www//.google//.[a-z]+(//.[a-z]+)*:80"; String baseUrl = getBaseUrl(response.getUri()); assertTrue(baseUrl.matches(anyGoogleSubdomain), "response does not show redirection to " + anyGoogleSubdomain); From e98bf06e41bb1648a2c0d431359495dd62eee8e1 Mon Sep 17 00:00:00 2001 From: Ryan Lubke Date: Sun, 10 Mar 2013 11:42:48 -0700 Subject: [PATCH 069/264] Port changes for #244 from master to 1.7. --- .../grizzly/GrizzlyResponseFuture.java | 30 ++++- .../GrizzlyUnexpectingTimeoutTest.java | 123 ++++++++++++++++++ 2 files changed, 148 insertions(+), 5 deletions(-) create mode 100644 src/test/java/com/ning/http/client/async/grizzly/GrizzlyUnexpectingTimeoutTest.java diff --git a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponseFuture.java b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponseFuture.java index 239b677206..fc17b39f16 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponseFuture.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponseFuture.java @@ -38,6 +38,7 @@ public class GrizzlyResponseFuture extends AbstractListenableFuture { private final AtomicBoolean done = new AtomicBoolean(false); + private final AtomicBoolean cancelled = new AtomicBoolean(false); private final AsyncHandler handler; private final GrizzlyAsyncHttpProvider provider; private final Request request; @@ -66,17 +67,28 @@ public class GrizzlyResponseFuture extends AbstractListenableFuture { public void done(Callable callable) { - done.compareAndSet(false, true); - super.done(); + if (!done.compareAndSet(false, true) || cancelled.get()) { + return; + } + done(); + } public void abort(Throwable t) { + if (done.get() || !cancelled.compareAndSet(false, true)) { + return; + } + delegate.failure(t); if (handler != null) { - handler.onThrowable(t); + try { + handler.onThrowable(t); + } catch (Throwable ignore) { + } + } closeConnection(); done(); @@ -121,7 +133,15 @@ public boolean getAndSetWriteBody(boolean writeBody) { public boolean cancel(boolean mayInterruptIfRunning) { - handler.onThrowable(new CancellationException()); + if (done.get() || !cancelled.compareAndSet(false, true)) { + return false; + } + if (handler != null) { + try { + handler.onThrowable(new CancellationException()); + } catch (Throwable ignore) { + } + } done(); return delegate.cancel(mayInterruptIfRunning); @@ -182,7 +202,7 @@ void setDelegate(final FutureImpl delegate) { private void closeConnection() { - if (connection != null && !connection.isOpen()) { + if (connection != null && connection.isOpen()) { connection.close().markForRecycle(true); } diff --git a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyUnexpectingTimeoutTest.java b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyUnexpectingTimeoutTest.java new file mode 100644 index 0000000000..9fc1f1d09c --- /dev/null +++ b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyUnexpectingTimeoutTest.java @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2012-2013 Sonatype, Inc. All rights reserved. + * + * This program is licensed to you under the Apache License Version 2.0, + * and you may not use this file except in compliance with the Apache License Version 2.0. + * You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the Apache License Version 2.0 is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under. + */ + +package com.ning.http.client.async.grizzly; + +import com.ning.http.client.AsyncCompletionHandler; +import com.ning.http.client.AsyncHttpClient; +import com.ning.http.client.AsyncHttpClientConfig; +import com.ning.http.client.Response; +import com.ning.http.client.async.AbstractBasicTest; +import com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProvider; +import org.eclipse.jetty.continuation.Continuation; +import org.eclipse.jetty.continuation.ContinuationSupport; +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.handler.AbstractHandler; +import org.testng.annotations.Test; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicInteger; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertNull; +import static org.testng.Assert.fail; + +public class GrizzlyUnexpectingTimeoutTest extends AbstractBasicTest { + + private static final String MSG = "Unauthorized without WWW-Authenticate header"; + + protected String getExpectedTimeoutMessage() { + return "401 response received, but no WWW-Authenticate header was present"; + } + + @Override + public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { + if (config == null) { + config = new AsyncHttpClientConfig.Builder().build(); + } + return new AsyncHttpClient(new GrizzlyAsyncHttpProvider(config), config); + } + + @Override + public AbstractHandler configureHandler() throws Exception { + return new ExpectExceptionHandler(); + } + + private class ExpectExceptionHandler extends AbstractHandler { + public void handle(String target, Request baseRequest, HttpServletRequest request, final HttpServletResponse response) throws IOException, ServletException { + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + final Continuation continuation = ContinuationSupport.getContinuation(request); + continuation.suspend(); + new Thread(new Runnable() { + public void run() { + try { + response.getOutputStream().print(MSG); + response.getOutputStream().flush(); + } catch (IOException e) { + log.error(e.getMessage(), e); + } + } + }).start(); + baseRequest.setHandled(true); + } + } + + @Test(groups = {"standalone", "default_provider"}) + public void unexpectedTimeoutTest() throws IOException { + final AtomicInteger counts = new AtomicInteger(); + final int timeout = 100; + + final AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeoutInMs(timeout).build()); + Future responseFuture = + client.prepareGet(getTargetUrl()).execute(new AsyncCompletionHandler() { + @Override + public Response onCompleted(Response response) throws Exception { + counts.incrementAndGet(); + return response; + } + + @Override + public void onThrowable(Throwable t) { + counts.incrementAndGet(); + super.onThrowable(t); + } + }); + // currently, an exception is expected + // because the grizzly provider would throw IllegalStateException if WWW-Authenticate header doesn't exist with 401 response status. + try { + Response response = responseFuture.get(); + assertNull(response); + } catch (InterruptedException e) { + fail("Interrupted.", e); + } catch (ExecutionException e) { + assertFalse(e.getCause() instanceof TimeoutException); + assertEquals(e.getCause().getMessage(), getExpectedTimeoutMessage()); + } + // wait for timeout again. + try { + Thread.sleep(timeout*2); + } catch (InterruptedException e) { + fail("Interrupted.", e); + } + // the result should be either onCompleted or onThrowable. + assertEquals(1, counts.get(), "result should be one"); + client.close(); + } +} From a7601bb05d647da59eff908e062324c44e87a512 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 11 Mar 2013 12:19:18 +0100 Subject: [PATCH 070/264] Backport fix for #114 --- .../providers/netty/NettyResponseFuture.java | 6 + .../NettyRequestThrottleTimeoutTest.java | 134 ++++++++++++++++++ 2 files changed, 140 insertions(+) create mode 100644 src/test/java/com/ning/http/client/async/netty/NettyRequestThrottleTimeoutTest.java diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyResponseFuture.java b/src/main/java/com/ning/http/client/providers/netty/NettyResponseFuture.java index 631b8c59ef..13a84ba88f 100755 --- a/src/main/java/com/ning/http/client/providers/netty/NettyResponseFuture.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyResponseFuture.java @@ -220,6 +220,12 @@ public V get(long l, TimeUnit tu) throws InterruptedException, TimeoutException, if (expired) { isCancelled.set(true); + try { + channel.getPipeline().getContext(NettyAsyncHttpProvider.class).setAttachment(new NettyAsyncHttpProvider.DiscardEvent()); + channel.close(); + } catch (Throwable t) { + // Ignore + } TimeoutException te = new TimeoutException(String.format("No response received after %s", l)); if (!throwableCalled.getAndSet(true)) { try { diff --git a/src/test/java/com/ning/http/client/async/netty/NettyRequestThrottleTimeoutTest.java b/src/test/java/com/ning/http/client/async/netty/NettyRequestThrottleTimeoutTest.java new file mode 100644 index 0000000000..9608846d46 --- /dev/null +++ b/src/test/java/com/ning/http/client/async/netty/NettyRequestThrottleTimeoutTest.java @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2010-2012 Sonatype, Inc. All rights reserved. + * + * This program is licensed to you under the Apache License Version 2.0, + * and you may not use this file except in compliance with the Apache License Version 2.0. + * You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the Apache License Version 2.0 is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under. + */ +package com.ning.http.client.async.netty; + +import com.ning.http.client.*; +import com.ning.http.client.async.AbstractBasicTest; +import com.ning.http.client.async.ProviderUtil; +import org.eclipse.jetty.continuation.Continuation; +import org.eclipse.jetty.continuation.ContinuationSupport; +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.handler.AbstractHandler; +import org.testng.annotations.Test; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.*; + +import static org.testng.Assert.*; + +public class NettyRequestThrottleTimeoutTest extends AbstractBasicTest { + private static final String MSG = "Enough is enough."; + private static final int SLEEPTIME_MS = 1000; + + @Override + public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { + return ProviderUtil.nettyProvider(config); + } + + @Override + public AbstractHandler configureHandler() throws Exception { + return new SlowHandler(); + } + + private class SlowHandler extends AbstractHandler { + public void handle(String target, Request baseRequest, HttpServletRequest request, final HttpServletResponse response) throws IOException, ServletException { + response.setStatus(HttpServletResponse.SC_OK); + final Continuation continuation = ContinuationSupport.getContinuation(request); + continuation.suspend(); + new Thread(new Runnable() { + public void run() { + try { + Thread.sleep(SLEEPTIME_MS); + response.getOutputStream().print(MSG); + response.getOutputStream().flush(); + continuation.complete(); + } catch (InterruptedException e) { + log.error(e.getMessage(), e); + } catch (IOException e) { + log.error(e.getMessage(), e); + } + } + }).start(); + baseRequest.setHandled(true); + } + } + + @Test(groups = {"standalone", "netty_provider"}) + public void testRequestTimeout() throws IOException { + final Semaphore requestThrottle = new Semaphore(1); + + final AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder() + .setCompressionEnabled(true) + .setAllowPoolingConnection(true) + .setMaximumConnectionsTotal(1).build()); + + final CountDownLatch latch = new CountDownLatch(2); + + final List tooManyConnections = new ArrayList(2); + for(int i=0;i<2;i++) { + new Thread(new Runnable() { + + public void run() { + try { + requestThrottle.acquire(); + PerRequestConfig requestConfig = new PerRequestConfig(); + requestConfig.setRequestTimeoutInMs(SLEEPTIME_MS/2); + Future responseFuture = null; + try { + responseFuture = + client.prepareGet(getTargetUrl()).setPerRequestConfig(requestConfig).execute(new AsyncCompletionHandler() { + + @Override + public Response onCompleted(Response response) throws Exception { + requestThrottle.release(); + return response; + } + + @Override + public void onThrowable(Throwable t) { + requestThrottle.release(); + } + }); + } catch(Exception e) { + tooManyConnections.add(e); + } + + if(responseFuture!=null) + responseFuture.get(); + } catch (Exception e) { + } finally { + latch.countDown(); + } + + } + }).start(); + + + } + + try { + latch.await(30,TimeUnit.SECONDS); + } catch (Exception e) { + fail("failed to wait for requests to complete"); + } + + assertTrue(tooManyConnections.size()==0,"Should not have any connection errors where too many connections have been attempted"); + + client.close(); + } +} \ No newline at end of file From 7009cadfa42ed6acbfb4ac59011091f7110760a3 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 11 Mar 2013 12:21:39 +0100 Subject: [PATCH 071/264] NettyAsyncHttpProvider not following redirect to lower-cased path, backport #127 --- .../http/client/providers/netty/NettyAsyncHttpProvider.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java index f1f101552c..9ec4564da5 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java @@ -2069,7 +2069,7 @@ private boolean redirect(Request request, String location = response.getHeader(HttpHeaders.Names.LOCATION); URI uri = AsyncHttpProviderUtils.getRedirectUri(future.getURI(), location); boolean stripQueryString = config.isRemoveQueryParamOnRedirect(); - if (!uri.toString().equalsIgnoreCase(future.getURI().toString())) { + if (!uri.toString().equals(future.getURI().toString())) { final RequestBuilder nBuilder = stripQueryString ? new RequestBuilder(future.getRequest()).setQueryParameters(null) : new RequestBuilder(future.getRequest()); From 045a06488cdc01dd79d498ad5c25257be4552a20 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 11 Mar 2013 11:57:53 +0100 Subject: [PATCH 072/264] Optimize and clean up NettyFuture.done, backport #141 --- .../providers/netty/NettyResponseFuture.java | 12 +++++-- .../http/client/async/ConnectionPoolTest.java | 2 +- .../grizzly/GrizzlyConnectionPoolTest.java | 36 ------------------- 3 files changed, 11 insertions(+), 39 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyResponseFuture.java b/src/main/java/com/ning/http/client/providers/netty/NettyResponseFuture.java index 13a84ba88f..1a21b6793c 100755 --- a/src/main/java/com/ning/http/client/providers/netty/NettyResponseFuture.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyResponseFuture.java @@ -278,6 +278,9 @@ V getContent() throws ExecutionException { } public final void done(Callable callable) { + + Throwable exception = null; + try { cancelReaper(); @@ -290,16 +293,21 @@ public final void done(Callable callable) { try { callable.call(); } catch (Exception ex) { - throw new RuntimeException(ex); + exception = ex; } } } catch (ExecutionException t) { return; } catch (RuntimeException t) { - exEx.compareAndSet(null, new ExecutionException(t)); + exception = t.getCause() != null ? t.getCause() : t; + } finally { latch.countDown(); } + + if (exception != null) + exEx.compareAndSet(null, new ExecutionException(exception)); + super.done(); } diff --git a/src/test/java/com/ning/http/client/async/ConnectionPoolTest.java b/src/test/java/com/ning/http/client/async/ConnectionPoolTest.java index 1a329be84e..a5bcdf743e 100644 --- a/src/test/java/com/ning/http/client/async/ConnectionPoolTest.java +++ b/src/test/java/com/ning/http/client/async/ConnectionPoolTest.java @@ -303,7 +303,7 @@ public Response onCompleted(Response response) throws Exception { } catch (ExecutionException ex) { assertNotNull(ex); assertNotNull(ex.getCause()); - assertEquals(ex.getCause().getCause().getClass(), IOException.class); + assertEquals(ex.getCause().getClass(), IOException.class); assertEquals(count.get(), 1); } } finally { diff --git a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyConnectionPoolTest.java b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyConnectionPoolTest.java index 4eabd6c653..c810843d6f 100644 --- a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyConnectionPoolTest.java +++ b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyConnectionPoolTest.java @@ -18,15 +18,11 @@ import static org.testng.Assert.assertNull; import static org.testng.Assert.fail; -import java.io.IOException; -import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; import org.glassfish.grizzly.Connection; import org.testng.annotations.Test; -import com.ning.http.client.AsyncCompletionHandler; import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.ConnectionsPool; @@ -178,36 +174,4 @@ public void multipleMaxConnectionOpenTest() throws Throwable { c.close(); } } - - @Override - @Test - public void win7DisconnectTest() throws Throwable { - final AtomicInteger count = new AtomicInteger(0); - - AsyncCompletionHandler handler = new AsyncCompletionHandlerAdapter() { - - @Override - public Response onCompleted(Response response) throws Exception { - - count.incrementAndGet(); - StackTraceElement e = new StackTraceElement("sun.nio.ch.SocketDispatcher", "read0", null, -1); - IOException t = new IOException(); - t.setStackTrace(new StackTraceElement[] { e }); - throw t; - } - }; - - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().build()); - try { - client.prepareGet(getTargetUrl()).execute(handler).get(); - fail("Must have received an exception"); - } catch (ExecutionException ex) { - assertNotNull(ex); - assertNotNull(ex.getCause()); - assertEquals(ex.getCause().getClass(), IOException.class); - assertEquals(count.get(), 1); - } finally { - client.close(); - } - } } From 3d2569b6c76bf45992bba2fd417f0d11b80c0c6a Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 11 Mar 2013 12:27:34 +0100 Subject: [PATCH 073/264] Re-enable PropertiesBasedResumableProcesserTest, backport #53 --- .../client/resumable/PropertiesBasedResumableProcesserTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/ning/http/client/resumable/PropertiesBasedResumableProcesserTest.java b/src/test/java/com/ning/http/client/resumable/PropertiesBasedResumableProcesserTest.java index 41d0d68947..e9969a599b 100644 --- a/src/test/java/com/ning/http/client/resumable/PropertiesBasedResumableProcesserTest.java +++ b/src/test/java/com/ning/http/client/resumable/PropertiesBasedResumableProcesserTest.java @@ -23,7 +23,7 @@ * @author Benjamin Hanzelmann */ public class PropertiesBasedResumableProcesserTest { - @Test (enabled = false) + @Test public void testSaveLoad() throws Exception { PropertiesBasedResumableProcessor p = new PropertiesBasedResumableProcessor(); From 6de510ffff6add5f4773034fcd52000ccec9bf53 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 11 Mar 2013 12:34:40 +0100 Subject: [PATCH 074/264] Minor clean up --- .../client/async/AsyncProvidersBasicTest.java | 4 ++-- .../http/client/async/ConnectionPoolTest.java | 4 ++-- .../client/async/FilePartLargeFileTest.java | 3 +-- .../async/NonAsciiContentLengthTest.java | 3 +-- .../async/PerRequestRelative302Test.java | 9 +++------ .../com/ning/http/client/async/ProxyTest.java | 6 ++---- .../http/client/async/PutLargeFileTest.java | 3 +-- .../http/client/async/RemoteSiteTest.java | 2 +- .../client/websocket/ByteMessageTest.java | 8 ++++---- .../websocket/CloseCodeReasonMessageTest.java | 9 ++------- .../client/websocket/TextMessageTest.java | 19 +++++++++---------- 11 files changed, 28 insertions(+), 42 deletions(-) diff --git a/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java b/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java index 8cff37fa41..d117458f74 100755 --- a/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java +++ b/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java @@ -828,7 +828,7 @@ public void onThrowable(Throwable t) { @Test(groups = { "standalone", "default_provider", "async" }) public void asyncRequestVirtualServerPOSTTest() throws Throwable { - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().build()); + AsyncHttpClient client = getAsyncHttpClient(null); try { FluentCaseInsensitiveStringsMap h = new FluentCaseInsensitiveStringsMap(); h.add("Content-Type", "application/x-www-form-urlencoded"); @@ -1716,7 +1716,7 @@ public void bodyAsByteTest() throws Throwable { @Test(groups = { "default_provider", "async" }) public void mirrorByteTest() throws Throwable { - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().build()); + AsyncHttpClient client = getAsyncHttpClient(null); try { Response r = client.preparePost(getTargetUrl()).setBody("MIRROR").execute().get(); diff --git a/src/test/java/com/ning/http/client/async/ConnectionPoolTest.java b/src/test/java/com/ning/http/client/async/ConnectionPoolTest.java index a5bcdf743e..1a82889ec6 100644 --- a/src/test/java/com/ning/http/client/async/ConnectionPoolTest.java +++ b/src/test/java/com/ning/http/client/async/ConnectionPoolTest.java @@ -282,7 +282,7 @@ public void multipleMaxConnectionOpenTestWithQuery() throws Throwable { public void win7DisconnectTest() throws Throwable { final AtomicInteger count = new AtomicInteger(0); - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().build()); + AsyncHttpClient client = getAsyncHttpClient(null); try { AsyncCompletionHandler handler = new AsyncCompletionHandlerAdapter() { @@ -313,7 +313,7 @@ public Response onCompleted(Response response) throws Exception { @Test(groups = { "standalone", "default_provider" }) public void asyncHandlerOnThrowableTest() throws Throwable { - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().build()); + AsyncHttpClient client = getAsyncHttpClient(null); try { final AtomicInteger count = new AtomicInteger(); final String THIS_IS_NOT_FOR_YOU = "This is not for you"; diff --git a/src/test/java/com/ning/http/client/async/FilePartLargeFileTest.java b/src/test/java/com/ning/http/client/async/FilePartLargeFileTest.java index 0f27acb0a2..49af5aa4c6 100644 --- a/src/test/java/com/ning/http/client/async/FilePartLargeFileTest.java +++ b/src/test/java/com/ning/http/client/async/FilePartLargeFileTest.java @@ -64,8 +64,7 @@ public void testPutLargeTextFile() throws Exception { long repeats = (1024 * 1024 / bytes.length) + 1; largeFile = createTempFile(bytes, (int) repeats); - AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder().build(); - AsyncHttpClient client = getAsyncHttpClient(config); + AsyncHttpClient client = getAsyncHttpClient(null); try { BoundRequestBuilder rb = client.preparePut(getTargetUrl()); diff --git a/src/test/java/com/ning/http/client/async/NonAsciiContentLengthTest.java b/src/test/java/com/ning/http/client/async/NonAsciiContentLengthTest.java index cebeb26e2c..b8401491d5 100644 --- a/src/test/java/com/ning/http/client/async/NonAsciiContentLengthTest.java +++ b/src/test/java/com/ning/http/client/async/NonAsciiContentLengthTest.java @@ -14,7 +14,6 @@ import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClient.BoundRequestBuilder; -import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.Response; import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.Request; @@ -82,7 +81,7 @@ public void testNonAsciiContentLength() throws Exception { } protected void execute(String body) throws IOException, InterruptedException, ExecutionException { - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().build()); + AsyncHttpClient client = getAsyncHttpClient(null); try { BoundRequestBuilder r = client.preparePost(getTargetUrl()).setBody(body).setBodyEncoding("UTF-8"); Future f = r.execute(); diff --git a/src/test/java/com/ning/http/client/async/PerRequestRelative302Test.java b/src/test/java/com/ning/http/client/async/PerRequestRelative302Test.java index e2bc68a31a..a476d9adca 100644 --- a/src/test/java/com/ning/http/client/async/PerRequestRelative302Test.java +++ b/src/test/java/com/ning/http/client/async/PerRequestRelative302Test.java @@ -88,8 +88,7 @@ public void setUpGlobal() throws Exception { @Test(groups = { "online", "default_provider" }) public void redirected302Test() throws Throwable { isSet.getAndSet(false); - AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().build(); - AsyncHttpClient c = getAsyncHttpClient(cg); + AsyncHttpClient c = getAsyncHttpClient(null); try { // once @@ -143,8 +142,7 @@ private static int getPort(URI uri) { @Test(groups = { "standalone", "default_provider" }) public void redirected302InvalidTest() throws Throwable { isSet.getAndSet(false); - AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().build(); - AsyncHttpClient c = getAsyncHttpClient(cg); + AsyncHttpClient c = getAsyncHttpClient(null); // If the test hit a proxy, no ConnectException will be thrown and instead of 404 will be returned. try { @@ -163,8 +161,7 @@ public void redirected302InvalidTest() throws Throwable { public void relativeLocationUrl() throws Throwable { isSet.getAndSet(false); - AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().build(); - AsyncHttpClient c = getAsyncHttpClient(cg); + AsyncHttpClient c = getAsyncHttpClient(null); try { Response response = c.preparePost(getTargetUrl()).setFollowRedirects(true).setHeader("X-redirect", "/foo/test").execute().get(); assertNotNull(response); diff --git a/src/test/java/com/ning/http/client/async/ProxyTest.java b/src/test/java/com/ning/http/client/async/ProxyTest.java index 8a67a6fa7f..f73d84d639 100644 --- a/src/test/java/com/ning/http/client/async/ProxyTest.java +++ b/src/test/java/com/ning/http/client/async/ProxyTest.java @@ -178,8 +178,7 @@ public void testIgnoreProxyPropertiesByDefault() throws IOException, ExecutionEx System.setProperty("http.proxyPort", String.valueOf(port1)); System.setProperty("http.nonProxyHosts", "localhost"); - AsyncHttpClientConfig cfg = new AsyncHttpClientConfig.Builder().build(); - AsyncHttpClient client = getAsyncHttpClient(cfg); + AsyncHttpClient client = getAsyncHttpClient(null); try { String target = "http://127.0.0.1:1234/"; Future f = client.prepareGet(target).execute(); @@ -212,8 +211,7 @@ public void testProxyActivationProperty() throws IOException, ExecutionException System.setProperty("http.nonProxyHosts", "localhost"); System.setProperty("com.ning.http.client.AsyncHttpClientConfig.useProxyProperties", "true"); - AsyncHttpClientConfig cfg = new AsyncHttpClientConfig.Builder().build(); - AsyncHttpClient client = getAsyncHttpClient(cfg); + AsyncHttpClient client = getAsyncHttpClient(null); try { String target = "http://127.0.0.1:1234/"; Future f = client.prepareGet(target).execute(); diff --git a/src/test/java/com/ning/http/client/async/PutLargeFileTest.java b/src/test/java/com/ning/http/client/async/PutLargeFileTest.java index d84ec3234c..a5d8d73651 100644 --- a/src/test/java/com/ning/http/client/async/PutLargeFileTest.java +++ b/src/test/java/com/ning/http/client/async/PutLargeFileTest.java @@ -64,8 +64,7 @@ public void testPutSmallFile() throws Exception { long repeats = (1024 / bytes.length) + 1; largeFile = createTempFile(bytes, (int) repeats); - AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder().build(); - AsyncHttpClient client = getAsyncHttpClient(config); + AsyncHttpClient client = getAsyncHttpClient(null); try { BoundRequestBuilder rb = client.preparePut(getTargetUrl()); diff --git a/src/test/java/com/ning/http/client/async/RemoteSiteTest.java b/src/test/java/com/ning/http/client/async/RemoteSiteTest.java index 3f8d12518f..43f4a498b4 100644 --- a/src/test/java/com/ning/http/client/async/RemoteSiteTest.java +++ b/src/test/java/com/ning/http/client/async/RemoteSiteTest.java @@ -165,7 +165,7 @@ public void invalidStreamTest2() throws Throwable { @Test(groups = { "online", "default_provider" }) public void asyncFullBodyProperlyRead() throws Throwable { - final AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().build()); + final AsyncHttpClient client = getAsyncHttpClient(null); try { Response r = client.prepareGet("http://www.cyberpresse.ca/").execute().get(); diff --git a/src/test/java/com/ning/http/client/websocket/ByteMessageTest.java b/src/test/java/com/ning/http/client/websocket/ByteMessageTest.java index 7cfd29b8cb..1811a3895b 100644 --- a/src/test/java/com/ning/http/client/websocket/ByteMessageTest.java +++ b/src/test/java/com/ning/http/client/websocket/ByteMessageTest.java @@ -66,7 +66,7 @@ public org.eclipse.jetty.websocket.WebSocket doWebSocketConnect(HttpServletReque @Test public void echoByte() throws Throwable { - AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().build()); + AsyncHttpClient c = getAsyncHttpClient(null); try { final CountDownLatch latch = new CountDownLatch(1); final AtomicReference text = new AtomicReference(new byte[0]); @@ -110,7 +110,7 @@ public void onFragment(byte[] fragment, boolean last) { @Test public void echoTwoMessagesTest() throws Throwable { - AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().build()); + AsyncHttpClient c = getAsyncHttpClient(null); try { final CountDownLatch latch = new CountDownLatch(2); final AtomicReference text = new AtomicReference(null); @@ -161,7 +161,7 @@ public void onFragment(byte[] fragment, boolean last) { @Test public void echoOnOpenMessagesTest() throws Throwable { - AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().build()); + AsyncHttpClient c = getAsyncHttpClient(null); try { final CountDownLatch latch = new CountDownLatch(2); final AtomicReference text = new AtomicReference(null); @@ -210,7 +210,7 @@ public void onFragment(byte[] fragment, boolean last) { } public void echoFragments() throws Exception { - AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().build()); + AsyncHttpClient c = getAsyncHttpClient(null); try { final CountDownLatch latch = new CountDownLatch(1); final AtomicReference text = new AtomicReference(null); diff --git a/src/test/java/com/ning/http/client/websocket/CloseCodeReasonMessageTest.java b/src/test/java/com/ning/http/client/websocket/CloseCodeReasonMessageTest.java index 02ef933ce7..d1ff9fa5ce 100644 --- a/src/test/java/com/ning/http/client/websocket/CloseCodeReasonMessageTest.java +++ b/src/test/java/com/ning/http/client/websocket/CloseCodeReasonMessageTest.java @@ -13,16 +13,11 @@ package com.ning.http.client.websocket; import com.ning.http.client.AsyncHttpClient; -import com.ning.http.client.AsyncHttpClientConfig; -import com.ning.http.client.async.ProviderUtil; import com.ning.http.client.websocket.TextMessageTest; import com.ning.http.client.websocket.WebSocket; import com.ning.http.client.websocket.WebSocketCloseCodeReasonListener; import com.ning.http.client.websocket.WebSocketListener; import com.ning.http.client.websocket.WebSocketUpgradeHandler; -import com.ning.http.client.websocket.netty.NettyTextMessageTest; -import org.eclipse.jetty.server.nio.SelectChannelConnector; -import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; import java.util.concurrent.CountDownLatch; @@ -35,7 +30,7 @@ public abstract class CloseCodeReasonMessageTest extends TextMessageTest { @Test(timeOut = 60000) public void onCloseWithCode() throws Throwable { - AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().build()); + AsyncHttpClient c = getAsyncHttpClient(null); try { final CountDownLatch latch = new CountDownLatch(1); final AtomicReference text = new AtomicReference(""); @@ -53,7 +48,7 @@ public void onCloseWithCode() throws Throwable { @Test(timeOut = 60000) public void onCloseWithCodeServerClose() throws Throwable { - AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().build()); + AsyncHttpClient c = getAsyncHttpClient(null); try { final CountDownLatch latch = new CountDownLatch(1); final AtomicReference text = new AtomicReference(""); diff --git a/src/test/java/com/ning/http/client/websocket/TextMessageTest.java b/src/test/java/com/ning/http/client/websocket/TextMessageTest.java index 93657e3a09..219502d387 100644 --- a/src/test/java/com/ning/http/client/websocket/TextMessageTest.java +++ b/src/test/java/com/ning/http/client/websocket/TextMessageTest.java @@ -13,7 +13,6 @@ package com.ning.http.client.websocket; import com.ning.http.client.AsyncHttpClient; -import com.ning.http.client.AsyncHttpClientConfig; import org.testng.annotations.Test; import javax.servlet.http.HttpServletRequest; @@ -68,7 +67,7 @@ public org.eclipse.jetty.websocket.WebSocket doWebSocketConnect(HttpServletReque @Test(timeOut = 60000) public void onOpen() throws Throwable { - AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().build()); + AsyncHttpClient c = getAsyncHttpClient(null); try { final CountDownLatch latch = new CountDownLatch(1); final AtomicReference text = new AtomicReference(""); @@ -101,7 +100,7 @@ public void onError(Throwable t) { @Test(timeOut = 60000) public void onEmptyListenerTest() throws Throwable { - AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().build()); + AsyncHttpClient c = getAsyncHttpClient(null); try { WebSocket websocket = null; try { @@ -117,7 +116,7 @@ public void onEmptyListenerTest() throws Throwable { @Test(timeOut = 60000) public void onFailureTest() throws Throwable { - AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().build()); + AsyncHttpClient c = getAsyncHttpClient(null); try { Throwable t = null; try { @@ -133,7 +132,7 @@ public void onFailureTest() throws Throwable { @Test(timeOut = 60000) public void onTimeoutCloseTest() throws Throwable { - AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().build()); + AsyncHttpClient c = getAsyncHttpClient(null); try { final CountDownLatch latch = new CountDownLatch(1); final AtomicReference text = new AtomicReference(""); @@ -166,7 +165,7 @@ public void onError(Throwable t) { @Test(timeOut = 60000) public void onClose() throws Throwable { - AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().build()); + AsyncHttpClient c = getAsyncHttpClient(null); try { final CountDownLatch latch = new CountDownLatch(1); final AtomicReference text = new AtomicReference(""); @@ -201,7 +200,7 @@ public void onError(Throwable t) { @Test(timeOut = 60000) public void echoText() throws Throwable { - AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().build()); + AsyncHttpClient c = getAsyncHttpClient(null); try { final CountDownLatch latch = new CountDownLatch(1); final AtomicReference text = new AtomicReference(""); @@ -245,7 +244,7 @@ public void onError(Throwable t) { @Test(timeOut = 60000) public void echoDoubleListenerText() throws Throwable { - AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().build()); + AsyncHttpClient c = getAsyncHttpClient(null); try { final CountDownLatch latch = new CountDownLatch(2); final AtomicReference text = new AtomicReference(""); @@ -315,7 +314,7 @@ public void onError(Throwable t) { @Test public void echoTwoMessagesTest() throws Throwable { - AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().build()); + AsyncHttpClient c = getAsyncHttpClient(null); try { final CountDownLatch latch = new CountDownLatch(2); final AtomicReference text = new AtomicReference(""); @@ -359,7 +358,7 @@ public void onError(Throwable t) { } public void echoFragments() throws Throwable { - AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().build()); + AsyncHttpClient c = getAsyncHttpClient(null); try { final CountDownLatch latch = new CountDownLatch(1); final AtomicReference text = new AtomicReference(""); From 888a5c8e4ba2aa8a0505c21fb9288ca512498d17 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 11 Mar 2013 12:39:06 +0100 Subject: [PATCH 075/264] Mention that RequestBuilder is mutable and not threadsafe, close #238 --- src/main/java/com/ning/http/client/RequestBuilder.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/com/ning/http/client/RequestBuilder.java b/src/main/java/com/ning/http/client/RequestBuilder.java index 50aaad585f..7bf55ee1a5 100644 --- a/src/main/java/com/ning/http/client/RequestBuilder.java +++ b/src/main/java/com/ning/http/client/RequestBuilder.java @@ -23,6 +23,8 @@ /** * Builder for a {@link Request}. + * Warning: mutable and not thread-safe! Beware that it holds a reference on the Request instance it builds, + * so modifying the builder will modify the request even after it has been built. */ public class RequestBuilder extends RequestBuilderBase { From ce7b4676ac1f3017407d4a9767fca62c55318c38 Mon Sep 17 00:00:00 2001 From: RickBullotta Date: Sat, 9 Feb 2013 10:16:47 -0500 Subject: [PATCH 076/264] Backport fix for #207 --- .../netty/NettyAsyncHttpProvider.java | 30 ++++++++- .../providers/netty/NettyWebSocket.java | 64 +++++++++++++++++-- 2 files changed, 87 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java index 9ec4564da5..2419c2f843 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java @@ -94,7 +94,9 @@ import org.jboss.netty.handler.codec.http.HttpResponse; import org.jboss.netty.handler.codec.http.HttpResponseDecoder; import org.jboss.netty.handler.codec.http.HttpVersion; +import org.jboss.netty.handler.codec.http.websocketx.BinaryWebSocketFrame; import org.jboss.netty.handler.codec.http.websocketx.CloseWebSocketFrame; +import org.jboss.netty.handler.codec.http.websocketx.TextWebSocketFrame; import org.jboss.netty.handler.codec.http.websocketx.WebSocket08FrameDecoder; import org.jboss.netty.handler.codec.http.websocketx.WebSocket08FrameEncoder; import org.jboss.netty.handler.codec.http.websocketx.WebSocketFrame; @@ -116,6 +118,7 @@ import java.nio.channels.ClosedChannelException; import java.nio.channels.FileChannel; import java.nio.channels.WritableByteChannel; +import java.nio.charset.Charset; import java.security.GeneralSecurityException; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; @@ -145,6 +148,7 @@ public class NettyAsyncHttpProvider extends SimpleChannelUpstreamHandler impleme private static final String WEBSOCKET = "ws"; private static final String WEBSOCKET_SSL = "wss"; private final static Logger log = LoggerFactory.getLogger(NettyAsyncHttpProvider.class); + private final static Charset UTF8 = Charset.forName("UTF-8"); private final ClientBootstrap plainBootstrap; private final ClientBootstrap secureBootstrap; private final ClientBootstrap webSocketBootstrap; @@ -2371,7 +2375,15 @@ public void onClose(ChannelHandlerContext ctx, ChannelStateEvent e) { } private final class WebSocketProtocol implements Protocol { - + private static final byte OPCODE_CONT = 0x0; + private static final byte OPCODE_TEXT = 0x1; + private static final byte OPCODE_BINARY = 0x2; + private static final byte OPCODE_UNKNOWN = -1; + + protected ChannelBuffer byteBuffer = null; + protected StringBuilder textBuffer = null; + protected byte pendingOpcode = OPCODE_UNKNOWN; + // @Override public void handle(ChannelHandlerContext ctx, MessageEvent e) throws Exception { NettyResponseFuture future = NettyResponseFuture.class.cast(ctx.getAttachment()); @@ -2448,6 +2460,13 @@ public void handle(ChannelHandlerContext ctx, MessageEvent e) throws Exception { } else if (e.getMessage() instanceof WebSocketFrame) { final WebSocketFrame frame = (WebSocketFrame) e.getMessage(); + if(frame instanceof TextWebSocketFrame) { + pendingOpcode = OPCODE_TEXT; + } + else if(frame instanceof BinaryWebSocketFrame) { + pendingOpcode = OPCODE_BINARY; + } + HttpChunk webSocketChunk = new HttpChunk() { private ChannelBuffer content; @@ -2473,8 +2492,13 @@ public void setContent(ChannelBuffer content) { h.onBodyPartReceived(rp); NettyWebSocket webSocket = NettyWebSocket.class.cast(h.onCompleted()); - webSocket.onMessage(rp.getBodyPartBytes()); - webSocket.onTextMessage(frame.getBinaryData().toString("UTF-8")); + + if(pendingOpcode == OPCODE_BINARY) { + webSocket.onBinaryFragment(rp.getBodyPartBytes(),frame.isFinalFragment()); + } + else { + webSocket.onTextFragment(frame.getBinaryData().toString(UTF8),frame.isFinalFragment()); + } if (CloseWebSocketFrame.class.isAssignableFrom(frame.getClass())) { try { diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyWebSocket.java b/src/main/java/com/ning/http/client/providers/netty/NettyWebSocket.java index 498e15ba12..3e0f7947e8 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyWebSocket.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyWebSocket.java @@ -27,6 +27,8 @@ import java.util.concurrent.ConcurrentLinkedQueue; +import java.io.ByteArrayOutputStream; + import static org.jboss.netty.buffer.ChannelBuffers.wrappedBuffer; public class NettyWebSocket implements WebSocket { @@ -35,6 +37,10 @@ public class NettyWebSocket implements WebSocket { private final Channel channel; private final ConcurrentLinkedQueue listeners = new ConcurrentLinkedQueue(); + private StringBuilder textBuffer; + private ByteArrayOutputStream byteBuffer; + private int maxBufferSize = 128000000; + public NettyWebSocket(Channel channel) { this.channel = channel; } @@ -90,6 +96,17 @@ public WebSocket removeWebSocketListener(WebSocketListener l) { return this; } + public int getMaxBufferSize() { + return maxBufferSize; + } + + public void setMaxBufferSize(int bufferSize) { + maxBufferSize = bufferSize; + + if(maxBufferSize < 8192) + maxBufferSize = 8192; + } + // @Override public boolean isOpen() { return channel.isOpen(); @@ -102,11 +119,31 @@ public void close() { channel.close(); } - protected void onMessage(byte[] message) { + protected void onBinaryFragment(byte[] message, boolean last) { for (WebSocketListener l : listeners) { if (WebSocketByteListener.class.isAssignableFrom(l.getClass())) { try { - WebSocketByteListener.class.cast(l).onMessage(message); + WebSocketByteListener.class.cast(l).onFragment(message,last); + + if(byteBuffer == null) { + byteBuffer = new ByteArrayOutputStream(); + } + + byteBuffer.write(message); + + if(byteBuffer.size() > maxBufferSize) { + Exception e = new Exception("Exceeded Netty Web Socket maximum buffer size of " + getMaxBufferSize()); + l.onError(e); + this.close(); + return; + } + + + if(last) { + WebSocketByteListener.class.cast(l).onMessage(byteBuffer.toByteArray()); + byteBuffer = null; + textBuffer = null; + } } catch (Exception ex) { l.onError(ex); } @@ -114,11 +151,30 @@ protected void onMessage(byte[] message) { } } - protected void onTextMessage(String message) { + protected void onTextFragment(String message, boolean last) { for (WebSocketListener l : listeners) { if (WebSocketTextListener.class.isAssignableFrom(l.getClass())) { try { - WebSocketTextListener.class.cast(l).onMessage(message); + WebSocketTextListener.class.cast(l).onFragment(message,last); + + if(textBuffer == null) { + textBuffer = new StringBuilder(); + } + + textBuffer.append(message); + + if(textBuffer.length() > maxBufferSize) { + Exception e = new Exception("Exceeded Netty Web Socket maximum buffer size of " + getMaxBufferSize()); + l.onError(e); + this.close(); + return; + } + + if(last) { + WebSocketTextListener.class.cast(l).onMessage(textBuffer.toString()); + byteBuffer = null; + textBuffer = null; + } } catch (Exception ex) { l.onError(ex); } From 6c8c0314a06d87f2b97247310676273f0df8ec76 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 12 Mar 2013 12:25:36 +0100 Subject: [PATCH 077/264] Refactor non proxy hosts handling, fix #202 in 1.7.x --- .../apache/ApacheAsyncHttpProvider.java | 5 +- .../grizzly/GrizzlyAsyncHttpProvider.java | 52 +++---------------- .../grizzly/GrizzlyResponseFuture.java | 11 ++-- .../providers/jdk/JDKAsyncHttpProvider.java | 7 ++- .../netty/NettyAsyncHttpProvider.java | 47 ++++++----------- .../providers/netty/NettyConnectListener.java | 8 ++- .../providers/netty/NettyResponseFuture.java | 10 +++- .../java/com/ning/http/util/ProxyUtils.java | 14 +++++ .../com/ning/http/client/async/ProxyTest.java | 15 ++++++ 9 files changed, 81 insertions(+), 88 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/apache/ApacheAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/apache/ApacheAsyncHttpProvider.java index 062ab4c689..561464d72f 100644 --- a/src/main/java/com/ning/http/client/providers/apache/ApacheAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/apache/ApacheAsyncHttpProvider.java @@ -340,9 +340,8 @@ private HttpMethodBase createMethod(HttpClient client, Request request) throws I throw new IllegalStateException(String.format("Invalid Method", methodName)); } - ProxyServer proxyServer = request.getProxyServer() != null ? request.getProxyServer() : config.getProxyServer(); - boolean avoidProxy = ProxyUtils.avoidProxy(proxyServer, request); - if (!avoidProxy) { + ProxyServer proxyServer = ProxyUtils.getProxyServer(config, request); + if (proxyServer != null) { if (proxyServer.getPrincipal() != null) { Credentials defaultcreds = new UsernamePasswordCredentials(proxyServer.getPrincipal(), proxyServer.getPassword()); diff --git a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java index 1f5ce1b993..83fc8cc63d 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java @@ -200,8 +200,8 @@ public GrizzlyAsyncHttpProvider(final AsyncHttpClientConfig clientConfig) { public ListenableFuture execute(final Request request, final AsyncHandler handler) throws IOException { - final GrizzlyResponseFuture future = - new GrizzlyResponseFuture(this, request, handler); + final ProxyServer proxy = ProxyUtils.getProxyServer(clientConfig, request); + final GrizzlyResponseFuture future = new GrizzlyResponseFuture(this, request, handler, proxy); future.setDelegate(SafeFutureImpl.create()); final CompletionHandler connectHandler = new CompletionHandler() { @Override @@ -816,24 +816,6 @@ public NextAction handleEvent(final FilterChainContext ctx, } -// @Override -// public NextAction handleRead(FilterChainContext ctx) throws IOException { -// Object message = ctx.getMessage(); -// if (HttpPacket.isHttp(message)) { -// final HttpPacket packet = (HttpPacket) message; -// HttpResponsePacket responsePacket; -// if (HttpContent.isContent(packet)) { -// responsePacket = (HttpResponsePacket) ((HttpContent) packet).getHttpHeader(); -// } else { -// responsePacket = (HttpResponsePacket) packet; -// } -// if (HttpStatus.SWITCHING_PROTOCOLS_101.statusMatches(responsePacket.getStatus())) { -// return ctx.getStopAction(); -// } -// } -// return super.handleRead(ctx); -// } - // ----------------------------------------------------- Private Methods @@ -861,9 +843,8 @@ private boolean sendAsGrizzlyRequest(final Request request, builder.header(Header.Host, uri.getHost() + ':' + uri.getPort()); } } - final ProxyServer proxy = getProxyServer(request); - boolean avoidProxy = ProxyUtils.avoidProxy(proxy, request); - final boolean useProxy = !(avoidProxy || proxy == null); + final ProxyServer proxy = ProxyUtils.getProxyServer(config, request); + final boolean useProxy = proxy != null; if (useProxy) { if ((secure || httpCtx.isWSRequest) && !httpCtx.isTunnelEstablished(ctx.getConnection())) { secure = false; @@ -956,18 +937,6 @@ private void convertToUpgradeRequest(final HttpTransactionContext ctx) { ctx.requestUrl = sb.toString(); } - - private ProxyServer getProxyServer(Request request) { - - ProxyServer proxyServer = request.getProxyServer(); - if (proxyServer == null) { - proxyServer = config.getProxyServer(); - } - return proxyServer; - - } - - private void addHeaders(final Request request, final HttpRequestPacket requestPacket) { @@ -2329,8 +2298,7 @@ Connection obtainConnection(final Request request, final GrizzlyResponseFuture requestFuture) throws IOException, ExecutionException, InterruptedException, TimeoutException { - final Connection c = (obtainConnection0(request, - requestFuture)); + final Connection c = obtainConnection0(request, requestFuture); DO_NOT_CACHE.set(c, Boolean.TRUE); return c; @@ -2341,10 +2309,7 @@ void doAsyncConnect(final Request request, final CompletionHandler connectHandler) throws IOException, ExecutionException, InterruptedException { - ProxyServer proxy = getProxyServer(request); - if (ProxyUtils.avoidProxy(proxy, request)) { - proxy = null; - } + ProxyServer proxy = requestFuture.getProxy(); final URI uri = request.getURI(); String host = ((proxy != null) ? proxy.getHost() : uri.getHost()); int port = ((proxy != null) ? proxy.getPort() : uri.getPort()); @@ -2363,10 +2328,7 @@ private Connection obtainConnection0(final Request request, throws IOException, ExecutionException, InterruptedException, TimeoutException { final URI uri = request.getURI(); - ProxyServer proxy = getProxyServer(request); - if (ProxyUtils.avoidProxy(proxy, request)) { - proxy = null; - } + final ProxyServer proxy = requestFuture.getProxy(); String host = ((proxy != null) ? proxy.getHost() : uri.getHost()); int port = ((proxy != null) ? proxy.getPort() : uri.getPort()); int cTimeout = provider.clientConfig.getConnectionTimeoutInMs(); diff --git a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponseFuture.java b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponseFuture.java index fc17b39f16..d4116ad4c0 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponseFuture.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponseFuture.java @@ -14,6 +14,7 @@ package com.ning.http.client.providers.grizzly; import com.ning.http.client.AsyncHandler; +import com.ning.http.client.ProxyServer; import com.ning.http.client.Request; import com.ning.http.client.listenable.AbstractListenableFuture; @@ -42,7 +43,7 @@ public class GrizzlyResponseFuture extends AbstractListenableFuture { private final AsyncHandler handler; private final GrizzlyAsyncHttpProvider provider; private final Request request; - + private final ProxyServer proxy; private Connection connection; FutureImpl delegate; @@ -53,12 +54,13 @@ public class GrizzlyResponseFuture extends AbstractListenableFuture { GrizzlyResponseFuture(final GrizzlyAsyncHttpProvider provider, final Request request, - final AsyncHandler handler) { + final AsyncHandler handler, + final ProxyServer proxy) { this.provider = provider; this.request = request; this.handler = handler; - + this.proxy = proxy; } @@ -208,4 +210,7 @@ private void closeConnection() { } + public ProxyServer getProxy() { + return proxy; + } } diff --git a/src/main/java/com/ning/http/client/providers/jdk/JDKAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/jdk/JDKAsyncHttpProvider.java index 7552246838..c413d13bd7 100644 --- a/src/main/java/com/ning/http/client/providers/jdk/JDKAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/jdk/JDKAsyncHttpProvider.java @@ -131,11 +131,10 @@ public ListenableFuture execute(Request request, AsyncHandler handler, throw new IOException(String.format("Too many connections %s", config.getMaxTotalConnections())); } - ProxyServer proxyServer = request.getProxyServer() != null ? request.getProxyServer() : config.getProxyServer(); + ProxyServer proxyServer = ProxyUtils.getProxyServer(config, request); Realm realm = request.getRealm() != null ? request.getRealm() : config.getRealm(); - boolean avoidProxy = ProxyUtils.avoidProxy(proxyServer, request); Proxy proxy = null; - if (!avoidProxy && (proxyServer != null || realm != null)) { + if (proxyServer != null || realm != null) { try { proxy = configureProxyAndAuth(proxyServer, realm); } catch (AuthenticationException e) { @@ -497,7 +496,7 @@ private void configure(URI uri, HttpURLConnection urlConnection, Request request String ka = config.getAllowPoolingConnection() ? "keep-alive" : "close"; urlConnection.setRequestProperty("Connection", ka); - ProxyServer proxyServer = request.getProxyServer() != null ? request.getProxyServer() : config.getProxyServer(); + ProxyServer proxyServer = ProxyUtils.getProxyServer(config, request); boolean avoidProxy = ProxyUtils.avoidProxy(proxyServer, uri.getHost()); if (!avoidProxy) { urlConnection.setRequestProperty("Proxy-Connection", ka); diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java index 2419c2f843..b13e3377b7 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java @@ -595,26 +595,14 @@ public void operationComplete(ChannelFuture cf) { } - private static boolean isProxyServer(AsyncHttpClientConfig config, Request request) { - ProxyServer proxyServer = request.getProxyServer(); - if (proxyServer == null) { - proxyServer = config.getProxyServer(); - } - if (proxyServer == null) { - return false; - } else { - return !ProxyUtils.avoidProxy(proxyServer, request); - } - } - protected final static HttpRequest buildRequest(AsyncHttpClientConfig config, Request request, URI uri, - boolean allowConnect, ChannelBuffer buffer) throws IOException { + boolean allowConnect, ChannelBuffer buffer, ProxyServer proxyServer) throws IOException { String method = request.getMethod(); - if (allowConnect && (isProxyServer(config, request) && isSecure(uri))) { + if (allowConnect && proxyServer != null && isSecure(uri)) { method = HttpMethod.CONNECT.toString(); } - return construct(config, request, new HttpMethod(method), uri, buffer); + return construct(config, request, new HttpMethod(method), uri, buffer, proxyServer); } private static SpnegoEngine getSpnegoEngine() { @@ -627,7 +615,8 @@ private static HttpRequest construct(AsyncHttpClientConfig config, Request request, HttpMethod m, URI uri, - ChannelBuffer buffer) throws IOException { + ChannelBuffer buffer, + ProxyServer proxyServer) throws IOException { String host = AsyncHttpProviderUtils.getHost(uri); @@ -640,7 +629,7 @@ private static HttpRequest construct(AsyncHttpClientConfig config, nettyRequest = new DefaultHttpRequest(HttpVersion.HTTP_1_0, m, AsyncHttpProviderUtils.getAuthority(uri)); } else { String path = null; - if (isProxyServer(config, request)) + if (proxyServer != null) path = uri.toString(); else if (uri.getRawQuery() != null) path = uri.getRawPath() + "?" + uri.getRawQuery(); @@ -690,7 +679,6 @@ else if (uri.getRawQuery() != null) nettyRequest.addHeader(HttpHeaders.Names.PROXY_AUTHORIZATION, auth.get(0)); } } - ProxyServer proxyServer = request.getProxyServer() != null ? request.getProxyServer() : config.getProxyServer(); Realm realm = request.getRealm() != null ? request.getRealm() : config.getRealm(); if (realm != null && realm.getUsePreemptiveAuth()) { @@ -754,8 +742,7 @@ else if (uri.getRawQuery() != null) nettyRequest.setHeader(HttpHeaders.Names.CONNECTION, "keep-alive"); } - boolean avoidProxy = ProxyUtils.avoidProxy(proxyServer, request); - if (!avoidProxy) { + if (proxyServer != null) { if (!request.getHeaders().containsKey("Proxy-Connection")) { nettyRequest.setHeader("Proxy-Connection", "keep-alive"); } @@ -958,7 +945,9 @@ private ListenableFuture doConnect(final Request request, final AsyncHand throw new IOException("WebSocket method must be a GET"); } - ProxyServer proxyServer = request.getProxyServer() != null ? request.getProxyServer() : config.getProxyServer(); + ProxyServer proxyServer = ProxyUtils.getProxyServer(config, request); + boolean useProxy = proxyServer != null; + URI uri; if (useRawUrl) { uri = request.getRawURI(); @@ -981,17 +970,14 @@ private ListenableFuture doConnect(final Request request, final AsyncHand bufferedBytes = f.getNettyRequest().getContent(); } - boolean avoidProxy = ProxyUtils.avoidProxy(proxyServer, uri.getHost()); - boolean useProxy = !(avoidProxy || proxyServer == null); - boolean useSSl = isSecure(uri) && !useProxy; if (channel != null && channel.isOpen() && channel.isConnected()) { - HttpRequest nettyRequest = buildRequest(config, request, uri, f == null ? false : f.isConnectAllowed(), bufferedBytes); + HttpRequest nettyRequest = buildRequest(config, request, uri, f == null ? false : f.isConnectAllowed(), bufferedBytes, proxyServer); if (f == null) { - f = newFuture(uri, request, asyncHandler, nettyRequest, config, this); + f = newFuture(uri, request, asyncHandler, nettyRequest, config, this, proxyServer); } else { - nettyRequest = buildRequest(config, request, uri, f.isConnectAllowed(), bufferedBytes); + nettyRequest = buildRequest(config, request, uri, f.isConnectAllowed(), bufferedBytes, proxyServer); f.setNettyRequest(nettyRequest); } f.setState(NettyResponseFuture.STATE.POOLED); @@ -1729,10 +1715,11 @@ public static NettyResponseFuture newFuture(URI uri, AsyncHandler asyncHandler, HttpRequest nettyRequest, AsyncHttpClientConfig config, - NettyAsyncHttpProvider provider) { + NettyAsyncHttpProvider provider, + ProxyServer proxyServer) { NettyResponseFuture f = new NettyResponseFuture(uri, request, asyncHandler, nettyRequest, - requestTimeout(config, request.getPerRequestConfig()), config.getIdleConnectionTimeoutInMs(), provider, request.getConnectionPoolKeyStrategy()); + requestTimeout(config, request.getPerRequestConfig()), config.getIdleConnectionTimeoutInMs(), provider, request.getConnectionPoolKeyStrategy(), proxyServer); if (request.getHeaders().getFirstValue("Expect") != null && request.getHeaders().getFirstValue("Expect").equalsIgnoreCase("100-Continue")) { @@ -2145,6 +2132,7 @@ public void handle(final ChannelHandlerContext ctx, final MessageEvent e) throws HttpRequest nettyRequest = future.getNettyRequest(); AsyncHandler handler = future.getAsyncHandler(); Request request = future.getRequest(); + ProxyServer proxyServer = future.getProxyServer(); HttpResponse response = null; try { if (e.getMessage() instanceof HttpResponse) { @@ -2194,7 +2182,6 @@ public void handle(final ChannelHandlerContext ctx, final MessageEvent e) throws } Realm newRealm = null; - ProxyServer proxyServer = request.getProxyServer() != null ? request.getProxyServer() : config.getProxyServer(); final FluentCaseInsensitiveStringsMap headers = request.getHeaders(); final RequestBuilder builder = new RequestBuilder(future.getRequest()); diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyConnectListener.java b/src/main/java/com/ning/http/client/providers/netty/NettyConnectListener.java index 301399c36e..8625643cd7 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyConnectListener.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyConnectListener.java @@ -18,8 +18,11 @@ import com.ning.http.client.AsyncHandler; import com.ning.http.client.AsyncHttpClientConfig; +import com.ning.http.client.ProxyServer; import com.ning.http.client.Request; import com.ning.http.util.AllowAllHostnameVerifier; +import com.ning.http.util.ProxyUtils; + import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFuture; @@ -137,9 +140,10 @@ public Builder(AsyncHttpClientConfig config, Request request, AsyncHandler as } public NettyConnectListener build(final URI uri) throws IOException { - HttpRequest nettyRequest = NettyAsyncHttpProvider.buildRequest(config, request, uri, true, buffer); + ProxyServer proxyServer = ProxyUtils.getProxyServer(config, request); + HttpRequest nettyRequest = NettyAsyncHttpProvider.buildRequest(config, request, uri, true, buffer, proxyServer); if (future == null) { - future = NettyAsyncHttpProvider.newFuture(uri, request, asyncHandler, nettyRequest, config, provider); + future = NettyAsyncHttpProvider.newFuture(uri, request, asyncHandler, nettyRequest, config, provider, proxyServer); } else { future.setNettyRequest(nettyRequest); future.setRequest(request); diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyResponseFuture.java b/src/main/java/com/ning/http/client/providers/netty/NettyResponseFuture.java index 1a21b6793c..560ed65e4f 100755 --- a/src/main/java/com/ning/http/client/providers/netty/NettyResponseFuture.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyResponseFuture.java @@ -17,6 +17,7 @@ import com.ning.http.client.AsyncHandler; import com.ning.http.client.ConnectionPoolKeyStrategy; +import com.ning.http.client.ProxyServer; import com.ning.http.client.Request; import com.ning.http.client.listenable.AbstractListenableFuture; import org.jboss.netty.channel.Channel; @@ -87,6 +88,7 @@ enum STATE { private final AtomicBoolean throwableCalled = new AtomicBoolean(false); private boolean allowConnect = false; private final ConnectionPoolKeyStrategy connectionPoolKeyStrategy; + private final ProxyServer proxyServer; public NettyResponseFuture(URI uri, Request request, @@ -95,7 +97,8 @@ public NettyResponseFuture(URI uri, int responseTimeoutInMs, int idleConnectionTimeoutInMs, NettyAsyncHttpProvider asyncHttpProvider, - ConnectionPoolKeyStrategy connectionPoolKeyStrategy) { + ConnectionPoolKeyStrategy connectionPoolKeyStrategy, + ProxyServer proxyServer) { this.asyncHandler = asyncHandler; this.responseTimeoutInMs = responseTimeoutInMs; @@ -105,6 +108,7 @@ public NettyResponseFuture(URI uri, this.uri = uri; this.asyncHttpProvider = asyncHttpProvider; this.connectionPoolKeyStrategy = connectionPoolKeyStrategy; + this.proxyServer = proxyServer; if (System.getProperty(MAX_RETRY) != null) { maxRetry = Integer.valueOf(System.getProperty(MAX_RETRY)); @@ -127,6 +131,10 @@ public ConnectionPoolKeyStrategy getConnectionPoolKeyStrategy() { return connectionPoolKeyStrategy; } + public ProxyServer getProxyServer() { + return proxyServer; + } + /** * {@inheritDoc} */ diff --git a/src/main/java/com/ning/http/util/ProxyUtils.java b/src/main/java/com/ning/http/util/ProxyUtils.java index ea448b6272..cf03ab78a5 100644 --- a/src/main/java/com/ning/http/util/ProxyUtils.java +++ b/src/main/java/com/ning/http/util/ProxyUtils.java @@ -12,6 +12,7 @@ */ package com.ning.http.util; +import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.ProxyServer; import com.ning.http.client.ProxyServer.Protocol; import com.ning.http.client.Request; @@ -58,6 +59,19 @@ public class ProxyUtils { */ public static final String PROXY_PASSWORD = PROPERTY_PREFIX + "password"; + /** + * @param config the global config + * @param request the request + * @return the proxy server to be used for this request (can be null) + */ + public static ProxyServer getProxyServer(AsyncHttpClientConfig config, Request request) { + ProxyServer proxyServer = request.getProxyServer(); + if (proxyServer == null) { + proxyServer = config.getProxyServer(); + } + return ProxyUtils.avoidProxy(proxyServer, request) ? null : proxyServer; + } + /** * 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 passed in, this method returns true -- since there is NO proxy, we diff --git a/src/test/java/com/ning/http/client/async/ProxyTest.java b/src/test/java/com/ning/http/client/async/ProxyTest.java index f73d84d639..385bee937f 100644 --- a/src/test/java/com/ning/http/client/async/ProxyTest.java +++ b/src/test/java/com/ning/http/client/async/ProxyTest.java @@ -125,6 +125,21 @@ public void testNonProxyHosts() throws IOException, ExecutionException, TimeoutE } } + @Test(groups = { "standalone", "default_provider" }) + public void testNonProxyHostIssue202() throws IOException, ExecutionException, TimeoutException, InterruptedException { + AsyncHttpClient client = getAsyncHttpClient(null); + try { + String target = "http://127.0.0.1/" + port1 + "/"; + Future f = client.prepareGet(target).setProxyServer(new ProxyServer("127.0.0.1", port1 - 1).addNonProxyHost("127.0.0.1")).execute(); + Response resp = f.get(3, TimeUnit.SECONDS); + assertNotNull(resp); + assertEquals(resp.getStatusCode(), HttpServletResponse.SC_OK); + assertEquals(resp.getHeader("target"), "/"); + } finally { + client.close(); + } + } + @Test(groups = { "standalone", "default_provider" }) public void testProxyProperties() throws IOException, ExecutionException, TimeoutException, InterruptedException { Properties originalProps = System.getProperties(); From e85c0d0919d0ee9c2ba382d1edc5b242849a58ba Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 12 Mar 2013 14:53:28 +0100 Subject: [PATCH 078/264] Backport fix for #251 --- .../http/client/providers/netty/NettyAsyncHttpProvider.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java index b13e3377b7..9e94446a4f 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java @@ -629,7 +629,7 @@ private static HttpRequest construct(AsyncHttpClientConfig config, nettyRequest = new DefaultHttpRequest(HttpVersion.HTTP_1_0, m, AsyncHttpProviderUtils.getAuthority(uri)); } else { String path = null; - if (proxyServer != null) + if (proxyServer != null && !isSecure(uri)) path = uri.toString(); else if (uri.getRawQuery() != null) path = uri.getRawPath() + "?" + uri.getRawQuery(); From f92ad10152803483e5d91091e65fefdfff408711 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 12 Mar 2013 15:17:19 +0100 Subject: [PATCH 079/264] minor clean up --- .../http/client/providers/netty/NettyAsyncHttpProvider.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java index 9e94446a4f..05fa8570cb 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java @@ -972,7 +972,7 @@ private ListenableFuture doConnect(final Request request, final AsyncHand boolean useSSl = isSecure(uri) && !useProxy; if (channel != null && channel.isOpen() && channel.isConnected()) { - HttpRequest nettyRequest = buildRequest(config, request, uri, f == null ? false : f.isConnectAllowed(), bufferedBytes, proxyServer); + HttpRequest nettyRequest = buildRequest(config, request, uri, f != null && f.isConnectAllowed(), bufferedBytes, proxyServer); if (f == null) { f = newFuture(uri, request, asyncHandler, nettyRequest, config, this, proxyServer); From 6c5f747bf72e0753a8d436c459b2b58d6b1c5f2d Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 12 Mar 2013 15:20:32 +0100 Subject: [PATCH 080/264] Dead code --- .../http/client/providers/netty/NettyAsyncHttpProvider.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java index 05fa8570cb..6792a226f9 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java @@ -926,10 +926,6 @@ public ListenableFuture execute(Request request, final AsyncHandler as return doConnect(request, asyncHandler, null, true, executeConnectAsync, false); } - private void execute(final Request request, final NettyResponseFuture f, boolean useCache, boolean asyncConnect) throws IOException { - doConnect(request, f.getAsyncHandler(), f, useCache, asyncConnect, false); - } - private void execute(final Request request, final NettyResponseFuture f, boolean useCache, boolean asyncConnect, boolean reclaimCache) throws IOException { doConnect(request, f.getAsyncHandler(), f, useCache, asyncConnect, reclaimCache); } From ea0763c3338313e55fb737fa78733007fe97082f Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 12 Mar 2013 15:41:25 +0100 Subject: [PATCH 081/264] Rollbacking #251 --- .../http/client/providers/netty/NettyAsyncHttpProvider.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java index 6792a226f9..40af166ec0 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java @@ -629,7 +629,7 @@ private static HttpRequest construct(AsyncHttpClientConfig config, nettyRequest = new DefaultHttpRequest(HttpVersion.HTTP_1_0, m, AsyncHttpProviderUtils.getAuthority(uri)); } else { String path = null; - if (proxyServer != null && !isSecure(uri)) + if (proxyServer != null) path = uri.toString(); else if (uri.getRawQuery() != null) path = uri.getRawPath() + "?" + uri.getRawQuery(); From c6f7fd91bdfc769804e703a482cc9d76707e8350 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 14 Mar 2013 09:41:55 +0100 Subject: [PATCH 082/264] Minor clean up --- .../ning/http/client/FluentStringsMap.java | 4 +++- .../ning/http/client/RequestBuilderBase.java | 20 +++++++++---------- .../java/com/ning/http/util/MiscUtil.java | 4 ++++ 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/ning/http/client/FluentStringsMap.java b/src/main/java/com/ning/http/client/FluentStringsMap.java index 5c71428614..0ca87cab48 100644 --- a/src/main/java/com/ning/http/client/FluentStringsMap.java +++ b/src/main/java/com/ning/http/client/FluentStringsMap.java @@ -16,6 +16,8 @@ */ package com.ning.http.client; +import static com.ning.http.util.MiscUtil.isNonEmpty; + import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -61,7 +63,7 @@ public FluentStringsMap(Map> src) { * @return This object */ public FluentStringsMap add(String key, String... values) { - if ((values != null) && (values.length > 0)) { + if (isNonEmpty(values)) { add(key, Arrays.asList(values)); } return this; diff --git a/src/main/java/com/ning/http/client/RequestBuilderBase.java b/src/main/java/com/ning/http/client/RequestBuilderBase.java index d9cb4965c4..fb50cc6687 100644 --- a/src/main/java/com/ning/http/client/RequestBuilderBase.java +++ b/src/main/java/com/ning/http/client/RequestBuilderBase.java @@ -49,11 +49,11 @@ public abstract class RequestBuilderBase> { private static final class RequestImpl implements Request { private String method; - private URI originalUri = null; - private URI uri = null; - private URI rawUri = null; - private InetAddress address = null; - private InetAddress localAddress = null; + private URI originalUri; + private URI uri; + private URI rawUri; + private InetAddress address; + private InetAddress localAddress; private FluentCaseInsensitiveStringsMap headers = new FluentCaseInsensitiveStringsMap(); private Collection cookies = new ArrayList(); private byte[] byteData; @@ -71,9 +71,9 @@ private static final class RequestImpl implements Request { private File file; private Boolean followRedirects; private PerRequestConfig perRequestConfig; - private long rangeOffset = 0; + private long rangeOffset; public String charset; - private boolean useRawUrl = false; + private boolean useRawUrl; private ConnectionPoolKeyStrategy connectionPoolKeyStrategy = DefaultConnectionPoolStrategy.INSTANCE; public RequestImpl(boolean useRawUrl) { @@ -93,9 +93,9 @@ public RequestImpl(Request prototype) { this.streamData = prototype.getStreamData(); this.entityWriter = prototype.getEntityWriter(); this.bodyGenerator = prototype.getBodyGenerator(); - this.params = (prototype.getParams() == null ? null : new FluentStringsMap(prototype.getParams())); - this.queryParams = (prototype.getQueryParams() == null ? null : new FluentStringsMap(prototype.getQueryParams())); - this.parts = (prototype.getParts() == null ? null : new ArrayList(prototype.getParts())); + this.params = prototype.getParams() == null ? null : new FluentStringsMap(prototype.getParams()); + this.queryParams = prototype.getQueryParams() == null ? null : new FluentStringsMap(prototype.getQueryParams()); + this.parts = prototype.getParts() == null ? null : new ArrayList(prototype.getParts()); this.virtualHost = prototype.getVirtualHost(); this.length = prototype.getContentLength(); this.proxyServer = prototype.getProxyServer(); diff --git a/src/main/java/com/ning/http/util/MiscUtil.java b/src/main/java/com/ning/http/util/MiscUtil.java index dea244fd7b..54e472cf9e 100644 --- a/src/main/java/com/ning/http/util/MiscUtil.java +++ b/src/main/java/com/ning/http/util/MiscUtil.java @@ -23,6 +23,10 @@ private MiscUtil() { public static boolean isNonEmpty(String string) { return string != null && string.length() != 0; } + + public static boolean isNonEmpty(Object[] array) { + return array != null && array.length != 0; + } public static boolean isNonEmpty(Collection collection) { return collection != null && !collection.isEmpty(); From b9889aedf87eeae17db1ba39029bdc720b1a6fd2 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 14 Mar 2013 10:41:33 +0100 Subject: [PATCH 083/264] Add getURI method on ProxyServer, close #253 --- .../java/com/ning/http/client/ProxyServer.java | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/ning/http/client/ProxyServer.java b/src/main/java/com/ning/http/client/ProxyServer.java index 79cc5e1eee..5a3023805b 100644 --- a/src/main/java/com/ning/http/client/ProxyServer.java +++ b/src/main/java/com/ning/http/client/ProxyServer.java @@ -16,10 +16,13 @@ */ package com.ning.http.client; +import java.net.URI; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import com.ning.http.util.AsyncHttpProviderUtils; + /** * Represents a proxy server. */ @@ -44,13 +47,14 @@ public String toString() { } } - private String encoding = "UTF-8"; private final List nonProxyHosts = new ArrayList(); private final Protocol protocol; private final String host; private final String principal; private final String password; - private int port; + private final int port; + private final URI uri; + private String encoding = "UTF-8"; private String ntlmDomain = System.getProperty("http.auth.ntlm.domain", ""); public ProxyServer(final Protocol protocol, final String host, final int port, String principal, String password) { @@ -59,6 +63,7 @@ public ProxyServer(final Protocol protocol, final String host, final int port, S this.port = port; this.principal = principal; this.password = password; + uri = AsyncHttpProviderUtils.createUri(toString()); } public ProxyServer(final String host, final int port, String principal, String password) { @@ -97,6 +102,10 @@ public String getPassword() { return password; } + public URI getUri() { + return uri; + } + public ProxyServer setEncoding(String encoding) { this.encoding = encoding; return this; @@ -131,7 +140,7 @@ public String getNtlmDomain() { @Override public String toString() { - return String.format("%s://%s:%d", protocol.toString(), host, port); + return protocol + "://" + host + ":" + port; } } From b6a5cb4ad0bd6a535b2174a3713b224aee3f772c Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 14 Mar 2013 11:08:12 +0100 Subject: [PATCH 084/264] Introduce useRelativeURIsWithSSLProxies, close #236, close #251 --- .../http/client/AsyncHttpClientConfig.java | 31 +++++++++++++++++-- .../grizzly/GrizzlyAsyncHttpProvider.java | 2 ++ .../netty/NettyAsyncHttpProvider.java | 2 +- 3 files changed, 32 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java b/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java index b3fb5bac1c..fde73329fb 100644 --- a/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java @@ -84,6 +84,7 @@ public class AsyncHttpClientConfig { protected HostnameVerifier hostnameVerifier; protected int ioThreadMultiplier; protected boolean strict302Handling; + protected boolean useRelativeURIsWithSSLProxies; protected AsyncHttpClientConfig() { } @@ -117,7 +118,8 @@ private AsyncHttpClientConfig(int maxTotalConnections, boolean removeQueryParamOnRedirect, HostnameVerifier hostnameVerifier, int ioThreadMultiplier, - boolean strict302Handling) { + boolean strict302Handling, + boolean useRelativeURIsWithSSLProxies) { this.maxTotalConnections = maxTotalConnections; this.maxConnectionPerHost = maxConnectionPerHost; @@ -476,6 +478,16 @@ public boolean isStrict302Handling() { return strict302Handling; } + /** + * @returntrue if AHC should use relative URIs instead of absolute ones when talking with a SSL proxy, + * otherwise false. + * + * @since 1.7.12 + */ + public boolean isUseRelativeURIsWithSSLProxies() { + return useRelativeURIsWithSSLProxies; + } + /** * Builder for an {@link AsyncHttpClient} */ @@ -493,6 +505,7 @@ public static class Builder { private String userAgent = System.getProperty(ASYNC_CLIENT + "userAgent", "NING/1.0"); private boolean useProxyProperties = Boolean.getBoolean(ASYNC_CLIENT + "useProxyProperties"); private boolean allowPoolingConnection = true; + private boolean useRelativeURIsWithSSLProxies = Boolean.getBoolean(ASYNC_CLIENT + "useRelativeURIsWithSSLProxies"); private ScheduledExecutorService reaper = Executors.newScheduledThreadPool(Runtime.getRuntime().availableProcessors(), new ThreadFactory() { public Thread newThread(Runnable r) { Thread t = new Thread(r, "AsyncHttpClient-Reaper"); @@ -955,6 +968,19 @@ public Builder setStrict302Handling(final boolean strict302Handling) { this.strict302Handling = strict302Handling; return this; } + + /** + * Configures this AHC instance to use relative URIs instead of absolute ones when talking with a SSL proxy. + * + * @param useRelativeURIsWithSSLProxies + * @return this + * + * @since 1.7.2 + */ + public Builder setUseRelativeURIsWithSSLProxies(boolean useRelativeURIsWithSSLProxies) { + this.useRelativeURIsWithSSLProxies = useRelativeURIsWithSSLProxies; + return this; + } /** * Create a config builder with values taken from the given prototype configuration. @@ -1045,7 +1071,8 @@ public AsyncHttpClientConfig build() { removeQueryParamOnRedirect, hostnameVerifier, ioThreadMultiplier, - strict302Handling); + strict302Handling, + useRelativeURIsWithSSLProxies); } } } diff --git a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java index 83fc8cc63d..2df221a161 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java @@ -851,6 +851,8 @@ private boolean sendAsGrizzlyRequest(final Request request, httpCtx.establishingTunnel = true; builder.method(Method.CONNECT); builder.uri(AsyncHttpProviderUtils.getAuthority(uri)); + } else if (secure && config.isUseRelativeURIsWithSSLProxies()){ + builder.uri(uri.getPath()); } else { builder.uri(uri.toString()); } diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java index 40af166ec0..25cae1f627 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java @@ -629,7 +629,7 @@ private static HttpRequest construct(AsyncHttpClientConfig config, nettyRequest = new DefaultHttpRequest(HttpVersion.HTTP_1_0, m, AsyncHttpProviderUtils.getAuthority(uri)); } else { String path = null; - if (proxyServer != null) + if (proxyServer != null && !isSecure(uri) && !config.isUseRelativeURIsWithSSLProxies()) path = uri.toString(); else if (uri.getRawQuery() != null) path = uri.getRawPath() + "?" + uri.getRawQuery(); From 1b986fdf99d9a7d159a9a034aaab443947af54eb Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 14 Mar 2013 13:34:51 +0100 Subject: [PATCH 085/264] Proper fix for #115 in 1.7.x branch --- .../com/ning/http/client/ProxyServer.java | 2 +- .../grizzly/GrizzlyAsyncHttpProvider.java | 26 ++---- .../providers/jdk/JDKAsyncHttpProvider.java | 10 +-- .../netty/NettyAsyncHttpProvider.java | 88 ++++++++++--------- 4 files changed, 59 insertions(+), 67 deletions(-) diff --git a/src/main/java/com/ning/http/client/ProxyServer.java b/src/main/java/com/ning/http/client/ProxyServer.java index 5a3023805b..784ba97e44 100644 --- a/src/main/java/com/ning/http/client/ProxyServer.java +++ b/src/main/java/com/ning/http/client/ProxyServer.java @@ -102,7 +102,7 @@ public String getPassword() { return password; } - public URI getUri() { + public URI getURI() { return uri; } diff --git a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java index 2df221a161..f75de1c9d0 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java @@ -2283,7 +2283,7 @@ void doAsyncTrackedConnection(final Request request, final GrizzlyResponseFuture requestFuture, final CompletionHandler connectHandler) throws IOException, ExecutionException, InterruptedException { - Connection c = pool.poll(getPoolKey(request)); + Connection c = pool.poll(getPoolKey(request, requestFuture.getProxy())); if (c == null) { if (!connectionMonitor.acquire()) { throw new IOException("Max connections exceeded"); @@ -2331,8 +2331,8 @@ private Connection obtainConnection0(final Request request, final URI uri = request.getURI(); final ProxyServer proxy = requestFuture.getProxy(); - String host = ((proxy != null) ? proxy.getHost() : uri.getHost()); - int port = ((proxy != null) ? proxy.getPort() : uri.getPort()); + String host = (proxy != null) ? proxy.getHost() : uri.getHost(); + int port = (proxy != null) ? proxy.getPort() : uri.getPort(); int cTimeout = provider.clientConfig.getConnectionTimeoutInMs(); FutureImpl future = Futures.createSafeFuture(); CompletionHandler ch = Futures.toCompletionHandler(future, @@ -2348,26 +2348,16 @@ private Connection obtainConnection0(final Request request, } } - private ProxyServer getProxyServer(Request request) { - - ProxyServer proxyServer = request.getProxyServer(); - if (proxyServer == null) { - proxyServer = provider.clientConfig.getProxyServer(); - } - return proxyServer; - - } - boolean returnConnection(final Request request, final Connection c) { + ProxyServer proxyServer = ProxyUtils.getProxyServer(provider.clientConfig, request); final boolean result = (DO_NOT_CACHE.get(c) == null - && pool.offer(getPoolKey(request), c)); + && pool.offer(getPoolKey(request, proxyServer), c)); if (result) { if (provider.resolver != null) { provider.resolver.setTimeoutMillis(c, IdleTimeoutFilter.FOREVER); } } return result; - } @@ -2421,9 +2411,9 @@ public void updated(Connection result) { }; } - private static String getPoolKey(final Request request) { - final ConnectionPoolKeyStrategy keyStrategy = request.getConnectionPoolKeyStrategy(); - return keyStrategy.getKey(request.getURI()); + private static String getPoolKey(Request request, ProxyServer proxyServer) { + URI uri = proxyServer != null? proxyServer.getURI(): request.getURI(); + return request.getConnectionPoolKeyStrategy().getKey(uri); } // ------------------------------------------------------ Nested Classes diff --git a/src/main/java/com/ning/http/client/providers/jdk/JDKAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/jdk/JDKAsyncHttpProvider.java index c413d13bd7..3cb78f4658 100644 --- a/src/main/java/com/ning/http/client/providers/jdk/JDKAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/jdk/JDKAsyncHttpProvider.java @@ -163,11 +163,10 @@ public ListenableFuture execute(Request request, AsyncHandler handler, } private HttpURLConnection createUrlConnection(Request request) throws IOException { - ProxyServer proxyServer = request.getProxyServer() != null ? request.getProxyServer() : config.getProxyServer(); + ProxyServer proxyServer = ProxyUtils.getProxyServer(config, request); Realm realm = request.getRealm() != null ? request.getRealm() : config.getRealm(); - boolean avoidProxy = ProxyUtils.avoidProxy(proxyServer, request); Proxy proxy = null; - if (!avoidProxy && proxyServer != null || realm != null) { + if (proxyServer != null || realm != null) { try { proxy = configureProxyAndAuth(proxyServer, realm); } catch (AuthenticationException e) { @@ -177,10 +176,9 @@ private HttpURLConnection createUrlConnection(Request request) throws IOExceptio HttpURLConnection urlConnection = null; if (proxy == null) { - urlConnection = - (HttpURLConnection) AsyncHttpProviderUtils.createUri(request.getUrl()).toURL().openConnection(Proxy.NO_PROXY); + urlConnection = (HttpURLConnection) request.getURI().toURL().openConnection(Proxy.NO_PROXY); } else { - urlConnection = (HttpURLConnection) AsyncHttpProviderUtils.createUri(request.getUrl()).toURL().openConnection(proxy); + urlConnection = (HttpURLConnection) proxyServer.getURI().toURL().openConnection(proxy); } if (request.getUrl().startsWith("https")) { diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java index 25cae1f627..5f3b16e5d1 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java @@ -201,25 +201,25 @@ public NettyAsyncHttpProvider(AsyncHttpClientConfig config) { socketChannelFactory = new OioClientSocketChannelFactory(config.executorService()); this.allowReleaseSocketChannelFactory = true; } else { - // check if external NioClientSocketChannelFactory is defined + // check if external NioClientSocketChannelFactory is defined Object oo = asyncHttpProviderConfig.getProperty(NettyAsyncHttpProviderConfig.SOCKET_CHANNEL_FACTORY); if (oo != null && NioClientSocketChannelFactory.class.isAssignableFrom(oo.getClass())) { - this.socketChannelFactory = NioClientSocketChannelFactory.class.cast(oo); + this.socketChannelFactory = NioClientSocketChannelFactory.class.cast(oo); - // cannot allow releasing shared channel factory - this.allowReleaseSocketChannelFactory = false; + // cannot allow releasing shared channel factory + this.allowReleaseSocketChannelFactory = false; } else { - ExecutorService e; - Object o = asyncHttpProviderConfig.getProperty(NettyAsyncHttpProviderConfig.BOSS_EXECUTOR_SERVICE); - if (o != null && ExecutorService.class.isAssignableFrom(o.getClass())) { - e = ExecutorService.class.cast(o); - } else { - e = Executors.newCachedThreadPool(); - } - int numWorkers = config.getIoThreadMultiplier() * Runtime.getRuntime().availableProcessors(); - log.debug("Number of application's worker threads is {}", numWorkers); - socketChannelFactory = new NioClientSocketChannelFactory(e, config.executorService(), numWorkers); - this.allowReleaseSocketChannelFactory = true; + ExecutorService e; + Object o = asyncHttpProviderConfig.getProperty(NettyAsyncHttpProviderConfig.BOSS_EXECUTOR_SERVICE); + if (o != null && ExecutorService.class.isAssignableFrom(o.getClass())) { + e = ExecutorService.class.cast(o); + } else { + e = Executors.newCachedThreadPool(); + } + int numWorkers = config.getIoThreadMultiplier() * Runtime.getRuntime().availableProcessors(); + log.debug("Number of application's worker threads is {}", numWorkers); + socketChannelFactory = new NioClientSocketChannelFactory(e, config.executorService(), numWorkers); + this.allowReleaseSocketChannelFactory = true; } } plainBootstrap = new ClientBootstrap(socketChannelFactory); @@ -629,7 +629,7 @@ private static HttpRequest construct(AsyncHttpClientConfig config, nettyRequest = new DefaultHttpRequest(HttpVersion.HTTP_1_0, m, AsyncHttpProviderUtils.getAuthority(uri)); } else { String path = null; - if (proxyServer != null && !isSecure(uri) && !config.isUseRelativeURIsWithSSLProxies()) + if (proxyServer != null && !(isSecure(uri) && config.isUseRelativeURIsWithSSLProxies())) path = uri.toString(); else if (uri.getRawQuery() != null) path = uri.getRawPath() + "?" + uri.getRawQuery(); @@ -901,11 +901,11 @@ public void close() { config.executorService().shutdown(); config.reaper().shutdown(); if (this.allowReleaseSocketChannelFactory) { - socketChannelFactory.releaseExternalResources(); - plainBootstrap.releaseExternalResources(); - secureBootstrap.releaseExternalResources(); - webSocketBootstrap.releaseExternalResources(); - secureWebSocketBootstrap.releaseExternalResources(); + socketChannelFactory.releaseExternalResources(); + plainBootstrap.releaseExternalResources(); + secureBootstrap.releaseExternalResources(); + webSocketBootstrap.releaseExternalResources(); + secureWebSocketBootstrap.releaseExternalResources(); } } catch (Throwable t) { log.warn("Unexpected error on close", t); @@ -956,7 +956,8 @@ private ListenableFuture doConnect(final Request request, final AsyncHand if (f != null && f.reuseChannel() && f.channel() != null) { channel = f.channel(); } else { - channel = lookupInCache(uri, request.getConnectionPoolKeyStrategy()); + URI connectionKeyUri = useProxy? proxyServer.getURI() : uri; + channel = lookupInCache(connectionKeyUri, request.getConnectionPoolKeyStrategy()); } } @@ -1306,18 +1307,24 @@ private Realm ntlmProxyChallenge(List wwwAuth, } else { realmBuilder = new Realm.RealmBuilder(); } - newRealm = realmBuilder//.setScheme(realm.getAuthScheme()) + newRealm = realmBuilder .setUri(request.getURI().getPath()) .setMethodName(request.getMethod()) .build(); return newRealm; } + + private String getPoolKey(NettyResponseFuture future) throws MalformedURLException { + URI uri = future.getProxyServer() != null ? future.getProxyServer().getURI() : future.getURI(); + return future.getConnectionPoolKeyStrategy().getKey(uri); + } - private void drainChannel(final ChannelHandlerContext ctx, final NettyResponseFuture future, final boolean keepAlive, final URI uri) { + private void drainChannel(final ChannelHandlerContext ctx, final NettyResponseFuture future) { ctx.setAttachment(new AsyncCallable(future) { public Object call() throws Exception { - if (keepAlive && ctx.getChannel().isReadable() && connectionsPool.offer(future.getConnectionPoolKeyStrategy().getKey(uri), ctx.getChannel())) { + + if (future.getKeepAlive() && ctx.getChannel().isReadable() && connectionsPool.offer(getPoolKey(future), ctx.getChannel())) { return null; } @@ -1353,7 +1360,7 @@ private void replayRequest(final NettyResponseFuture future, FilterContext fc future.touch(); log.debug("\n\nReplaying Request {}\n for Future {}\n", newRequest, future); - drainChannel(ctx, future, future.getKeepAlive(), future.getURI()); + drainChannel(ctx, future); nextRequest(newRequest, future); return; } @@ -1510,10 +1517,9 @@ private void markAsDone(final NettyResponseFuture future, final ChannelHandle private void finishUpdate(final NettyResponseFuture future, final ChannelHandlerContext ctx, boolean lastValidChunk) throws IOException { if (lastValidChunk && future.getKeepAlive()) { - drainChannel(ctx, future, future.getKeepAlive(), future.getURI()); + drainChannel(ctx, future); } else { - if (future.getKeepAlive() && ctx.getChannel().isReadable() && - connectionsPool.offer(future.getConnectionPoolKeyStrategy().getKey(future.getURI()), ctx.getChannel())) { + if (future.getKeepAlive() && ctx.getChannel().isReadable() && connectionsPool.offer(getPoolKey(future), ctx.getChannel())) { markAsDone(future, ctx); return; } @@ -2066,8 +2072,8 @@ private boolean redirect(Request request, && config.isStrict302Handling())) { nBuilder.setMethod("GET"); } - final URI initialConnectionUri = future.getURI(); final boolean initialConnectionKeepAlive = future.getKeepAlive(); + final String initialPoolKey = getPoolKey(future); future.setURI(uri); String newUrl = uri.toString(); if (request.getUrl().startsWith(WEBSOCKET)) { @@ -2085,11 +2091,9 @@ private boolean redirect(Request request, nBuilder.addOrReplaceCookie(c); } - final String connectionPoolKey = future.getConnectionPoolKeyStrategy().getKey(initialConnectionUri); AsyncCallable ac = new AsyncCallable(future) { public Object call() throws Exception { - if (initialConnectionKeepAlive && ctx.getChannel().isReadable() && - connectionsPool.offer(connectionPoolKey, ctx.getChannel())) { + if (initialConnectionKeepAlive && ctx.getChannel().isReadable() && connectionsPool.offer(initialPoolKey, ctx.getChannel())) { return null; } finishChannel(ctx); @@ -2186,7 +2190,7 @@ public void handle(final ChannelHandlerContext ctx, final MessageEvent e) throws //} if (statusCode == 401 - && realm != null + && realm != null && wwwAuth.size() > 0 && !future.getAndSetAuth(true)) { @@ -2220,7 +2224,7 @@ public void handle(final ChannelHandlerContext ctx, final MessageEvent e) throws log.debug("Sending authentication to {}", request.getUrl()); AsyncCallable ac = new AsyncCallable(future) { public Object call() throws Exception { - drainChannel(ctx, future, future.getKeepAlive(), future.getURI()); + drainChannel(ctx, future); nextRequest(builder.setHeaders(headers).setRealm(nr).build(), future); return null; } @@ -2244,7 +2248,7 @@ public Object call() throws Exception { List proxyAuth = getAuthorizationToken(response.getHeaders(), HttpHeaders.Names.PROXY_AUTHENTICATE); if (statusCode == 407 - && realm != null + && realm != null && proxyAuth.size() > 0 && !future.getAndSetAuth(true)) { @@ -2310,7 +2314,7 @@ public Object call() throws Exception { if (nettyRequest.getMethod().equals(HttpMethod.HEAD)) { updateBodyAndInterrupt(future, handler, new ResponseBodyPart(future.getURI(), response, NettyAsyncHttpProvider.this, true)); markAsDone(future, ctx); - drainChannel(ctx, future, future.getKeepAlive(), future.getURI()); + drainChannel(ctx, future); } } else if (e.getMessage() instanceof HttpChunk) { @@ -2363,9 +2367,9 @@ private final class WebSocketProtocol implements Protocol { private static final byte OPCODE_BINARY = 0x2; private static final byte OPCODE_UNKNOWN = -1; - protected ChannelBuffer byteBuffer = null; - protected StringBuilder textBuffer = null; - protected byte pendingOpcode = OPCODE_UNKNOWN; + protected ChannelBuffer byteBuffer = null; + protected StringBuilder textBuffer = null; + protected byte pendingOpcode = OPCODE_UNKNOWN; // @Override public void handle(ChannelHandlerContext ctx, MessageEvent e) throws Exception { @@ -2444,10 +2448,10 @@ public void handle(ChannelHandlerContext ctx, MessageEvent e) throws Exception { final WebSocketFrame frame = (WebSocketFrame) e.getMessage(); if(frame instanceof TextWebSocketFrame) { - pendingOpcode = OPCODE_TEXT; + pendingOpcode = OPCODE_TEXT; } else if(frame instanceof BinaryWebSocketFrame) { - pendingOpcode = OPCODE_BINARY; + pendingOpcode = OPCODE_BINARY; } HttpChunk webSocketChunk = new HttpChunk() { From b583ca55bd16108b9d56a2e74938c73705697dcb Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 14 Mar 2013 15:56:03 +0100 Subject: [PATCH 086/264] Backport partial fix for #254 --- .../providers/jdk/JDKAsyncHttpProvider.java | 2 +- .../netty/NettyAsyncHttpProvider.java | 4 +-- .../http/util/AsyncHttpProviderUtils.java | 29 +++++++++++-------- 3 files changed, 20 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/jdk/JDKAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/jdk/JDKAsyncHttpProvider.java index 3cb78f4658..7a315facec 100644 --- a/src/main/java/com/ning/http/client/providers/jdk/JDKAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/jdk/JDKAsyncHttpProvider.java @@ -492,7 +492,7 @@ private void configure(URI uri, HttpURLConnection urlConnection, Request request } } - String ka = config.getAllowPoolingConnection() ? "keep-alive" : "close"; + String ka = AsyncHttpProviderUtils.keepAliveHeaderValue(config); urlConnection.setRequestProperty("Connection", ka); ProxyServer proxyServer = ProxyUtils.getProxyServer(config, request); boolean avoidProxy = ProxyUtils.avoidProxy(proxyServer, uri.getHost()); diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java index 5f3b16e5d1..ab1dd7c13e 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java @@ -739,12 +739,12 @@ else if (uri.getRawQuery() != null) } if (!webSocket && !request.getHeaders().containsKey(HttpHeaders.Names.CONNECTION)) { - nettyRequest.setHeader(HttpHeaders.Names.CONNECTION, "keep-alive"); + nettyRequest.setHeader(HttpHeaders.Names.CONNECTION, AsyncHttpProviderUtils.keepAliveHeaderValue(config)); } if (proxyServer != null) { if (!request.getHeaders().containsKey("Proxy-Connection")) { - nettyRequest.setHeader("Proxy-Connection", "keep-alive"); + nettyRequest.setHeader("Proxy-Connection", AsyncHttpProviderUtils.keepAliveHeaderValue(config)); } if (proxyServer.getPrincipal() != null) { diff --git a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java index c880592cc3..00db92cdca 100644 --- a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java +++ b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java @@ -12,6 +12,19 @@ */ package com.ning.http.util; +import java.io.ByteArrayInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; +import java.net.URI; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Collection; +import java.util.List; +import java.util.Locale; + +import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.AsyncHttpProvider; import com.ning.http.client.ByteArrayPart; import com.ning.http.client.Cookie; @@ -25,18 +38,6 @@ import com.ning.http.multipart.MultipartRequestEntity; import com.ning.http.multipart.PartSource; -import java.io.ByteArrayInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.io.UnsupportedEncodingException; -import java.net.URI; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.Collection; -import java.util.List; -import java.util.Locale; - /** * {@link com.ning.http.client.AsyncHttpProvider} common utilities. *

@@ -550,4 +551,8 @@ public static void checkBodyParts(int statusCode, Collection Date: Thu, 14 Mar 2013 12:13:43 -0400 Subject: [PATCH 087/264] [maven-release-plugin] prepare release async-http-client-1.7.12 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 48fd9e451a..ba9f6ea4b2 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.7.12-SNAPSHOT + 1.7.12 jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From 1b512efbd8305506c1d185eebbc93afac2508464 Mon Sep 17 00:00:00 2001 From: jfarcand Date: Thu, 14 Mar 2013 12:13:49 -0400 Subject: [PATCH 088/264] [maven-release-plugin] prepare for next development iteration --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index ba9f6ea4b2..c46ea75972 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.7.12 + 1.7.13-SNAPSHOT jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From 3a8957d7b9a34eeb683dc10265d3d8fd701fbcce Mon Sep 17 00:00:00 2001 From: Vincent Theron Date: Mon, 18 Mar 2013 10:22:27 -0400 Subject: [PATCH 089/264] use createHttpClientCodec to use user defined parameters --- .../http/client/providers/netty/NettyAsyncHttpProvider.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java index ab1dd7c13e..de8760a5d9 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java @@ -1405,14 +1405,14 @@ private void upgradeProtocol(ChannelPipeline p, String scheme) throws IOExceptio if (isSecure(scheme)) { if (p.get(SSL_HANDLER) == null) { - p.addFirst(HTTP_HANDLER, new HttpClientCodec()); + p.addFirst(HTTP_HANDLER, createHttpClientCodec); p.addFirst(SSL_HANDLER, new SslHandler(createSSLEngine())); } else { - p.addAfter(SSL_HANDLER, HTTP_HANDLER, new HttpClientCodec()); + p.addAfter(SSL_HANDLER, HTTP_HANDLER, createHttpClientCodec); } } else { - p.addFirst(HTTP_HANDLER, new HttpClientCodec()); + p.addFirst(HTTP_HANDLER, createHttpClientCodec); } } From e931eeb3e33ae4223b0b1be357d1c56903159b33 Mon Sep 17 00:00:00 2001 From: Vincent Theron Date: Mon, 18 Mar 2013 10:33:14 -0400 Subject: [PATCH 090/264] fix compilation error --- .../http/client/providers/netty/NettyAsyncHttpProvider.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java index de8760a5d9..c9e973ca9c 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java @@ -1405,14 +1405,14 @@ private void upgradeProtocol(ChannelPipeline p, String scheme) throws IOExceptio if (isSecure(scheme)) { if (p.get(SSL_HANDLER) == null) { - p.addFirst(HTTP_HANDLER, createHttpClientCodec); + p.addFirst(HTTP_HANDLER, createHttpClientCodec()); p.addFirst(SSL_HANDLER, new SslHandler(createSSLEngine())); } else { - p.addAfter(SSL_HANDLER, HTTP_HANDLER, createHttpClientCodec); + p.addAfter(SSL_HANDLER, HTTP_HANDLER, createHttpClientCodec()); } } else { - p.addFirst(HTTP_HANDLER, createHttpClientCodec); + p.addFirst(HTTP_HANDLER, createHttpClientCodec()); } } From 8283b33ae5697a2e51b061105dd462995c49c94b Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 25 Mar 2013 03:58:48 +0100 Subject: [PATCH 091/264] Only compute StringData bytes once, close #263 --- .../http/client/providers/netty/NettyAsyncHttpProvider.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java index c9e973ca9c..a2a1d8ecf6 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java @@ -812,8 +812,9 @@ else if (uri.getRawQuery() != null) nettyRequest.setHeader(HttpHeaders.Names.CONTENT_LENGTH, String.valueOf(request.getByteData().length)); nettyRequest.setContent(ChannelBuffers.wrappedBuffer(request.getByteData())); } else if (request.getStringData() != null) { - nettyRequest.setHeader(HttpHeaders.Names.CONTENT_LENGTH, String.valueOf(request.getStringData().getBytes(bodyCharset).length)); - nettyRequest.setContent(ChannelBuffers.wrappedBuffer(request.getStringData().getBytes(bodyCharset))); + byte[] bytes = request.getStringData().getBytes(bodyCharset); + nettyRequest.setHeader(HttpHeaders.Names.CONTENT_LENGTH, String.valueOf(bytes.length)); + nettyRequest.setContent(ChannelBuffers.wrappedBuffer(bytes)); } else if (request.getStreamData() != null) { int[] lengthWrapper = new int[1]; byte[] bytes = AsyncHttpProviderUtils.readFully(request.getStreamData(), lengthWrapper); From 32ddccb2cb54a28bcf9dac1e30ee1ab34c30f315 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 29 Mar 2013 13:25:52 +0100 Subject: [PATCH 092/264] AsyncHttpProviderUtils.convertExpireField shouldn't be Exception based, close #264 --- .../http/util/AsyncHttpProviderUtils.java | 33 ++++++++++--------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java index 00db92cdca..fd913c192e 100644 --- a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java +++ b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java @@ -18,9 +18,10 @@ import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.net.URI; -import java.text.ParseException; +import java.text.ParsePosition; import java.text.SimpleDateFormat; import java.util.Collection; +import java.util.Date; import java.util.List; import java.util.Locale; @@ -514,30 +515,30 @@ public static Cookie parseCookie(String value) { } public static int convertExpireField(String timestring) throws Exception { - Exception exception = null; String trimmedTimeString = removeQuote(timestring.trim()); long now = System.currentTimeMillis(); + Date date = null; + for (SimpleDateFormat sdf : simpleDateFormat.get()) { - try { - long expire = sdf.parse(trimmedTimeString).getTime(); - return (int) ((expire - now) / 1000); - } catch (ParseException e) { - exception = e; - } catch (NumberFormatException e) { - exception = e; - } + date = sdf.parse(trimmedTimeString, new ParsePosition(0)); + if (date != null) + break; } - throw exception; + if (date != null) { + long expire = date.getTime(); + return (int) ((expire - now) / 1000); + } else + throw new IllegalArgumentException("Not a valid expire field " + trimmedTimeString); } private final static String removeQuote(String s) { - if (s.startsWith("\"")) { - s = s.substring(1); - } + if (!s.isEmpty()) { + if (s.charAt(0) == '"') + s = s.substring(1); - if (s.endsWith("\"")) { - s = s.substring(0, s.length() - 1); + if (s.charAt(s.length() - 1) == '"') + s = s.substring(0, s.length() - 1); } return s; } From f3bff6bae52fa0b6901d4e490cfd873ce8ead283 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 29 Mar 2013 13:32:25 +0100 Subject: [PATCH 093/264] KMN --- src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java index fd913c192e..f73d7ec42d 100644 --- a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java +++ b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java @@ -533,7 +533,7 @@ public static int convertExpireField(String timestring) throws Exception { } private final static String removeQuote(String s) { - if (!s.isEmpty()) { + if (MiscUtil.isNonEmpty(s)) { if (s.charAt(0) == '"') s = s.substring(1); From b922c4a2efd27f4e440128de8040421a8572ecab Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 2 Apr 2013 12:55:31 +0200 Subject: [PATCH 094/264] RFC1123 is the standard format, try it first and not last --- .../java/com/ning/http/util/AsyncHttpProviderUtils.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java index f73d7ec42d..ba2024d1c8 100644 --- a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java +++ b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java @@ -56,14 +56,13 @@ protected SimpleDateFormat[] initialValue() { return new SimpleDateFormat[] { - new SimpleDateFormat("EEE MMM d HH:mm:ss yyyy", Locale.US), //ASCTIME + new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US), // RFC1123 new SimpleDateFormat("EEEE, dd-MMM-yy HH:mm:ss zzz", Locale.US), //RFC1036 + new SimpleDateFormat("EEE MMM d HH:mm:ss yyyy", Locale.US), //ASCTIME new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US), new SimpleDateFormat("EEE, dd-MMM-yyyy HH:mm:ss z", Locale.US), new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss Z", Locale.US), - new SimpleDateFormat("EEE, dd-MMM-yyyy HH:mm:ss Z", Locale.US), - new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US) // RFC1123 - + new SimpleDateFormat("EEE, dd-MMM-yyyy HH:mm:ss Z", Locale.US) }; } }; From 0281e3c58762506f79e2712640ce06a16acef28a Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 11 Apr 2013 21:59:18 +0200 Subject: [PATCH 095/264] Backport #272 --- src/main/java/com/ning/http/client/RequestBuilderBase.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/com/ning/http/client/RequestBuilderBase.java b/src/main/java/com/ning/http/client/RequestBuilderBase.java index fb50cc6687..14f71a5bc4 100644 --- a/src/main/java/com/ning/http/client/RequestBuilderBase.java +++ b/src/main/java/com/ning/http/client/RequestBuilderBase.java @@ -371,6 +371,8 @@ protected RequestBuilderBase(Class derived, Request prototype) { public T setUrl(String url) { request.originalUri = buildURI(url); + request.uri = null; + request.rawUri = null; return derived.cast(this); } From ef34a2b0948722aceed798eb21fdac0f1722fbfc Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 11 Apr 2013 22:07:41 +0200 Subject: [PATCH 096/264] Backport #267 --- .../http/client/providers/apache/ApacheAsyncHttpProvider.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/ning/http/client/providers/apache/ApacheAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/apache/ApacheAsyncHttpProvider.java index 561464d72f..e572101cbb 100644 --- a/src/main/java/com/ning/http/client/providers/apache/ApacheAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/apache/ApacheAsyncHttpProvider.java @@ -345,7 +345,7 @@ private HttpMethodBase createMethod(HttpClient client, Request request) throws I if (proxyServer.getPrincipal() != null) { Credentials defaultcreds = new UsernamePasswordCredentials(proxyServer.getPrincipal(), proxyServer.getPassword()); - client.getState().setCredentials(new AuthScope(null, -1, AuthScope.ANY_REALM), defaultcreds); + client.getState().setProxyCredentials(new AuthScope(null, -1, AuthScope.ANY_REALM), defaultcreds); } ProxyHost proxyHost = proxyServer == null ? null : new ProxyHost(proxyServer.getHost(), proxyServer.getPort()); From bf3c9c6112bf536c5fdcde70b983f2142b1d9fe6 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 12 Apr 2013 10:14:09 +0200 Subject: [PATCH 097/264] Lower log level, close #275 --- .../ning/http/client/generators/InputStreamBodyGenerator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/ning/http/client/generators/InputStreamBodyGenerator.java b/src/main/java/com/ning/http/client/generators/InputStreamBodyGenerator.java index 12660ca438..5beba6e092 100644 --- a/src/main/java/com/ning/http/client/generators/InputStreamBodyGenerator.java +++ b/src/main/java/com/ning/http/client/generators/InputStreamBodyGenerator.java @@ -43,7 +43,7 @@ public InputStreamBodyGenerator(InputStream inputStream) { if (inputStream.markSupported()) { inputStream.mark(0); } else { - logger.warn("inputStream.markSupported() not supported. Some features will not works"); + logger.info("inputStream.markSupported() not supported. Some features will not works"); } } From 4cc2f1453ad482fefca472a87be653f8aeacab62 Mon Sep 17 00:00:00 2001 From: jfarcand Date: Fri, 12 Apr 2013 16:14:35 -0400 Subject: [PATCH 098/264] [maven-release-plugin] prepare release async-http-client-1.7.13 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index c46ea75972..c60ec9ec8f 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.7.13-SNAPSHOT + 1.7.13 jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From 0b0886ba27b43bdbe5e1505c9b0ea8ea7d53a954 Mon Sep 17 00:00:00 2001 From: jfarcand Date: Fri, 12 Apr 2013 16:14:43 -0400 Subject: [PATCH 099/264] [maven-release-plugin] prepare for next development iteration --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index c60ec9ec8f..89fd0e45af 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.7.13 + 1.7.14-SNAPSHOT jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From e6cf447158c53e915b1ba0cf888733ba2ba83dce Mon Sep 17 00:00:00 2001 From: jfarcand Date: Thu, 18 Apr 2013 14:17:37 -0400 Subject: [PATCH 100/264] Fixes for #278 --- .../netty/NettyAsyncHttpProvider.java | 36 +++++++++++-------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java index a2a1d8ecf6..4f4b043b08 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java @@ -2480,21 +2480,25 @@ public void setContent(ChannelBuffer content) { h.onBodyPartReceived(rp); NettyWebSocket webSocket = NettyWebSocket.class.cast(h.onCompleted()); - - if(pendingOpcode == OPCODE_BINARY) { - webSocket.onBinaryFragment(rp.getBodyPartBytes(),frame.isFinalFragment()); - } - else { - webSocket.onTextFragment(frame.getBinaryData().toString(UTF8),frame.isFinalFragment()); - } - if (CloseWebSocketFrame.class.isAssignableFrom(frame.getClass())) { - try { - webSocket.onClose(CloseWebSocketFrame.class.cast(frame).getStatusCode(), CloseWebSocketFrame.class.cast(frame).getReasonText()); - } catch (Throwable t) { - // Swallow any exception that may comes from a Netty version released before 3.4.0 - log.trace("", t); + if (webSocket != null) { + if(pendingOpcode == OPCODE_BINARY) { + webSocket.onBinaryFragment(rp.getBodyPartBytes(),frame.isFinalFragment()); + } + else { + webSocket.onTextFragment(frame.getBinaryData().toString(UTF8),frame.isFinalFragment()); } + + if (CloseWebSocketFrame.class.isAssignableFrom(frame.getClass())) { + try { + webSocket.onClose(CloseWebSocketFrame.class.cast(frame).getStatusCode(), CloseWebSocketFrame.class.cast(frame).getReasonText()); + } catch (Throwable t) { + // Swallow any exception that may comes from a Netty version released before 3.4.0 + log.trace("", t); + } + } + } else { + log.debug("UpgradeHandler returned a null NettyWebSocket "); } } } else { @@ -2514,8 +2518,10 @@ public void onError(ChannelHandlerContext ctx, ExceptionEvent e) { WebSocketUpgradeHandler h = WebSocketUpgradeHandler.class.cast(nettyResponse.getAsyncHandler()); NettyWebSocket webSocket = NettyWebSocket.class.cast(h.onCompleted()); - webSocket.onError(e.getCause()); - webSocket.close(); + if (webSocket != null) { + webSocket.onError(e.getCause()); + webSocket.close(); + } } catch (Throwable t) { log.error("onError", t); } From b62bd15a330b3f80aa2a3ba4d2aeffe7b06e1f6c Mon Sep 17 00:00:00 2001 From: jfarcand Date: Wed, 24 Apr 2013 11:02:39 -0400 Subject: [PATCH 101/264] Fixes for #284 --- .../http/client/providers/netty/NettyWebSocket.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyWebSocket.java b/src/main/java/com/ning/http/client/providers/netty/NettyWebSocket.java index 3e0f7947e8..2197ba01f4 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyWebSocket.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyWebSocket.java @@ -19,15 +19,15 @@ import com.ning.http.client.websocket.WebSocketTextListener; import org.jboss.netty.channel.Channel; import org.jboss.netty.handler.codec.http.websocketx.BinaryWebSocketFrame; +import org.jboss.netty.handler.codec.http.websocketx.CloseWebSocketFrame; import org.jboss.netty.handler.codec.http.websocketx.PingWebSocketFrame; import org.jboss.netty.handler.codec.http.websocketx.PongWebSocketFrame; import org.jboss.netty.handler.codec.http.websocketx.TextWebSocketFrame; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.concurrent.ConcurrentLinkedQueue; - import java.io.ByteArrayOutputStream; +import java.util.concurrent.ConcurrentLinkedQueue; import static org.jboss.netty.buffer.ChannelBuffers.wrappedBuffer; @@ -116,7 +116,12 @@ public boolean isOpen() { public void close() { onClose(); listeners.clear(); - channel.close(); + try { + channel.write(new CloseWebSocketFrame()); + channel.getCloseFuture().awaitUninterruptibly(); + } finally { + channel.close(); + } } protected void onBinaryFragment(byte[] message, boolean last) { From 354fad361a29df6bf98d4d97440f0373c879da7f Mon Sep 17 00:00:00 2001 From: Ryan Lubke Date: Wed, 24 Apr 2013 10:05:47 -0700 Subject: [PATCH 102/264] Changes for Grizzly 2.3.2-SNAPSHOT. --- pom.xml | 2 +- .../grizzly/GrizzlyAsyncHttpProvider.java | 19 +++++++++---------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/pom.xml b/pom.xml index 89fd0e45af..5afd3c65c9 100644 --- a/pom.xml +++ b/pom.xml @@ -540,7 +540,7 @@ org.glassfish.grizzly grizzly-websockets - 2.2.21 + 2.3.2-SNAPSHOT true diff --git a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java index f75de1c9d0..3741027fc5 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java @@ -31,7 +31,6 @@ import com.ning.http.client.HttpResponseStatus; import com.ning.http.client.ListenableFuture; import com.ning.http.client.MaxRedirectException; -import com.ning.http.client.Part; import com.ning.http.client.PerRequestConfig; import com.ning.http.client.ProxyServer; import com.ning.http.client.Realm; @@ -102,13 +101,13 @@ import org.glassfish.grizzly.utils.Futures; import org.glassfish.grizzly.utils.IdleTimeoutFilter; import org.glassfish.grizzly.websockets.DataFrame; -import org.glassfish.grizzly.websockets.DefaultWebSocket; import org.glassfish.grizzly.websockets.HandShake; import org.glassfish.grizzly.websockets.HandshakeException; import org.glassfish.grizzly.websockets.ProtocolHandler; +import org.glassfish.grizzly.websockets.SimpleWebSocket; import org.glassfish.grizzly.websockets.Version; -import org.glassfish.grizzly.websockets.WebSocketEngine; import org.glassfish.grizzly.websockets.WebSocketFilter; +import org.glassfish.grizzly.websockets.WebSocketHolder; import org.glassfish.grizzly.websockets.draft06.ClosingFrame; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -1295,13 +1294,13 @@ protected void onHttpHeadersParsed(HttpHeader httpHeader, context.protocolHandler.setConnection(ctx.getConnection()); final GrizzlyWebSocketAdapter webSocketAdapter = createWebSocketAdapter(context); context.webSocket = webSocketAdapter; - DefaultWebSocket ws = webSocketAdapter.gWebSocket; + SimpleWebSocket ws = webSocketAdapter.gWebSocket; if (context.currentState == AsyncHandler.STATE.UPGRADE) { httpHeader.setChunked(false); ws.onConnect(); - WebSocketEngine.getEngine().setWebSocketHolder(ctx.getConnection(), - context.protocolHandler, - ws); + WebSocketHolder.set(ctx.getConnection(), + context.protocolHandler, + ws); ((WebSocketUpgradeHandler) context.handler).onSuccess(context.webSocket); final int wsTimeout = context.provider.clientConfig.getWebSocketIdleTimeoutInMs(); IdleTimeoutFilter.setCustomTimeout(ctx.getConnection(), @@ -1388,7 +1387,7 @@ protected boolean onHttpPacketParsed(HttpHeader httpHeader, FilterChainContext c // ----------------------------------------------------- Private Methods private static GrizzlyWebSocketAdapter createWebSocketAdapter(final HttpTransactionContext context) { - DefaultWebSocket ws = new DefaultWebSocket(context.protocolHandler); + SimpleWebSocket ws = new SimpleWebSocket(context.protocolHandler); AsyncHttpProviderConfig config = context.provider.clientConfig.getAsyncHttpProviderConfig(); boolean bufferFragments = true; if (config instanceof GrizzlyAsyncHttpProviderConfig) { @@ -2576,13 +2575,13 @@ public void getBytes(byte[] bytes) { private static final class GrizzlyWebSocketAdapter implements WebSocket { - final DefaultWebSocket gWebSocket; + final SimpleWebSocket gWebSocket; final boolean bufferFragments; // -------------------------------------------------------- Constructors - GrizzlyWebSocketAdapter(final DefaultWebSocket gWebSocket, + GrizzlyWebSocketAdapter(final SimpleWebSocket gWebSocket, final boolean bufferFragments) { this.gWebSocket = gWebSocket; this.bufferFragments = bufferFragments; From 4d7fa21b6b7d55bf59c5862a573f92e0eb3c5405 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 25 Apr 2013 00:10:31 +0200 Subject: [PATCH 103/264] Fork Netty's Cookie Decoder, close #283 --- pom.xml | 1 + .../java/com/ning/http/client/Cookie.java | 203 ++++++++++-- .../providers/apache/ApacheResponse.java | 7 +- .../grizzly/GrizzlyAsyncHttpProvider.java | 7 +- .../client/providers/jdk/JDKResponse.java | 6 +- .../netty/NettyAsyncHttpProvider.java | 13 +- .../client/providers/netty/NettyResponse.java | 6 +- .../http/util/AsyncHttpProviderUtils.java | 60 +--- .../handler/codec/http/CookieDecoder.java | 304 ++++++++++++++++++ .../handler/codec/http/CookieHeaderNames.java | 57 ++++ .../jboss/netty/util/internal/StringUtil.java | 73 +++++ .../handler/codec/http/CookieDecoderTest.java | 52 +++ 12 files changed, 686 insertions(+), 103 deletions(-) create mode 100644 src/main/java/com/ning/org/jboss/netty/handler/codec/http/CookieDecoder.java create mode 100644 src/main/java/com/ning/org/jboss/netty/handler/codec/http/CookieHeaderNames.java create mode 100644 src/main/java/com/ning/org/jboss/netty/util/internal/StringUtil.java create mode 100644 src/test/java/com/ning/org/jboss/netty/handler/codec/http/CookieDecoderTest.java diff --git a/pom.xml b/pom.xml index 89fd0e45af..5bd153c27e 100644 --- a/pom.xml +++ b/pom.xml @@ -465,6 +465,7 @@ **/NettyAsyncHttpProvider$* **/NettyResponse **/AsyncHttpProviderUtils + **/Cookie diff --git a/src/main/java/com/ning/http/client/Cookie.java b/src/main/java/com/ning/http/client/Cookie.java index 26fd46920f..f9c6cb2362 100644 --- a/src/main/java/com/ning/http/client/Cookie.java +++ b/src/main/java/com/ning/http/client/Cookie.java @@ -20,7 +20,7 @@ import java.util.Set; import java.util.TreeSet; -public class Cookie { +public class Cookie implements Comparable{ private final String domain; private final String name; private final String value; @@ -28,27 +28,85 @@ public class Cookie { private final int maxAge; private final boolean secure; private final int version; + private final boolean httpOnly; + private final boolean discard; + private final String comment; + private final String commentUrl; + private Set ports = Collections.emptySet(); private Set unmodifiablePorts = ports; + @Deprecated public Cookie(String domain, String name, String value, String path, int maxAge, boolean secure) { - this.domain = domain; - this.name = name; - this.value = value; - this.path = path; - this.maxAge = maxAge; - this.secure = secure; - this.version = 1; + this(domain, name, value, path, maxAge, secure, 1); } + @Deprecated public Cookie(String domain, String name, String value, String path, int maxAge, boolean secure, int version) { - this.domain = domain; + this(domain, name, value, path, maxAge, secure, version, false, false, null, null, Collections. emptySet()); + } + + public Cookie(String domain, String name, String value, String path, int maxAge, boolean secure, int version, boolean httpOnly, boolean discard, String comment, String commentUrl, Iterable ports) { + + if (name == null) { + throw new NullPointerException("name"); + } + name = name.trim(); + if (name.length() == 0) { + throw new IllegalArgumentException("empty name"); + } + + for (int i = 0; i < name.length(); i++) { + char c = name.charAt(i); + if (c > 127) { + throw new IllegalArgumentException("name contains non-ascii character: " + name); + } + + // Check prohibited characters. + switch (c) { + case '\t': + case '\n': + case 0x0b: + case '\f': + case '\r': + case ' ': + case ',': + case ';': + case '=': + throw new IllegalArgumentException("name contains one of the following prohibited characters: " + "=,; \\t\\r\\n\\v\\f: " + name); + } + } + + if (name.charAt(0) == '$') { + throw new IllegalArgumentException("name starting with '$' not allowed: " + name); + } + + if (value == null) { + throw new NullPointerException("value"); + } + this.name = name; this.value = value; - this.path = path; + this.domain = validateValue("domain", domain); + this.path = validateValue("path", path); this.maxAge = maxAge; this.secure = secure; this.version = version; + this.httpOnly = httpOnly; + + if (version > 0) { + this.comment = validateValue("comment", comment); + } else { + this.comment = null; + } + if (version > 1) { + this.discard = discard; + this.commentUrl = validateValue("commentUrl", commentUrl); + setPorts(ports); + } else { + this.discard = false; + this.commentUrl = null; + } } public String getDomain() { @@ -79,6 +137,22 @@ public int getVersion() { return version; } + public String getComment() { + return this.comment; + } + + public String getCommentUrl() { + return this.commentUrl; + } + + public boolean isHttpOnly() { + return httpOnly; + } + + public boolean isDiscard() { + return discard; + } + public Set getPorts() { if (unmodifiablePorts == null) { unmodifiablePorts = Collections.unmodifiableSet(ports); @@ -86,28 +160,7 @@ public Set getPorts() { return unmodifiablePorts; } - public void setPorts(int... ports) { - if (ports == null) { - throw new NullPointerException("ports"); - } - - int[] portsCopy = ports.clone(); - if (portsCopy.length == 0) { - unmodifiablePorts = this.ports = Collections.emptySet(); - } else { - Set newPorts = new TreeSet(); - for (int p : portsCopy) { - if (p <= 0 || p > 65535) { - throw new IllegalArgumentException("port out of range: " + p); - } - newPorts.add(Integer.valueOf(p)); - } - this.ports = newPorts; - unmodifiablePorts = null; - } - } - - public void setPorts(Iterable ports) { + private void setPorts(Iterable ports) { Set newPorts = new TreeSet(); for (int p : ports) { if (p <= 0 || p > 65535) { @@ -125,7 +178,89 @@ public void setPorts(Iterable ports) { @Override public String toString() { - return String.format("Cookie: domain=%s, name=%s, value=%s, path=%s, maxAge=%d, secure=%s", - domain, name, value, path, maxAge, secure); + StringBuilder buf = new StringBuilder(); + buf.append(getName()); + buf.append('='); + buf.append(getValue()); + if (getDomain() != null) { + buf.append("; domain="); + buf.append(getDomain()); + } + if (getPath() != null) { + buf.append("; path="); + buf.append(getPath()); + } + if (getComment() != null) { + buf.append("; comment="); + buf.append(getComment()); + } + if (getMaxAge() >= 0) { + buf.append("; maxAge="); + buf.append(getMaxAge()); + buf.append('s'); + } + if (isSecure()) { + buf.append("; secure"); + } + if (isHttpOnly()) { + buf.append("; HTTPOnly"); + } + return buf.toString(); + } + + private String validateValue(String name, String value) { + if (value == null) { + return null; + } + value = value.trim(); + if (value.length() == 0) { + return null; + } + for (int i = 0; i < value.length(); i++) { + char c = value.charAt(i); + switch (c) { + case '\r': + case '\n': + case '\f': + case 0x0b: + case ';': + throw new IllegalArgumentException(name + " contains one of the following prohibited characters: " + ";\\r\\n\\f\\v (" + value + ')'); + } + } + return value; + } + + public int compareTo(Cookie c) { + int v; + v = getName().compareToIgnoreCase(c.getName()); + if (v != 0) { + return v; + } + + if (getPath() == null) { + if (c.getPath() != null) { + return -1; + } + } else if (c.getPath() == null) { + return 1; + } else { + v = getPath().compareTo(c.getPath()); + if (v != 0) { + return v; + } + } + + if (getDomain() == null) { + if (c.getDomain() != null) { + return -1; + } + } else if (c.getDomain() == null) { + return 1; + } else { + v = getDomain().compareToIgnoreCase(c.getDomain()); + return v; + } + + return 0; } } diff --git a/src/main/java/com/ning/http/client/providers/apache/ApacheResponse.java b/src/main/java/com/ning/http/client/providers/apache/ApacheResponse.java index d899a40ed1..c0ad75bc47 100644 --- a/src/main/java/com/ning/http/client/providers/apache/ApacheResponse.java +++ b/src/main/java/com/ning/http/client/providers/apache/ApacheResponse.java @@ -14,6 +14,7 @@ import static com.ning.http.util.MiscUtil.isNonEmpty; +import com.ning.org.jboss.netty.handler.codec.http.CookieDecoder; import com.ning.http.client.Cookie; import com.ning.http.client.FluentCaseInsensitiveStringsMap; import com.ning.http.client.HttpResponseBodyPart; @@ -31,7 +32,7 @@ import java.util.Collections; import java.util.List; import java.util.Map; - +import java.util.Set; public class ApacheResponse implements Response { private final static String DEFAULT_CHARSET = "ISO-8859-1"; @@ -161,8 +162,8 @@ public List getCookies() { // TODO: ask for parsed header List v = header.getValue(); for (String value : v) { - Cookie cookie = AsyncHttpProviderUtils.parseCookie(value); - localCookies.add(cookie); + Set cookies = CookieDecoder.decode(value); + localCookies.addAll(cookies); } } } diff --git a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java index f75de1c9d0..a0632a664e 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java @@ -15,13 +15,13 @@ import static com.ning.http.util.MiscUtil.isNonEmpty; +import com.ning.org.jboss.netty.handler.codec.http.CookieDecoder; import com.ning.http.client.AsyncHandler; import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.AsyncHttpProvider; import com.ning.http.client.AsyncHttpProviderConfig; import com.ning.http.client.Body; import com.ning.http.client.BodyGenerator; -import com.ning.http.client.ConnectionPoolKeyStrategy; import com.ning.http.client.ConnectionsPool; import com.ning.http.client.Cookie; import com.ning.http.client.FluentCaseInsensitiveStringsMap; @@ -1667,8 +1667,9 @@ private static Request newRequest(final URI uri, builder.setQueryParameters(null); } for (String cookieStr : response.getHeaders().values(Header.Cookie)) { - Cookie c = AsyncHttpProviderUtils.parseCookie(cookieStr); - builder.addOrReplaceCookie(c); + for (Cookie c : CookieDecoder.decode(cookieStr)) { + builder.addOrReplaceCookie(c); + } } return builder.build(); diff --git a/src/main/java/com/ning/http/client/providers/jdk/JDKResponse.java b/src/main/java/com/ning/http/client/providers/jdk/JDKResponse.java index 2fe9566e06..8dda720d8b 100644 --- a/src/main/java/com/ning/http/client/providers/jdk/JDKResponse.java +++ b/src/main/java/com/ning/http/client/providers/jdk/JDKResponse.java @@ -14,6 +14,7 @@ import static com.ning.http.util.MiscUtil.isNonEmpty; +import com.ning.org.jboss.netty.handler.codec.http.CookieDecoder; import com.ning.http.client.Cookie; import com.ning.http.client.FluentCaseInsensitiveStringsMap; import com.ning.http.client.HttpResponseBodyPart; @@ -32,6 +33,7 @@ import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; @@ -175,8 +177,8 @@ public List getCookies() { // TODO: ask for parsed header List v = header.getValue(); for (String value : v) { - Cookie cookie = AsyncHttpProviderUtils.parseCookie(value); - localCookies.add(cookie); + Set cookies = CookieDecoder.decode(value); + localCookies.addAll(cookies); } } } diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java index 4f4b043b08..9cc75a946f 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java @@ -17,6 +17,7 @@ import static com.ning.http.util.MiscUtil.isNonEmpty; +import com.ning.org.jboss.netty.handler.codec.http.CookieDecoder; import com.ning.http.client.AsyncHandler; import com.ning.http.client.AsyncHandler.STATE; import com.ning.http.client.AsyncHttpClientConfig; @@ -585,7 +586,7 @@ public void operationComplete(ChannelFuture cf) { int delay = Math.min(config.getIdleConnectionTimeoutInMs(), requestTimeout(config, future.getRequest().getPerRequestConfig())); if (delay != -1 && !future.isDone() && !future.isCancelled()) { ReaperFuture reaperFuture = new ReaperFuture(future); - Future scheduledFuture = config.reaper().scheduleAtFixedRate(reaperFuture, 0, delay, TimeUnit.MILLISECONDS); + Future scheduledFuture = config.reaper().scheduleAtFixedRate(reaperFuture, 0, delay, TimeUnit.MILLISECONDS); reaperFuture.setScheduledFuture(scheduledFuture); future.setReaperFuture(reaperFuture); } @@ -2083,13 +2084,15 @@ private boolean redirect(Request request, log.debug("Redirecting to {}", newUrl); for (String cookieStr : future.getHttpResponse().getHeaders(HttpHeaders.Names.SET_COOKIE)) { - Cookie c = AsyncHttpProviderUtils.parseCookie(cookieStr); - nBuilder.addOrReplaceCookie(c); + for (Cookie c : CookieDecoder.decode(cookieStr)) { + nBuilder.addOrReplaceCookie(c); + } } for (String cookieStr : future.getHttpResponse().getHeaders(HttpHeaders.Names.SET_COOKIE2)) { - Cookie c = AsyncHttpProviderUtils.parseCookie(cookieStr); - nBuilder.addOrReplaceCookie(c); + for (Cookie c : CookieDecoder.decode(cookieStr)) { + nBuilder.addOrReplaceCookie(c); + } } AsyncCallable ac = new AsyncCallable(future) { diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyResponse.java b/src/main/java/com/ning/http/client/providers/netty/NettyResponse.java index 65870b0ca0..3758d2b3cc 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyResponse.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyResponse.java @@ -17,6 +17,7 @@ import static com.ning.http.util.MiscUtil.isNonEmpty; +import com.ning.org.jboss.netty.handler.codec.http.CookieDecoder; import com.ning.http.client.Cookie; import com.ning.http.client.FluentCaseInsensitiveStringsMap; import com.ning.http.client.HttpResponseBodyPart; @@ -35,6 +36,7 @@ import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.Set; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBufferInputStream; @@ -184,8 +186,8 @@ public List getCookies() { // TODO: ask for parsed header List v = header.getValue(); for (String value : v) { - Cookie cookie = AsyncHttpProviderUtils.parseCookie(value); - localCookies.add(cookie); + Set cookies = CookieDecoder.decode(value); + localCookies.addAll(cookies); } } } diff --git a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java index ba2024d1c8..60b9379664 100644 --- a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java +++ b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java @@ -25,6 +25,7 @@ import java.util.List; import java.util.Locale; +import com.ning.org.jboss.netty.handler.codec.http.CookieDecoder; import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.AsyncHttpProvider; import com.ning.http.client.ByteArrayPart; @@ -459,61 +460,12 @@ public static String parseCharset(String contentType) { return null; } + @Deprecated public static Cookie parseCookie(String value) { - String[] fields = value.split(";\\s*"); - String[] cookie = fields[0].split("=", 2); - String cookieName = cookie[0]; - String cookieValue = (cookie.length == 1) ? null : cookie[1]; - - int maxAge = -1; - String path = null; - String domain = null; - boolean secure = false; - - boolean maxAgeSet = false; - boolean expiresSet = false; - - for (int j = 1; j < fields.length; j++) { - if ("secure".equalsIgnoreCase(fields[j])) { - secure = true; - } else if (fields[j].indexOf('=') > 0) { - String[] f = fields[j].split("="); - if (f.length == 1) continue; // Add protection against null field values - - // favor 'max-age' field over 'expires' - if (!maxAgeSet && "max-age".equalsIgnoreCase(f[0])) { - try { - maxAge = Math.max(Integer.valueOf(removeQuote(f[1])), 0); - } catch (NumberFormatException e1) { - // ignore failure to parse -> treat as session cookie - // invalidate a previously parsed expires-field - maxAge = -1; - } - maxAgeSet = true; - } else if (!maxAgeSet && !expiresSet && "expires".equalsIgnoreCase(f[0])) { - try { - maxAge = Math.max(convertExpireField(f[1]), 0); - } catch (Exception e) { - // original behavior, is this correct at all (expires field with max-age semantics)? - try { - maxAge = Math.max(Integer.valueOf(f[1]), 0); - } catch (NumberFormatException e1) { - // ignore failure to parse -> treat as session cookie - } - } - expiresSet = true; - } else if ("domain".equalsIgnoreCase(f[0])) { - domain = f[1]; - } else if ("path".equalsIgnoreCase(f[0])) { - path = f[1]; - } - } - } - - return new Cookie(domain, cookieName, cookieValue, path, maxAge, secure); + return CookieDecoder.decode(value).iterator().next(); } - public static int convertExpireField(String timestring) throws Exception { + public static int convertExpireField(String timestring) { String trimmedTimeString = removeQuote(timestring.trim()); long now = System.currentTimeMillis(); Date date = null; @@ -525,8 +477,8 @@ public static int convertExpireField(String timestring) throws Exception { } if (date != null) { - long expire = date.getTime(); - return (int) ((expire - now) / 1000); + long maxAgeMillis = date.getTime() - now; + return (int) (maxAgeMillis / 1000) + (maxAgeMillis % 1000 != 0? 1 : 0); } else throw new IllegalArgumentException("Not a valid expire field " + trimmedTimeString); } diff --git a/src/main/java/com/ning/org/jboss/netty/handler/codec/http/CookieDecoder.java b/src/main/java/com/ning/org/jboss/netty/handler/codec/http/CookieDecoder.java new file mode 100644 index 0000000000..15cbfe22e5 --- /dev/null +++ b/src/main/java/com/ning/org/jboss/netty/handler/codec/http/CookieDecoder.java @@ -0,0 +1,304 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Copyright (c) 2010-2012 Sonatype, Inc. All rights reserved. + * + * This program is licensed to you under the Apache License Version 2.0, + * and you may not use this file except in compliance with the Apache License Version 2.0. + * You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the Apache License Version 2.0 is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under. + */ +package com.ning.org.jboss.netty.handler.codec.http; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Set; +import java.util.TreeSet; + +import com.ning.org.jboss.netty.util.internal.StringUtil; +import com.ning.http.client.Cookie; +import com.ning.http.util.AsyncHttpProviderUtils; + +/** + * Decodes an HTTP header value into {@link Cookie}s. This decoder can decode the HTTP cookie version 0, 1, and 2. + * + *

+ * {@link HttpRequest} req = ...;
+ * String value = req.getHeader("Cookie");
+ * Set<{@link Cookie}> cookies = new {@link CookieDecoder}().decode(value);
+ * 
+ * + * @see CookieEncoder + * + * @apiviz.stereotype utility + * @apiviz.has org.jboss.netty.handler.codec.http.Cookie oneway - - decodes + */ +public class CookieDecoder { + + private static final char COMMA = ','; + + /** + * Creates a new decoder. + */ + private CookieDecoder() { + } + + /** + * Decodes the specified HTTP header value into {@link Cookie}s. + * + * @return the decoded {@link Cookie}s + */ + public static Set decode(String header) { + List names = new ArrayList(8); + List values = new ArrayList(8); + extractKeyValuePairs(header, names, values); + + if (names.isEmpty()) { + return Collections.emptySet(); + } + + int i; + int version = 0; + + // $Version is the only attribute that can appear before the actual + // cookie name-value pair. + if (names.get(0).equalsIgnoreCase(CookieHeaderNames.VERSION)) { + try { + version = Integer.parseInt(values.get(0)); + } catch (NumberFormatException e) { + // Ignore. + } + i = 1; + } else { + i = 0; + } + + if (names.size() <= i) { + // There's a version attribute, but nothing more. + return Collections.emptySet(); + } + + Set cookies = new TreeSet(); + for (; i < names.size(); i++) { + String name = names.get(i); + String value = values.get(i); + if (value == null) { + value = ""; + } + + String cookieName = name; + String cookieValue = value; + boolean discard = false; + boolean secure = false; + boolean httpOnly = false; + String comment = null; + String commentURL = null; + String domain = null; + String path = null; + int maxAge = Integer.MIN_VALUE; + List ports = Collections.emptyList(); + + for (int j = i + 1; j < names.size(); j++, i++) { + name = names.get(j); + value = values.get(j); + + if (CookieHeaderNames.DISCARD.equalsIgnoreCase(name)) { + discard = true; + } else if (CookieHeaderNames.SECURE.equalsIgnoreCase(name)) { + secure = true; + } else if (CookieHeaderNames.HTTPONLY.equalsIgnoreCase(name)) { + httpOnly = true; + } else if (CookieHeaderNames.COMMENT.equalsIgnoreCase(name)) { + comment = value; + } else if (CookieHeaderNames.COMMENTURL.equalsIgnoreCase(name)) { + commentURL = value; + } else if (CookieHeaderNames.DOMAIN.equalsIgnoreCase(name)) { + domain = value; + } else if (CookieHeaderNames.PATH.equalsIgnoreCase(name)) { + path = value; + } else if (CookieHeaderNames.EXPIRES.equalsIgnoreCase(name)) { + try { + maxAge = AsyncHttpProviderUtils.convertExpireField(value); + } catch (Exception e) { + // original behavior, is this correct at all (expires field with max-age semantics)? + try { + maxAge = Math.max(Integer.valueOf(value), 0); + } catch (NumberFormatException e1) { + // ignore failure to parse -> treat as session cookie + } + } + } else if (CookieHeaderNames.MAX_AGE.equalsIgnoreCase(name)) { + maxAge = Integer.parseInt(value); + } else if (CookieHeaderNames.VERSION.equalsIgnoreCase(name)) { + version = Integer.parseInt(value); + } else if (CookieHeaderNames.PORT.equalsIgnoreCase(name)) { + String[] portList = StringUtil.split(value, COMMA); + ports = new ArrayList(2); + for (String s1 : portList) { + try { + ports.add(Integer.valueOf(s1)); + } catch (NumberFormatException e) { + // Ignore. + } + } + } else { + break; + } + } + + Cookie c = new Cookie(domain, cookieName, cookieValue, path, maxAge, secure, version, httpOnly, discard, comment, commentURL, ports); + cookies.add(c); + } + + return cookies; + } + + private static void extractKeyValuePairs(final String header, final List names, final List values) { + + final int headerLen = header.length(); + loop: for (int i = 0;;) { + + // Skip spaces and separators. + for (;;) { + if (i == headerLen) { + break loop; + } + switch (header.charAt(i)) { + case '\t': + case '\n': + case 0x0b: + case '\f': + case '\r': + case ' ': + case ',': + case ';': + i++; + continue; + } + break; + } + + // Skip '$'. + for (;;) { + if (i == headerLen) { + break loop; + } + if (header.charAt(i) == '$') { + i++; + continue; + } + break; + } + + String name; + String value; + + if (i == headerLen) { + name = null; + value = null; + } else { + int newNameStart = i; + keyValLoop: for (;;) { + switch (header.charAt(i)) { + case ';': + // NAME; (no value till ';') + name = header.substring(newNameStart, i); + value = null; + break keyValLoop; + case '=': + // NAME=VALUE + name = header.substring(newNameStart, i); + i++; + if (i == headerLen) { + // NAME= (empty value, i.e. nothing after '=') + value = ""; + break keyValLoop; + } + + int newValueStart = i; + char c = header.charAt(i); + if (c == '"' || c == '\'') { + // NAME="VALUE" or NAME='VALUE' + StringBuilder newValueBuf = new StringBuilder(header.length() - i); + final char q = c; + boolean hadBackslash = false; + i++; + for (;;) { + if (i == headerLen) { + value = newValueBuf.toString(); + break keyValLoop; + } + if (hadBackslash) { + hadBackslash = false; + c = header.charAt(i++); + switch (c) { + case '\\': + case '"': + case '\'': + // Escape last backslash. + newValueBuf.setCharAt(newValueBuf.length() - 1, c); + break; + default: + // Do not escape last backslash. + newValueBuf.append(c); + } + } else { + c = header.charAt(i++); + if (c == q) { + value = newValueBuf.toString(); + break keyValLoop; + } + newValueBuf.append(c); + if (c == '\\') { + hadBackslash = true; + } + } + } + } else { + // NAME=VALUE; + int semiPos = header.indexOf(';', i); + if (semiPos > 0) { + value = header.substring(newValueStart, semiPos); + i = semiPos; + } else { + value = header.substring(newValueStart); + i = headerLen; + } + } + break keyValLoop; + default: + i++; + } + + if (i == headerLen) { + // NAME (no value till the end of string) + name = header.substring(newNameStart); + value = null; + break; + } + } + } + + names.add(name); + values.add(value); + } + } +} diff --git a/src/main/java/com/ning/org/jboss/netty/handler/codec/http/CookieHeaderNames.java b/src/main/java/com/ning/org/jboss/netty/handler/codec/http/CookieHeaderNames.java new file mode 100644 index 0000000000..5d3e6c9249 --- /dev/null +++ b/src/main/java/com/ning/org/jboss/netty/handler/codec/http/CookieHeaderNames.java @@ -0,0 +1,57 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Copyright (c) 2010-2012 Sonatype, Inc. All rights reserved. + * + * This program is licensed to you under the Apache License Version 2.0, + * and you may not use this file except in compliance with the Apache License Version 2.0. + * You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the Apache License Version 2.0 is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under. + */ +package com.ning.org.jboss.netty.handler.codec.http; + +final class CookieHeaderNames { + static final String PATH = "Path"; + + static final String EXPIRES = "Expires"; + + static final String MAX_AGE = "Max-Age"; + + static final String DOMAIN = "Domain"; + + static final String SECURE = "Secure"; + + static final String HTTPONLY = "HTTPOnly"; + + static final String COMMENT = "Comment"; + + static final String COMMENTURL = "CommentURL"; + + static final String DISCARD = "Discard"; + + static final String PORT = "Port"; + + static final String VERSION = "Version"; + + private CookieHeaderNames() { + // Unused. + } +} + diff --git a/src/main/java/com/ning/org/jboss/netty/util/internal/StringUtil.java b/src/main/java/com/ning/org/jboss/netty/util/internal/StringUtil.java new file mode 100644 index 0000000000..b7e55976eb --- /dev/null +++ b/src/main/java/com/ning/org/jboss/netty/util/internal/StringUtil.java @@ -0,0 +1,73 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package com.ning.org.jboss.netty.util.internal; + +import java.util.ArrayList; +import java.util.List; + +/** + * String utility class. + */ +public final class StringUtil { + + private StringUtil() { + // Unused. + } + + private static final String EMPTY_STRING = ""; + + /** + * Splits the specified {@link String} with the specified delimiter. This operation is a simplified and optimized + * version of {@link String#split(String)}. + */ + public static String[] split(String value, char delim) { + final int end = value.length(); + final List res = new ArrayList(); + + int start = 0; + for (int i = 0; i < end; i ++) { + if (value.charAt(i) == delim) { + if (start == i) { + res.add(EMPTY_STRING); + } else { + res.add(value.substring(start, i)); + } + start = i + 1; + } + } + + if (start == 0) { // If no delimiter was found in the value + res.add(value); + } else { + if (start != end) { + // Add the last element if it's not empty. + res.add(value.substring(start, end)); + } else { + // Truncate trailing empty elements. + for (int i = res.size() - 1; i >= 0; i --) { + if (res.get(i).length() == 0) { + res.remove(i); + } else { + break; + } + } + } + } + + return res.toArray(new String[res.size()]); + } +} + diff --git a/src/test/java/com/ning/org/jboss/netty/handler/codec/http/CookieDecoderTest.java b/src/test/java/com/ning/org/jboss/netty/handler/codec/http/CookieDecoderTest.java new file mode 100644 index 0000000000..5d2f9cb09b --- /dev/null +++ b/src/test/java/com/ning/org/jboss/netty/handler/codec/http/CookieDecoderTest.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2010-2012 Sonatype, Inc. All rights reserved. + * + * This program is licensed to you under the Apache License Version 2.0, + * and you may not use this file except in compliance with the Apache License Version 2.0. + * You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the Apache License Version 2.0 is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under. + */ +package com.ning.org.jboss.netty.handler.codec.http; + +import java.util.Set; + +import org.testng.Assert; +import org.testng.annotations.Test; + +import com.ning.http.client.Cookie; + +public class CookieDecoderTest { + + @Test(groups = "fast") + public void testDecodeUnquoted() { + Set cookies = CookieDecoder.decode("foo=value; domain=/; path=/"); + Assert.assertEquals(cookies.size(), 1); + + Cookie first = cookies.iterator().next(); + Assert.assertEquals(first.getValue(), "value"); + Assert.assertEquals(first.getDomain(), "/"); + Assert.assertEquals(first.getPath(), "/"); + } + + @Test(groups = "fast") + public void testDecodeQuoted() { + Set cookies = CookieDecoder.decode("ALPHA=\"VALUE1\"; Domain=docs.foo.com; Path=/accounts; Expires=Wed, 13-Jan-2021 22:23:01 GMT; Secure; HttpOnly"); + Assert.assertEquals(cookies.size(), 1); + + Cookie first = cookies.iterator().next(); + Assert.assertEquals(first.getValue(), "VALUE1"); + } + + @Test(groups = "fast") + public void testDecodeQuotedContainingEscapedQuote() { + Set cookies = CookieDecoder.decode("ALPHA=\"VALUE1\\\"\"; Domain=docs.foo.com; Path=/accounts; Expires=Wed, 13-Jan-2021 22:23:01 GMT; Secure; HttpOnly"); + Assert.assertEquals(cookies.size(), 1); + + Cookie first = cookies.iterator().next(); + Assert.assertEquals(first.getValue(), "VALUE1\""); + } +} From 59348bfc53d1ab728cad4f99b4584a58a9c099d3 Mon Sep 17 00:00:00 2001 From: Ryan Lubke Date: Wed, 24 Apr 2013 23:56:55 -0700 Subject: [PATCH 104/264] Update to Grizzly 2.3.2. --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index be031e8cf5..bbc920c8ee 100644 --- a/pom.xml +++ b/pom.xml @@ -541,7 +541,7 @@ org.glassfish.grizzly grizzly-websockets - 2.3.2-SNAPSHOT + 2.3.2 true From 9e7fb384118e21c36363988578240ad1f250c42e Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 25 Apr 2013 11:48:03 +0200 Subject: [PATCH 105/264] Revive obsolete methods, deprecate them instead --- .../java/com/ning/http/client/Cookie.java | 59 +++++++++---------- 1 file changed, 29 insertions(+), 30 deletions(-) diff --git a/src/main/java/com/ning/http/client/Cookie.java b/src/main/java/com/ning/http/client/Cookie.java index f9c6cb2362..3e766b0cf5 100644 --- a/src/main/java/com/ning/http/client/Cookie.java +++ b/src/main/java/com/ning/http/client/Cookie.java @@ -20,7 +20,7 @@ import java.util.Set; import java.util.TreeSet; -public class Cookie implements Comparable{ +public class Cookie implements Comparable { private final String domain; private final String name; private final String value; @@ -160,7 +160,32 @@ public Set getPorts() { return unmodifiablePorts; } - private void setPorts(Iterable ports) { + @Deprecated + // to be removed + public void setPorts(int... ports) { + if (ports == null) { + throw new NullPointerException("ports"); + } + + int[] portsCopy = ports.clone(); + if (portsCopy.length == 0) { + unmodifiablePorts = this.ports = Collections.emptySet(); + } else { + Set newPorts = new TreeSet(); + for (int p : portsCopy) { + if (p <= 0 || p > 65535) { + throw new IllegalArgumentException("port out of range: " + p); + } + newPorts.add(Integer.valueOf(p)); + } + this.ports = newPorts; + unmodifiablePorts = null; + } + } + + @Deprecated + // to become private + public void setPorts(Iterable ports) { Set newPorts = new TreeSet(); for (int p : ports) { if (p <= 0 || p > 65535) { @@ -178,34 +203,8 @@ private void setPorts(Iterable ports) { @Override public String toString() { - StringBuilder buf = new StringBuilder(); - buf.append(getName()); - buf.append('='); - buf.append(getValue()); - if (getDomain() != null) { - buf.append("; domain="); - buf.append(getDomain()); - } - if (getPath() != null) { - buf.append("; path="); - buf.append(getPath()); - } - if (getComment() != null) { - buf.append("; comment="); - buf.append(getComment()); - } - if (getMaxAge() >= 0) { - buf.append("; maxAge="); - buf.append(getMaxAge()); - buf.append('s'); - } - if (isSecure()) { - buf.append("; secure"); - } - if (isHttpOnly()) { - buf.append("; HTTPOnly"); - } - return buf.toString(); + return String.format("Cookie: domain=%s, name=%s, value=%s, path=%s, maxAge=%d, secure=%s", + domain, name, value, path, maxAge, secure); } private String validateValue(String name, String value) { From c640c570c16aceb4ae0914247ec8f55cfd56767b Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 25 Apr 2013 12:12:25 +0200 Subject: [PATCH 106/264] Revive previous maxAge default value -1 --- .../ning/org/jboss/netty/handler/codec/http/CookieDecoder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/ning/org/jboss/netty/handler/codec/http/CookieDecoder.java b/src/main/java/com/ning/org/jboss/netty/handler/codec/http/CookieDecoder.java index 15cbfe22e5..138e3ac0ab 100644 --- a/src/main/java/com/ning/org/jboss/netty/handler/codec/http/CookieDecoder.java +++ b/src/main/java/com/ning/org/jboss/netty/handler/codec/http/CookieDecoder.java @@ -113,7 +113,7 @@ public static Set decode(String header) { String commentURL = null; String domain = null; String path = null; - int maxAge = Integer.MIN_VALUE; + int maxAge = -1; List ports = Collections.emptyList(); for (int j = i + 1; j < names.size(); j++, i++) { From 38704f14aa727be8b70aae421cc68e63431e878a Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 25 Apr 2013 13:44:20 +0200 Subject: [PATCH 107/264] Fix and optimize Netty ResponseBodyParts bytes[], close #287 --- .../providers/netty/ChannelBufferUtil.java | 35 +++++++++++++++++++ .../client/providers/netty/NettyResponse.java | 2 +- .../providers/netty/ResponseBodyPart.java | 5 ++- .../client/providers/netty/WebSocketUtil.java | 1 - 4 files changed, 38 insertions(+), 5 deletions(-) create mode 100644 src/main/java/com/ning/http/client/providers/netty/ChannelBufferUtil.java diff --git a/src/main/java/com/ning/http/client/providers/netty/ChannelBufferUtil.java b/src/main/java/com/ning/http/client/providers/netty/ChannelBufferUtil.java new file mode 100644 index 0000000000..e2707f6dfe --- /dev/null +++ b/src/main/java/com/ning/http/client/providers/netty/ChannelBufferUtil.java @@ -0,0 +1,35 @@ +/* + * Copyright 2010 Ning, Inc. + * + * Ning licenses this file to you under the Apache License, version 2.0 + * (the "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package com.ning.http.client.providers.netty; + +import org.jboss.netty.buffer.ChannelBuffer; + +public class ChannelBufferUtil { + + public static byte[] channelBuffer2bytes(ChannelBuffer b) { + int readable = b.readableBytes(); + int readerIndex = b.readerIndex(); + if (b.hasArray()) { + byte[] array = b.array(); + if (b.arrayOffset() == 0 && readerIndex == 0 && array.length == readable) { + return array; + } + } + byte[] array = new byte[readable]; + b.getBytes(readerIndex, array); + return array; + } +} diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyResponse.java b/src/main/java/com/ning/http/client/providers/netty/NettyResponse.java index 3758d2b3cc..4269bb7187 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyResponse.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyResponse.java @@ -76,7 +76,7 @@ public String getStatusText() { /* @Override */ public byte[] getResponseBodyAsBytes() throws IOException { - return getResponseBodyAsByteBuffer().array(); + return ChannelBufferUtil.channelBuffer2bytes(getResponseBodyAsChannelBuffer()); } public ByteBuffer getResponseBodyAsByteBuffer() throws IOException { diff --git a/src/main/java/com/ning/http/client/providers/netty/ResponseBodyPart.java b/src/main/java/com/ning/http/client/providers/netty/ResponseBodyPart.java index adc744716d..6ed8abc945 100644 --- a/src/main/java/com/ning/http/client/providers/netty/ResponseBodyPart.java +++ b/src/main/java/com/ning/http/client/providers/netty/ResponseBodyPart.java @@ -34,7 +34,7 @@ public class ResponseBodyPart extends HttpResponseBodyPart { private final HttpChunk chunk; private final HttpResponse response; - private final AtomicReference bytes = new AtomicReference(null); + private final AtomicReference bytes = new AtomicReference(null); private final boolean isLast; private boolean closeConnection = false; @@ -63,8 +63,7 @@ public byte[] getBodyPartBytes() { return bytes.get(); } - ChannelBuffer b = getChannelBuffer(); - byte[] rb = b.toByteBuffer().array(); + byte[] rb = ChannelBufferUtil.channelBuffer2bytes(getChannelBuffer()); bytes.set(rb); return rb; } diff --git a/src/main/java/com/ning/http/client/providers/netty/WebSocketUtil.java b/src/main/java/com/ning/http/client/providers/netty/WebSocketUtil.java index c2a452e66f..5e20a499cf 100644 --- a/src/main/java/com/ning/http/client/providers/netty/WebSocketUtil.java +++ b/src/main/java/com/ning/http/client/providers/netty/WebSocketUtil.java @@ -13,7 +13,6 @@ package com.ning.http.client.providers.netty; import com.ning.http.util.Base64; -import org.jboss.netty.util.CharsetUtil; import java.io.UnsupportedEncodingException; import java.security.MessageDigest; From 5995a7d4d5f2b8582bcc2975cedd0498926564b4 Mon Sep 17 00:00:00 2001 From: Ryan Lubke Date: Thu, 25 Apr 2013 09:24:44 -0700 Subject: [PATCH 108/264] Fix my integration goof. --- .../client/providers/grizzly/GrizzlyAsyncHttpProvider.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java index f758ca98d2..7b241cbf5c 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java @@ -64,6 +64,7 @@ import org.glassfish.grizzly.attributes.Attribute; import org.glassfish.grizzly.attributes.AttributeStorage; import org.glassfish.grizzly.filterchain.BaseFilter; +import org.glassfish.grizzly.filterchain.FilterChain; import org.glassfish.grizzly.filterchain.FilterChainBuilder; import org.glassfish.grizzly.filterchain.FilterChainContext; import org.glassfish.grizzly.filterchain.FilterChainEvent; @@ -2508,6 +2509,11 @@ public NextAction handleWrite(FilterChainContext ctx) throws IOException { } + @Override + public void onFilterChainChanged(FilterChain filterChain) { + // no-op + } + // ----------------------------------------------------- Private Methods From fe28c77b0904f3fccc9965bb6ee9b65700a05fb2 Mon Sep 17 00:00:00 2001 From: jfarcand Date: Thu, 25 Apr 2013 18:11:08 -0400 Subject: [PATCH 109/264] [maven-release-plugin] prepare release async-http-client-1.7.14 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index bbc920c8ee..002ed08026 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.7.14-SNAPSHOT + 1.7.14 jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From a346e8e55981b434a3c331bba17c289806579527 Mon Sep 17 00:00:00 2001 From: jfarcand Date: Thu, 25 Apr 2013 18:11:17 -0400 Subject: [PATCH 110/264] [maven-release-plugin] prepare for next development iteration --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 002ed08026..d967083b96 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.7.14 + 1.7.15-SNAPSHOT jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From 84917f8f72da9df4634328c2e2b25651be0bcc4b Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 1 May 2013 13:15:54 +0200 Subject: [PATCH 111/264] Add another public constructor to NettyConnectionsPool that doesn't depend on NettyAsyncHttpProvider, close #289 --- .../client/providers/netty/NettyConnectionsPool.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyConnectionsPool.java b/src/main/java/com/ning/http/client/providers/netty/NettyConnectionsPool.java index ca8dc9bc74..43c788e4a5 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyConnectionsPool.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyConnectionsPool.java @@ -42,10 +42,14 @@ public class NettyConnectionsPool implements ConnectionsPool { private final long maxIdleTime; public NettyConnectionsPool(NettyAsyncHttpProvider provider) { - this.maxTotalConnections = provider.getConfig().getMaxTotalConnections(); - this.maxConnectionPerHost = provider.getConfig().getMaxConnectionPerHost(); - this.sslConnectionPoolEnabled = provider.getConfig().isSslConnectionPoolEnabled(); - this.maxIdleTime = provider.getConfig().getIdleConnectionInPoolTimeoutInMs(); + this(provider.getConfig().getMaxTotalConnections(), provider.getConfig().getMaxConnectionPerHost(), provider.getConfig().getIdleConnectionInPoolTimeoutInMs(), provider.getConfig().isSslConnectionPoolEnabled()); + } + + public NettyConnectionsPool(int maxTotalConnections, int maxConnectionPerHost, long maxIdleTime, boolean sslConnectionPoolEnabled) { + this.maxTotalConnections = maxTotalConnections; + this.maxConnectionPerHost = maxConnectionPerHost; + this.sslConnectionPoolEnabled = sslConnectionPoolEnabled; + this.maxIdleTime = maxIdleTime; this.idleConnectionDetector.schedule(new IdleChannelDetector(), maxIdleTime, maxIdleTime); } From 32c9945b330115f9aaaa7c6c69c9de1538ddba90 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 1 May 2013 13:26:57 +0200 Subject: [PATCH 112/264] Don't use System.currentTimeMillis, close #280 --- src/main/java/com/ning/http/client/Realm.java | 3 ++- .../java/com/ning/http/client/ntlm/NTLMEngine.java | 3 ++- .../http/client/oauth/OAuthSignatureCalculator.java | 5 +++-- .../client/providers/apache/ApacheResponseFuture.java | 10 ++++++---- .../providers/grizzly/GrizzlyAsyncHttpProvider.java | 5 +++-- .../providers/grizzly/GrizzlyConnectionsPool.java | 6 ++++-- .../http/client/providers/jdk/JDKDelegateFuture.java | 4 +++- .../com/ning/http/client/providers/jdk/JDKFuture.java | 10 ++++++---- .../client/providers/netty/NettyConnectionsPool.java | 10 ++++++---- .../client/providers/netty/NettyResponseFuture.java | 10 ++++++---- .../com/ning/http/util/AsyncHttpProviderUtils.java | 4 +++- src/main/java/com/ning/http/util/DateUtil.java | 3 +++ .../http/client/async/AsyncProvidersBasicTest.java | 5 +++-- .../ning/http/client/async/PerRequestTimeoutTest.java | 6 ++++-- .../client/providers/netty/NettyAsyncResponseTest.java | 4 +++- 15 files changed, 57 insertions(+), 31 deletions(-) diff --git a/src/main/java/com/ning/http/client/Realm.java b/src/main/java/com/ning/http/client/Realm.java index 8e68142c98..c15eacb080 100644 --- a/src/main/java/com/ning/http/client/Realm.java +++ b/src/main/java/com/ning/http/client/Realm.java @@ -16,6 +16,7 @@ */ package com.ning.http.client; +import static com.ning.http.util.DateUtil.millisTime; import static com.ning.http.util.MiscUtil.isNonEmpty; import org.slf4j.Logger; @@ -475,7 +476,7 @@ public RealmBuilder clone(Realm clone) { private void newCnonce() { try { MessageDigest md = MessageDigest.getInstance("MD5"); - byte[] b = md.digest(String.valueOf(System.currentTimeMillis()).getBytes("ISO-8859-1")); + byte[] b = md.digest(String.valueOf(millisTime()).getBytes("ISO-8859-1")); cnonce = toHexString(b); } catch (Exception e) { throw new SecurityException(e); diff --git a/src/main/java/com/ning/http/client/ntlm/NTLMEngine.java b/src/main/java/com/ning/http/client/ntlm/NTLMEngine.java index 00023369ef..cc84e89f05 100644 --- a/src/main/java/com/ning/http/client/ntlm/NTLMEngine.java +++ b/src/main/java/com/ning/http/client/ntlm/NTLMEngine.java @@ -38,6 +38,7 @@ package com.ning.http.client.ntlm; +import static com.ning.http.util.DateUtil.millisTime; import static com.ning.http.util.MiscUtil.isNonEmpty; import java.io.UnsupportedEncodingException; @@ -516,7 +517,7 @@ private static byte[] createBlob(byte[] clientChallenge, byte[] targetInformatio byte[] blobSignature = new byte[]{(byte) 0x01, (byte) 0x01, (byte) 0x00, (byte) 0x00}; byte[] reserved = new byte[]{(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00}; byte[] unknown1 = new byte[]{(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00}; - long time = System.currentTimeMillis(); + long time = millisTime(); time += 11644473600000l; // milliseconds from January 1, 1601 -> epoch. time *= 10000; // tenths of a microsecond. // convert to little-endian byte array. diff --git a/src/main/java/com/ning/http/client/oauth/OAuthSignatureCalculator.java b/src/main/java/com/ning/http/client/oauth/OAuthSignatureCalculator.java index e33ad87c73..98d4105e09 100644 --- a/src/main/java/com/ning/http/client/oauth/OAuthSignatureCalculator.java +++ b/src/main/java/com/ning/http/client/oauth/OAuthSignatureCalculator.java @@ -16,6 +16,7 @@ */ package com.ning.http.client.oauth; +import static com.ning.http.util.DateUtil.millisTime; import com.ning.http.client.FluentStringsMap; import com.ning.http.client.Request; @@ -78,7 +79,7 @@ public OAuthSignatureCalculator(ConsumerKey consumerAuth, RequestToken userAuth) mac = new ThreadSafeHMAC(consumerAuth, userAuth); this.consumerAuth = consumerAuth; this.userAuth = userAuth; - random = new Random(System.identityHashCode(this) + System.currentTimeMillis()); + random = new Random(System.identityHashCode(this) + millisTime()); } //@Override // silly 1.5; doesn't allow this for interfaces @@ -86,7 +87,7 @@ public OAuthSignatureCalculator(ConsumerKey consumerAuth, RequestToken userAuth) public void calculateAndAddSignature(String baseURL, Request request, RequestBuilderBase requestBuilder) { String method = request.getMethod(); // POST etc String nonce = generateNonce(); - long timestamp = System.currentTimeMillis() / 1000L; + long timestamp = millisTime() / 1000L; String signature = calculateSignature(method, baseURL, timestamp, nonce, request.getParams(), request.getQueryParams()); String headerValue = constructAuthHeader(signature, nonce, timestamp); requestBuilder.setHeader(HEADER_AUTHORIZATION, headerValue); diff --git a/src/main/java/com/ning/http/client/providers/apache/ApacheResponseFuture.java b/src/main/java/com/ning/http/client/providers/apache/ApacheResponseFuture.java index 0b8abff3e9..67706fbea6 100644 --- a/src/main/java/com/ning/http/client/providers/apache/ApacheResponseFuture.java +++ b/src/main/java/com/ning/http/client/providers/apache/ApacheResponseFuture.java @@ -12,6 +12,8 @@ */ package com.ning.http.client.providers.apache; +import static com.ning.http.util.DateUtil.millisTime; + import com.ning.http.client.AsyncHandler; import com.ning.http.client.Request; import com.ning.http.client.listenable.AbstractListenableFuture; @@ -41,7 +43,7 @@ public class ApacheResponseFuture extends AbstractListenableFuture { private final AtomicBoolean timedOut = new AtomicBoolean(false); private final AtomicBoolean isDone = new AtomicBoolean(false); private final AtomicReference exception = new AtomicReference(); - private final AtomicLong touch = new AtomicLong(System.currentTimeMillis()); + private final AtomicLong touch = new AtomicLong(millisTime()); private final AtomicBoolean contentProcessed = new AtomicBoolean(false); private final Request request; private final HttpMethodBase method; @@ -174,7 +176,7 @@ public V get(long timeout, TimeUnit unit) throws InterruptedException, Execution content = innerFuture.get(timeout, unit); } } catch (TimeoutException t) { - if (!contentProcessed.get() && timeout != -1 && ((System.currentTimeMillis() - touch.get()) <= responseTimeoutInMs)) { + if (!contentProcessed.get() && timeout != -1 && ((millisTime() - touch.get()) <= responseTimeoutInMs)) { return get(timeout, unit); } @@ -197,11 +199,11 @@ public V get(long timeout, TimeUnit unit) throws InterruptedException, Execution * @return true if response has expired and should be terminated. */ public boolean hasExpired() { - return responseTimeoutInMs != -1 && ((System.currentTimeMillis() - touch.get()) >= responseTimeoutInMs); + return responseTimeoutInMs != -1 && ((millisTime() - touch.get()) >= responseTimeoutInMs); } public void touch() { - touch.set(System.currentTimeMillis()); + touch.set(millisTime()); } public Request getRequest() { diff --git a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java index 7b241cbf5c..63f494946d 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java @@ -13,6 +13,7 @@ package com.ning.http.client.providers.grizzly; +import static com.ning.http.util.DateUtil.millisTime; import static com.ning.http.util.MiscUtil.isNonEmpty; import com.ning.org.jboss.netty.handler.codec.http.CookieDecoder; @@ -427,7 +428,7 @@ void touchConnection(final Connection c, final Request request) { if (config != null) { final long timeout = config.getRequestTimeoutInMs(); if (timeout > 0) { - final long newTimeout = System.currentTimeMillis() + timeout; + final long newTimeout = millisTime() + timeout; if (resolver != null) { resolver.setTimeoutMillis(c, newTimeout); } @@ -436,7 +437,7 @@ void touchConnection(final Connection c, final Request request) { final long timeout = clientConfig.getRequestTimeoutInMs(); if (timeout > 0) { if (resolver != null) { - resolver.setTimeoutMillis(c, System.currentTimeMillis() + timeout); + resolver.setTimeoutMillis(c, millisTime() + timeout); } } } diff --git a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyConnectionsPool.java b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyConnectionsPool.java index e3478e5769..00c7c46bc5 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyConnectionsPool.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyConnectionsPool.java @@ -13,6 +13,8 @@ package com.ning.http.client.providers.grizzly; +import static com.ning.http.util.DateUtil.millisTime; + import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.ConnectionsPool; @@ -310,7 +312,7 @@ private class DelayedRunnable implements Runnable { @Override public void run() { while (isStarted) { - final long currentTimeMs = System.currentTimeMillis(); + final long currentTimeMs = millisTime(); for (final IdleConnectionQueue delayQueue : queues) { if (delayQueue.queue.isEmpty()) continue; @@ -381,7 +383,7 @@ public IdleConnectionQueue(final long timeout) { void offer(final Connection c) { if (timeout >= 0) { - resolver.setTimeoutMs(c, System.currentTimeMillis() + timeout); + resolver.setTimeoutMs(c, millisTime() + timeout); } queue.offer(c); count.incrementAndGet(); diff --git a/src/main/java/com/ning/http/client/providers/jdk/JDKDelegateFuture.java b/src/main/java/com/ning/http/client/providers/jdk/JDKDelegateFuture.java index 9553e02152..0791a4a567 100644 --- a/src/main/java/com/ning/http/client/providers/jdk/JDKDelegateFuture.java +++ b/src/main/java/com/ning/http/client/providers/jdk/JDKDelegateFuture.java @@ -12,6 +12,8 @@ */ package com.ning.http.client.providers.jdk; +import static com.ning.http.util.DateUtil.millisTime; + import com.ning.http.client.AsyncHandler; import com.ning.http.client.ListenableFuture; @@ -66,7 +68,7 @@ public V get(long timeout, TimeUnit unit) throws InterruptedException, Execution content = innerFuture.get(timeout, unit); } } catch (Throwable t) { - if (!contentProcessed.get() && timeout != -1 && ((System.currentTimeMillis() - touch.get()) <= responseTimeoutInMs)) { + if (!contentProcessed.get() && timeout != -1 && ((millisTime() - touch.get()) <= responseTimeoutInMs)) { return get(timeout, unit); } timedOut.set(true); diff --git a/src/main/java/com/ning/http/client/providers/jdk/JDKFuture.java b/src/main/java/com/ning/http/client/providers/jdk/JDKFuture.java index 4666459dc9..e029183f53 100644 --- a/src/main/java/com/ning/http/client/providers/jdk/JDKFuture.java +++ b/src/main/java/com/ning/http/client/providers/jdk/JDKFuture.java @@ -12,6 +12,8 @@ */ package com.ning.http.client.providers.jdk; +import static com.ning.http.util.DateUtil.millisTime; + import com.ning.http.client.AsyncHandler; import com.ning.http.client.listenable.AbstractListenableFuture; import org.slf4j.Logger; @@ -40,7 +42,7 @@ public class JDKFuture extends AbstractListenableFuture { protected final AtomicBoolean timedOut = new AtomicBoolean(false); protected final AtomicBoolean isDone = new AtomicBoolean(false); protected final AtomicReference exception = new AtomicReference(); - protected final AtomicLong touch = new AtomicLong(System.currentTimeMillis()); + protected final AtomicLong touch = new AtomicLong(millisTime()); protected final AtomicBoolean contentProcessed = new AtomicBoolean(false); protected final HttpURLConnection urlConnection; private boolean writeHeaders; @@ -126,7 +128,7 @@ public V get(long timeout, TimeUnit unit) throws InterruptedException, Execution content = innerFuture.get(timeout, unit); } } catch (TimeoutException t) { - if (!contentProcessed.get() && timeout != -1 && ((System.currentTimeMillis() - touch.get()) <= responseTimeoutInMs)) { + if (!contentProcessed.get() && timeout != -1 && ((millisTime() - touch.get()) <= responseTimeoutInMs)) { return get(timeout, unit); } @@ -149,7 +151,7 @@ public V get(long timeout, TimeUnit unit) throws InterruptedException, Execution * @return true if response has expired and should be terminated. */ public boolean hasExpired() { - return responseTimeoutInMs != -1 && ((System.currentTimeMillis() - touch.get()) > responseTimeoutInMs); + return responseTimeoutInMs != -1 && ((millisTime() - touch.get()) > responseTimeoutInMs); } /** @@ -157,7 +159,7 @@ public boolean hasExpired() { */ /* @Override */ public void touch() { - touch.set(System.currentTimeMillis()); + touch.set(millisTime()); } /** diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyConnectionsPool.java b/src/main/java/com/ning/http/client/providers/netty/NettyConnectionsPool.java index 43c788e4a5..2c232fb2a9 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyConnectionsPool.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyConnectionsPool.java @@ -12,6 +12,8 @@ */ package com.ning.http.client.providers.netty; +import static com.ning.http.util.DateUtil.millisTime; + import com.ning.http.client.ConnectionsPool; import org.jboss.netty.channel.Channel; import org.slf4j.Logger; @@ -61,7 +63,7 @@ private static class IdleChannel { IdleChannel(String uri, Channel channel) { this.uri = uri; this.channel = channel; - this.start = System.currentTimeMillis(); + this.start = millisTime(); } @Override @@ -97,7 +99,7 @@ public void run() { } List channelsInTimeout = new ArrayList(); - long currentTime = System.currentTimeMillis(); + long currentTime = millisTime(); for (IdleChannel idleChannel : channel2IdleChannel.values()) { long age = currentTime - idleChannel.start; @@ -109,7 +111,7 @@ public void run() { channelsInTimeout.add(idleChannel); } } - long endConcurrentLoop = System.currentTimeMillis(); + long endConcurrentLoop = millisTime(); for (IdleChannel idleChannel : channelsInTimeout) { Object attachment = idleChannel.channel.getPipeline().getContext(NettyAsyncHttpProvider.class).getAttachment(); @@ -136,7 +138,7 @@ public void run() { openChannels += hostChannels.size(); } log.trace(String.format("%d channel open, %d idle channels closed (times: 1st-loop=%d, 2nd-loop=%d).\n", - openChannels, channelsInTimeout.size(), endConcurrentLoop - currentTime, System.currentTimeMillis() - endConcurrentLoop)); + openChannels, channelsInTimeout.size(), endConcurrentLoop - currentTime, millisTime() - endConcurrentLoop)); } } catch (Throwable t) { diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyResponseFuture.java b/src/main/java/com/ning/http/client/providers/netty/NettyResponseFuture.java index 560ed65e4f..dae8095c46 100755 --- a/src/main/java/com/ning/http/client/providers/netty/NettyResponseFuture.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyResponseFuture.java @@ -15,6 +15,8 @@ */ package com.ning.http.client.providers.netty; +import static com.ning.http.util.DateUtil.millisTime; + import com.ning.http.client.AsyncHandler; import com.ning.http.client.ConnectionPoolKeyStrategy; import com.ning.http.client.ProxyServer; @@ -74,8 +76,8 @@ enum STATE { private volatile Future reaperFuture; private final AtomicBoolean inAuth = new AtomicBoolean(false); private final AtomicBoolean statusReceived = new AtomicBoolean(false); - private final AtomicLong touch = new AtomicLong(System.currentTimeMillis()); - private final long start = System.currentTimeMillis(); + private final AtomicLong touch = new AtomicLong(millisTime()); + private final long start = millisTime(); private final NettyAsyncHttpProvider asyncHttpProvider; private final AtomicReference state = new AtomicReference(STATE.NEW); private final AtomicBoolean contentProcessed = new AtomicBoolean(false); @@ -189,7 +191,7 @@ public boolean cancel(boolean force) { * @return true if response has expired and should be terminated. */ public boolean hasExpired() { - long now = System.currentTimeMillis(); + long now = millisTime(); return idleConnectionTimeoutInMs != -1 && ((now - touch.get()) >= idleConnectionTimeoutInMs) || responseTimeoutInMs != -1 && ((now - start) >= responseTimeoutInMs); } @@ -408,7 +410,7 @@ public boolean getAndSetStatusReceived(boolean sr) { */ /* @Override */ public void touch() { - touch.set(System.currentTimeMillis()); + touch.set(millisTime()); } /** diff --git a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java index 60b9379664..265a9c6fcc 100644 --- a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java +++ b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java @@ -12,6 +12,8 @@ */ package com.ning.http.util; +import static com.ning.http.util.DateUtil.millisTime; + import java.io.ByteArrayInputStream; import java.io.FileNotFoundException; import java.io.IOException; @@ -467,7 +469,7 @@ public static Cookie parseCookie(String value) { public static int convertExpireField(String timestring) { String trimmedTimeString = removeQuote(timestring.trim()); - long now = System.currentTimeMillis(); + long now = millisTime(); Date date = null; for (SimpleDateFormat sdf : simpleDateFormat.get()) { diff --git a/src/main/java/com/ning/http/util/DateUtil.java b/src/main/java/com/ning/http/util/DateUtil.java index 54def8d8c1..8e5e3fe6fe 100644 --- a/src/main/java/com/ning/http/util/DateUtil.java +++ b/src/main/java/com/ning/http/util/DateUtil.java @@ -231,4 +231,7 @@ public DateParseException(String message) { } + public static long millisTime() { + return System.nanoTime() / 1000000; + } } diff --git a/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java b/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java index d117458f74..eb6bb5eda5 100755 --- a/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java +++ b/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java @@ -15,6 +15,7 @@ */ package com.ning.http.client.async; +import static com.ning.http.util.DateUtil.millisTime; import static com.ning.http.util.MiscUtil.isNonEmpty; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNull; @@ -1591,7 +1592,7 @@ public void idleRequestTimeoutTest() throws Exception { h.add("Content-Type", "application/x-www-form-urlencoded"); h.add("LockThread", "true"); - long t1 = System.currentTimeMillis(); + long t1 = millisTime(); try { client.prepareGet(getTargetUrl()).setHeaders(h).setUrl(getTargetUrl()).execute(new AsyncHandlerAdapter() { @@ -1603,7 +1604,7 @@ public void onThrowable(Throwable t) { }).get(); Assert.fail(); } catch (Throwable ex) { - final long elapsedTime = System.currentTimeMillis() - t1; + final long elapsedTime = millisTime() - t1; System.out.println("EXPIRED: " + (elapsedTime)); Assert.assertNotNull(ex.getCause()); Assert.assertTrue(elapsedTime >= 10000 && elapsedTime <= 25000); diff --git a/src/test/java/com/ning/http/client/async/PerRequestTimeoutTest.java b/src/test/java/com/ning/http/client/async/PerRequestTimeoutTest.java index 72de9b9930..22655effcb 100644 --- a/src/test/java/com/ning/http/client/async/PerRequestTimeoutTest.java +++ b/src/test/java/com/ning/http/client/async/PerRequestTimeoutTest.java @@ -15,6 +15,8 @@ */ package com.ning.http.client.async; +import static com.ning.http.util.DateUtil.millisTime; + import com.ning.http.client.AsyncCompletionHandler; import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClientConfig; @@ -171,13 +173,13 @@ public Response onCompleted(Response response) throws Exception { @Override public STATE onBodyPartReceived(HttpResponseBodyPart content) throws Exception { - times[0] = System.currentTimeMillis(); + times[0] = millisTime(); return super.onBodyPartReceived(content); } @Override public void onThrowable(Throwable t) { - times[1] = System.currentTimeMillis(); + times[1] = millisTime(); super.onThrowable(t); } }); diff --git a/src/test/java/com/ning/http/client/providers/netty/NettyAsyncResponseTest.java b/src/test/java/com/ning/http/client/providers/netty/NettyAsyncResponseTest.java index c49eee8dc2..65cddcd89b 100644 --- a/src/test/java/com/ning/http/client/providers/netty/NettyAsyncResponseTest.java +++ b/src/test/java/com/ning/http/client/providers/netty/NettyAsyncResponseTest.java @@ -13,6 +13,8 @@ package com.ning.http.client.providers.netty; +import static com.ning.http.util.DateUtil.millisTime; + import com.ning.http.client.Cookie; import com.ning.http.client.FluentCaseInsensitiveStringsMap; import com.ning.http.client.HttpResponseHeaders; @@ -38,7 +40,7 @@ public void testCookieParseExpires() { SimpleDateFormat sdf = new SimpleDateFormat("EEE, dd-MMM-yyyy HH:mm:ss z", Locale.US); sdf.setTimeZone(TimeZone.getTimeZone("GMT")); - Date date = new Date(System.currentTimeMillis() + 60000); // sdf.parse( dateString ); + Date date = new Date(millisTime() + 60000); // sdf.parse( dateString ); final String cookieDef = String.format("efmembercheck=true; expires=%s; path=/; domain=.eclipse.org", sdf.format(date)); NettyResponse response = new NettyResponse(new ResponseStatus(null, null, null), new HttpResponseHeaders(null, null, false) { From 74b6b0f8b5d970f70fc28314fd947280cd7ed9ec Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 1 May 2013 14:19:26 +0200 Subject: [PATCH 113/264] Prevent file description leak on ClosedChannelException, close #288 --- .../providers/netty/NettyAsyncHttpProvider.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java index 9cc75a946f..ade1a85e66 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java @@ -530,7 +530,16 @@ protected final void writeRequest(final Channel channel, final FileRegion region = new OptimizedFileRegion(raf, 0, fileLength); writeFuture = channel.write(region); } - writeFuture.addListener(new ProgressListener(false, future.getAsyncHandler(), future)); + writeFuture.addListener(new ProgressListener(false, future.getAsyncHandler(), future) { + public void operationComplete(ChannelFuture cf) { + try { + raf.close(); + } catch (IOException e) { + log.warn("Failed to close request body: {}", e.getMessage(), e); + } + super.operationComplete(cf); + } + }); } catch (IOException ex) { if (raf != null) { try { From b51442c6c4a1740ceba0d60cb429b0e5cf6f227d Mon Sep 17 00:00:00 2001 From: jfarcand Date: Wed, 1 May 2013 10:21:23 -0400 Subject: [PATCH 114/264] Improve Channel closing --- .../http/client/providers/netty/NettyWebSocket.java | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyWebSocket.java b/src/main/java/com/ning/http/client/providers/netty/NettyWebSocket.java index 2197ba01f4..b572dcf0f4 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyWebSocket.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyWebSocket.java @@ -18,6 +18,7 @@ import com.ning.http.client.websocket.WebSocketListener; import com.ning.http.client.websocket.WebSocketTextListener; import org.jboss.netty.channel.Channel; +import org.jboss.netty.channel.ChannelFutureListener; import org.jboss.netty.handler.codec.http.websocketx.BinaryWebSocketFrame; import org.jboss.netty.handler.codec.http.websocketx.CloseWebSocketFrame; import org.jboss.netty.handler.codec.http.websocketx.PingWebSocketFrame; @@ -114,13 +115,10 @@ public boolean isOpen() { // @Override public void close() { - onClose(); - listeners.clear(); - try { - channel.write(new CloseWebSocketFrame()); - channel.getCloseFuture().awaitUninterruptibly(); - } finally { - channel.close(); + if (channel.isOpen()) { + onClose(); + listeners.clear(); + channel.write(new CloseWebSocketFrame()).addListener(ChannelFutureListener.CLOSE); } } From 74a21dec9fd1c0dfadbd3c6e385eafcc9dd2f2ec Mon Sep 17 00:00:00 2001 From: jfarcand Date: Wed, 1 May 2013 10:29:17 -0400 Subject: [PATCH 115/264] Fixes #290 --- .../com/ning/http/client/AsyncHttpClient.java | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/ning/http/client/AsyncHttpClient.java b/src/main/java/com/ning/http/client/AsyncHttpClient.java index 99a6a7a4b4..b507e9defe 100755 --- a/src/main/java/com/ning/http/client/AsyncHttpClient.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClient.java @@ -30,6 +30,8 @@ import java.io.InputStream; import java.util.Collection; import java.util.Map; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.atomic.AtomicBoolean; @@ -370,11 +372,16 @@ public void close() { * Asynchronous close the {@link AsyncHttpProvider} by spawning a thread and avoid blocking. */ public void closeAsynchronously() { - config.applicationThreadPool.submit(new Runnable() { - + final ExecutorService e = Executors.newSingleThreadExecutor(); + e.submit(new Runnable() { public void run() { - httpProvider.close(); - isClosed.set(true); + try { + close(); + } catch (Throwable t) { + logger.warn("", t); + } finally { + e.shutdown(); + } } }); } From 154ebdcc6c0a8d372244f600b85bd1b6cc55aafa Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 1 May 2013 21:31:33 +0200 Subject: [PATCH 116/264] Support Location header with raw query, backport #268 --- .../http/util/AsyncHttpProviderUtils.java | 62 ++++++++++++++----- .../http/util/AsyncHttpProviderUtilsTest.java | 45 ++++++++++++++ 2 files changed, 91 insertions(+), 16 deletions(-) create mode 100644 src/test/java/com/ning/http/util/AsyncHttpProviderUtilsTest.java diff --git a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java index 265a9c6fcc..d96bb326d6 100644 --- a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java +++ b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java @@ -20,6 +20,7 @@ import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.net.URI; +import java.net.URISyntaxException; import java.text.ParsePosition; import java.text.SimpleDateFormat; import java.util.Collection; @@ -27,7 +28,6 @@ import java.util.List; import java.util.Locale; -import com.ning.org.jboss.netty.handler.codec.http.CookieDecoder; import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.AsyncHttpProvider; import com.ning.http.client.ByteArrayPart; @@ -41,6 +41,7 @@ import com.ning.http.multipart.ByteArrayPartSource; import com.ning.http.multipart.MultipartRequestEntity; import com.ning.http.multipart.PartSource; +import com.ning.org.jboss.netty.handler.codec.http.CookieDecoder; /** * {@link com.ning.http.client.AsyncHttpProvider} common utilities. @@ -231,22 +232,51 @@ public final static String getHost(URI uri) { } public final static URI getRedirectUri(URI uri, String location) { - if(location == null) - throw new IllegalArgumentException("URI " + uri + " was redirected to null location"); - URI newUri = uri.resolve(location); - - String scheme = newUri.getScheme(); - - if (scheme == null || !scheme.equalsIgnoreCase("http") - && !scheme.equalsIgnoreCase("https") - && !scheme.equals("ws") - && !scheme.equals("wss")) { - throw new IllegalArgumentException("The URI scheme, of the URI " + newUri - + ", must be equal (ignoring case) to 'ws, 'wss', 'http', or 'https'"); - } + if(location == null) + throw new IllegalArgumentException("URI " + uri + " was redirected to null location"); + + URI locationURI = null; + try { + locationURI = new URI(location); + } catch (URISyntaxException e) { + // rich, we have a badly encoded location, let's try to encode the query params + String[] parts = location.split("\\?"); + if (parts.length != 2) { + throw new IllegalArgumentException("Don't know how to turn this location into a proper URI:" + location, e); + } else { + StringBuilder properUrl = new StringBuilder(location.length()).append(parts[0]).append("?"); + + String[] queryParams = parts[1].split("&"); + for (int i = 0; i < queryParams.length; i++) { + String queryParam = queryParams[i]; + if (i != 0) + properUrl.append("&"); + String[] nameValue = queryParam.split("=", 2); + UTF8UrlEncoder.appendEncoded(properUrl, nameValue[0]); + if (nameValue.length == 2) { + properUrl.append("="); + UTF8UrlEncoder.appendEncoded(properUrl, nameValue[1]); + } + } + + locationURI = URI.create(properUrl.toString()); + } + } + + URI redirectUri = uri.resolve(locationURI); - return newUri; - } + String scheme = redirectUri.getScheme(); + + if (scheme == null || !scheme.equalsIgnoreCase("http") + && !scheme.equalsIgnoreCase("https") + && !scheme.equals("ws") + && !scheme.equals("wss")) { + throw new IllegalArgumentException("The URI scheme, of the URI " + redirectUri + + ", must be equal (ignoring case) to 'ws, 'wss', 'http', or 'https'"); + } + + return redirectUri; + } public final static int getPort(URI uri) { int port = uri.getPort(); diff --git a/src/test/java/com/ning/http/util/AsyncHttpProviderUtilsTest.java b/src/test/java/com/ning/http/util/AsyncHttpProviderUtilsTest.java new file mode 100644 index 0000000000..7a1bdd26c5 --- /dev/null +++ b/src/test/java/com/ning/http/util/AsyncHttpProviderUtilsTest.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2010-2012 Sonatype, Inc. All rights reserved. + * + * This program is licensed to you under the Apache License Version 2.0, + * and you may not use this file except in compliance with the Apache License Version 2.0. + * You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the Apache License Version 2.0 is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under. + */ +package com.ning.http.util; + +import java.net.URI; + +import org.testng.Assert; +import org.testng.annotations.Test; + +public class AsyncHttpProviderUtilsTest { + + @Test(groups = "fast") + public void getRedirectUriShouldHandleProperlyEncodedLocation() { + + String url = "http://www.ebay.de/sch/sis.html;jsessionid=92D73F80262E3EBED7E115ED01035DDA?_nkw=FSC%20Lifebook%20E8310%20Core2Duo%20T8100%202%201GHz%204GB%20DVD%20RW&_itemId=150731406505"; + URI uri = AsyncHttpProviderUtils.getRedirectUri(URI.create("http://www.ebay.de/"), url); + Assert.assertEquals("http://www.ebay.de/sch/sis.html;jsessionid=92D73F80262E3EBED7E115ED01035DDA?_nkw=FSC%20Lifebook%20E8310%20Core2Duo%20T8100%202%201GHz%204GB%20DVD%20RW&_itemId=150731406505", uri.toString()); + } + + @Test(groups = "fast") + public void getRedirectUriShouldHandleRawQueryParamsLocation() { + + String url = "http://www.ebay.de/sch/sis.html;jsessionid=92D73F80262E3EBED7E115ED01035DDA?_nkw=FSC%20Lifebook%20E8310%20Core2Duo%20T8100%202%201GHz%204GB%20DVD%20RW&_itemId=150731406505"; + URI uri = AsyncHttpProviderUtils.getRedirectUri(URI.create("http://www.ebay.de/"), url); + Assert.assertEquals("http://www.ebay.de/sch/sis.html;jsessionid=92D73F80262E3EBED7E115ED01035DDA?_nkw=FSC%20Lifebook%20E8310%20Core2Duo%20T8100%202%201GHz%204GB%20DVD%20RW&_itemId=150731406505", uri.toString()); + } + + @Test(groups = "fast") + public void getRedirectUriShouldHandleRelativeLocation() { + + String url = "/sch/sis.html;jsessionid=92D73F80262E3EBED7E115ED01035DDA?_nkw=FSC Lifebook E8310 Core2Duo T8100 2 1GHz 4GB DVD RW&_itemId=150731406505"; + URI uri = AsyncHttpProviderUtils.getRedirectUri(URI.create("http://www.ebay.de/"), url); + Assert.assertEquals("http://www.ebay.de/sch/sis.html;jsessionid=92D73F80262E3EBED7E115ED01035DDA?_nkw=FSC%20Lifebook%20E8310%20Core2Duo%20T8100%202%201GHz%204GB%20DVD%20RW&_itemId=150731406505", uri.toString()); + } +} \ No newline at end of file From 91fa1848833db49b6314a071295cda6972f82a85 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 1 May 2013 22:57:54 +0200 Subject: [PATCH 117/264] Remove Cookie extra constructors deprecation --- src/main/java/com/ning/http/client/Cookie.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/com/ning/http/client/Cookie.java b/src/main/java/com/ning/http/client/Cookie.java index 3e766b0cf5..de8773f744 100644 --- a/src/main/java/com/ning/http/client/Cookie.java +++ b/src/main/java/com/ning/http/client/Cookie.java @@ -36,12 +36,10 @@ public class Cookie implements Comparable { private Set ports = Collections.emptySet(); private Set unmodifiablePorts = ports; - @Deprecated public Cookie(String domain, String name, String value, String path, int maxAge, boolean secure) { this(domain, name, value, path, maxAge, secure, 1); } - @Deprecated public Cookie(String domain, String name, String value, String path, int maxAge, boolean secure, int version) { this(domain, name, value, path, maxAge, secure, version, false, false, null, null, Collections. emptySet()); } From 4b2886e4d20022538be7bd485e345eb70b56526b Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 2 May 2013 00:22:19 +0200 Subject: [PATCH 118/264] Revert back some invalid nanoTime usage, close #280 --- src/main/java/com/ning/http/client/Realm.java | 3 +-- src/main/java/com/ning/http/client/ntlm/NTLMEngine.java | 3 +-- .../ning/http/client/oauth/OAuthSignatureCalculator.java | 6 ++---- .../client/providers/grizzly/GrizzlyAsyncHttpProvider.java | 5 ++--- .../client/providers/grizzly/GrizzlyConnectionsPool.java | 6 ++---- .../java/com/ning/http/util/AsyncHttpProviderUtils.java | 4 +--- .../http/client/providers/netty/NettyAsyncResponseTest.java | 4 +--- 7 files changed, 10 insertions(+), 21 deletions(-) diff --git a/src/main/java/com/ning/http/client/Realm.java b/src/main/java/com/ning/http/client/Realm.java index c15eacb080..8e68142c98 100644 --- a/src/main/java/com/ning/http/client/Realm.java +++ b/src/main/java/com/ning/http/client/Realm.java @@ -16,7 +16,6 @@ */ package com.ning.http.client; -import static com.ning.http.util.DateUtil.millisTime; import static com.ning.http.util.MiscUtil.isNonEmpty; import org.slf4j.Logger; @@ -476,7 +475,7 @@ public RealmBuilder clone(Realm clone) { private void newCnonce() { try { MessageDigest md = MessageDigest.getInstance("MD5"); - byte[] b = md.digest(String.valueOf(millisTime()).getBytes("ISO-8859-1")); + byte[] b = md.digest(String.valueOf(System.currentTimeMillis()).getBytes("ISO-8859-1")); cnonce = toHexString(b); } catch (Exception e) { throw new SecurityException(e); diff --git a/src/main/java/com/ning/http/client/ntlm/NTLMEngine.java b/src/main/java/com/ning/http/client/ntlm/NTLMEngine.java index cc84e89f05..00023369ef 100644 --- a/src/main/java/com/ning/http/client/ntlm/NTLMEngine.java +++ b/src/main/java/com/ning/http/client/ntlm/NTLMEngine.java @@ -38,7 +38,6 @@ package com.ning.http.client.ntlm; -import static com.ning.http.util.DateUtil.millisTime; import static com.ning.http.util.MiscUtil.isNonEmpty; import java.io.UnsupportedEncodingException; @@ -517,7 +516,7 @@ private static byte[] createBlob(byte[] clientChallenge, byte[] targetInformatio byte[] blobSignature = new byte[]{(byte) 0x01, (byte) 0x01, (byte) 0x00, (byte) 0x00}; byte[] reserved = new byte[]{(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00}; byte[] unknown1 = new byte[]{(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00}; - long time = millisTime(); + long time = System.currentTimeMillis(); time += 11644473600000l; // milliseconds from January 1, 1601 -> epoch. time *= 10000; // tenths of a microsecond. // convert to little-endian byte array. diff --git a/src/main/java/com/ning/http/client/oauth/OAuthSignatureCalculator.java b/src/main/java/com/ning/http/client/oauth/OAuthSignatureCalculator.java index 98d4105e09..4e363745e0 100644 --- a/src/main/java/com/ning/http/client/oauth/OAuthSignatureCalculator.java +++ b/src/main/java/com/ning/http/client/oauth/OAuthSignatureCalculator.java @@ -16,8 +16,6 @@ */ package com.ning.http.client.oauth; -import static com.ning.http.util.DateUtil.millisTime; - import com.ning.http.client.FluentStringsMap; import com.ning.http.client.Request; import com.ning.http.client.RequestBuilderBase; @@ -79,7 +77,7 @@ public OAuthSignatureCalculator(ConsumerKey consumerAuth, RequestToken userAuth) mac = new ThreadSafeHMAC(consumerAuth, userAuth); this.consumerAuth = consumerAuth; this.userAuth = userAuth; - random = new Random(System.identityHashCode(this) + millisTime()); + random = new Random(System.identityHashCode(this) + System.currentTimeMillis()); } //@Override // silly 1.5; doesn't allow this for interfaces @@ -87,7 +85,7 @@ public OAuthSignatureCalculator(ConsumerKey consumerAuth, RequestToken userAuth) public void calculateAndAddSignature(String baseURL, Request request, RequestBuilderBase requestBuilder) { String method = request.getMethod(); // POST etc String nonce = generateNonce(); - long timestamp = millisTime() / 1000L; + long timestamp = System.currentTimeMillis() / 1000L; String signature = calculateSignature(method, baseURL, timestamp, nonce, request.getParams(), request.getQueryParams()); String headerValue = constructAuthHeader(signature, nonce, timestamp); requestBuilder.setHeader(HEADER_AUTHORIZATION, headerValue); diff --git a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java index 63f494946d..7b241cbf5c 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java @@ -13,7 +13,6 @@ package com.ning.http.client.providers.grizzly; -import static com.ning.http.util.DateUtil.millisTime; import static com.ning.http.util.MiscUtil.isNonEmpty; import com.ning.org.jboss.netty.handler.codec.http.CookieDecoder; @@ -428,7 +427,7 @@ void touchConnection(final Connection c, final Request request) { if (config != null) { final long timeout = config.getRequestTimeoutInMs(); if (timeout > 0) { - final long newTimeout = millisTime() + timeout; + final long newTimeout = System.currentTimeMillis() + timeout; if (resolver != null) { resolver.setTimeoutMillis(c, newTimeout); } @@ -437,7 +436,7 @@ void touchConnection(final Connection c, final Request request) { final long timeout = clientConfig.getRequestTimeoutInMs(); if (timeout > 0) { if (resolver != null) { - resolver.setTimeoutMillis(c, millisTime() + timeout); + resolver.setTimeoutMillis(c, System.currentTimeMillis() + timeout); } } } diff --git a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyConnectionsPool.java b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyConnectionsPool.java index 00c7c46bc5..e3478e5769 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyConnectionsPool.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyConnectionsPool.java @@ -13,8 +13,6 @@ package com.ning.http.client.providers.grizzly; -import static com.ning.http.util.DateUtil.millisTime; - import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.ConnectionsPool; @@ -312,7 +310,7 @@ private class DelayedRunnable implements Runnable { @Override public void run() { while (isStarted) { - final long currentTimeMs = millisTime(); + final long currentTimeMs = System.currentTimeMillis(); for (final IdleConnectionQueue delayQueue : queues) { if (delayQueue.queue.isEmpty()) continue; @@ -383,7 +381,7 @@ public IdleConnectionQueue(final long timeout) { void offer(final Connection c) { if (timeout >= 0) { - resolver.setTimeoutMs(c, millisTime() + timeout); + resolver.setTimeoutMs(c, System.currentTimeMillis() + timeout); } queue.offer(c); count.incrementAndGet(); diff --git a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java index d96bb326d6..d7aca075e3 100644 --- a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java +++ b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java @@ -12,8 +12,6 @@ */ package com.ning.http.util; -import static com.ning.http.util.DateUtil.millisTime; - import java.io.ByteArrayInputStream; import java.io.FileNotFoundException; import java.io.IOException; @@ -499,7 +497,7 @@ public static Cookie parseCookie(String value) { public static int convertExpireField(String timestring) { String trimmedTimeString = removeQuote(timestring.trim()); - long now = millisTime(); + long now = System.currentTimeMillis(); Date date = null; for (SimpleDateFormat sdf : simpleDateFormat.get()) { diff --git a/src/test/java/com/ning/http/client/providers/netty/NettyAsyncResponseTest.java b/src/test/java/com/ning/http/client/providers/netty/NettyAsyncResponseTest.java index 65cddcd89b..c49eee8dc2 100644 --- a/src/test/java/com/ning/http/client/providers/netty/NettyAsyncResponseTest.java +++ b/src/test/java/com/ning/http/client/providers/netty/NettyAsyncResponseTest.java @@ -13,8 +13,6 @@ package com.ning.http.client.providers.netty; -import static com.ning.http.util.DateUtil.millisTime; - import com.ning.http.client.Cookie; import com.ning.http.client.FluentCaseInsensitiveStringsMap; import com.ning.http.client.HttpResponseHeaders; @@ -40,7 +38,7 @@ public void testCookieParseExpires() { SimpleDateFormat sdf = new SimpleDateFormat("EEE, dd-MMM-yyyy HH:mm:ss z", Locale.US); sdf.setTimeZone(TimeZone.getTimeZone("GMT")); - Date date = new Date(millisTime() + 60000); // sdf.parse( dateString ); + Date date = new Date(System.currentTimeMillis() + 60000); // sdf.parse( dateString ); final String cookieDef = String.format("efmembercheck=true; expires=%s; path=/; domain=.eclipse.org", sdf.format(date)); NettyResponse response = new NettyResponse(new ResponseStatus(null, null, null), new HttpResponseHeaders(null, null, false) { From e7288358170fe6efa9befab7f2793681bd47f88a Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 2 May 2013 00:50:05 +0200 Subject: [PATCH 119/264] Backport fix for encoding issue, close #255 --- src/main/java/com/ning/http/client/oauth/ThreadSafeHMAC.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/ning/http/client/oauth/ThreadSafeHMAC.java b/src/main/java/com/ning/http/client/oauth/ThreadSafeHMAC.java index 0157a9df77..7ba72dd1a6 100644 --- a/src/main/java/com/ning/http/client/oauth/ThreadSafeHMAC.java +++ b/src/main/java/com/ning/http/client/oauth/ThreadSafeHMAC.java @@ -17,6 +17,7 @@ package com.ning.http.client.oauth; import com.ning.http.util.UTF8Codec; +import com.ning.http.util.UTF8UrlEncoder; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; @@ -36,7 +37,7 @@ public class ThreadSafeHMAC { private final Mac mac; public ThreadSafeHMAC(ConsumerKey consumerAuth, RequestToken userAuth) { - byte[] keyBytes = UTF8Codec.toUTF8(consumerAuth.getSecret() + "&" + userAuth.getSecret()); + byte[] keyBytes = UTF8Codec.toUTF8(UTF8UrlEncoder.encode(consumerAuth.getSecret()) + "&" + UTF8UrlEncoder.encode(userAuth.getSecret())); SecretKeySpec signingKey = new SecretKeySpec(keyBytes, HMAC_SHA1_ALGORITHM); // Get an hmac_sha1 instance and initialize with the signing key From a123f9fe1a2faaef92892f71d4a321a89eb96411 Mon Sep 17 00:00:00 2001 From: jfarcand Date: Fri, 3 May 2013 08:53:02 -0400 Subject: [PATCH 120/264] [maven-release-plugin] prepare release async-http-client-1.7.15 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index d967083b96..6d5e05a808 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.7.15-SNAPSHOT + 1.7.15 jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From 92f226d9e8bf8487543b01fccafea362e2660b03 Mon Sep 17 00:00:00 2001 From: jfarcand Date: Fri, 3 May 2013 08:53:08 -0400 Subject: [PATCH 121/264] [maven-release-plugin] prepare for next development iteration --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 6d5e05a808..ee3c61cfb4 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.7.15 + 1.7.16-SNAPSHOT jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From 12e4c15a14a2269e974bd220a80ec1887716b283 Mon Sep 17 00:00:00 2001 From: jfarcand Date: Fri, 3 May 2013 08:56:19 -0400 Subject: [PATCH 122/264] Release failed --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index ee3c61cfb4..d967083b96 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.7.16-SNAPSHOT + 1.7.15-SNAPSHOT jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From e7c5c9ca67ee0e4f94cfe2aa65fb147f81b99b1a Mon Sep 17 00:00:00 2001 From: jfarcand Date: Fri, 3 May 2013 08:58:02 -0400 Subject: [PATCH 123/264] [maven-release-plugin] prepare release async-http-client-1.7.15 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index d967083b96..6d5e05a808 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.7.15-SNAPSHOT + 1.7.15 jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From 7eff0ec3b6aeb8c3db0e14f944e0d1ada05a5477 Mon Sep 17 00:00:00 2001 From: jfarcand Date: Fri, 3 May 2013 08:59:34 -0400 Subject: [PATCH 124/264] Not sure why release fail --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 6d5e05a808..d967083b96 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.7.15 + 1.7.15-SNAPSHOT jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From cc4b1b266cccab0a166214bc4ac4e8c8b5b6980e Mon Sep 17 00:00:00 2001 From: jfarcand Date: Fri, 3 May 2013 09:00:45 -0400 Subject: [PATCH 125/264] [maven-release-plugin] prepare release async-http-client-1.7.15 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index d967083b96..6d5e05a808 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.7.15-SNAPSHOT + 1.7.15 jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From 247d2c61ffd8df9cd2f9b0b942ba769a4bf66711 Mon Sep 17 00:00:00 2001 From: jfarcand Date: Fri, 3 May 2013 09:01:27 -0400 Subject: [PATCH 126/264] A big WTF --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 6d5e05a808..d967083b96 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.7.15 + 1.7.15-SNAPSHOT jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From 9bfd4da8030357511c302617272765c7a533a112 Mon Sep 17 00:00:00 2001 From: jfarcand Date: Fri, 3 May 2013 09:03:24 -0400 Subject: [PATCH 127/264] [maven-release-plugin] prepare release async-http-client-1.7.15 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index d967083b96..6d5e05a808 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.7.15-SNAPSHOT + 1.7.15 jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From 0fc7442270d29468a4c2ee581dfca559f7af9bb3 Mon Sep 17 00:00:00 2001 From: jfarcand Date: Fri, 3 May 2013 09:03:29 -0400 Subject: [PATCH 128/264] [maven-release-plugin] prepare for next development iteration --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 6d5e05a808..ee3c61cfb4 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.7.15 + 1.7.16-SNAPSHOT jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From 1b8db2d1f2aa8667d39bf424721121c531a8d051 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 6 May 2013 15:43:06 +0200 Subject: [PATCH 129/264] All GET requests to have a body, close #292 --- src/main/java/com/ning/http/client/RequestBuilderBase.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/ning/http/client/RequestBuilderBase.java b/src/main/java/com/ning/http/client/RequestBuilderBase.java index 14f71a5bc4..1f5c273566 100644 --- a/src/main/java/com/ning/http/client/RequestBuilderBase.java +++ b/src/main/java/com/ning/http/client/RequestBuilderBase.java @@ -492,8 +492,8 @@ private void resetMultipartData() { } private void checkIfBodyAllowed() { - if ("GET".equals(request.method) || "HEAD".equals(request.method)) { - throw new IllegalArgumentException("Can NOT set Body on HTTP Request Method GET nor HEAD."); + if ("HEAD".equals(request.method)) { + throw new IllegalArgumentException("Can NOT set Body on HTTP Request Method HEAD."); } } From d8b32a40447b0c9e0aae2192fb587bb4d4840938 Mon Sep 17 00:00:00 2001 From: Norman Maurer Date: Tue, 7 May 2013 06:29:16 +0200 Subject: [PATCH 130/264] Make sure no bytes are lost when replace the HttpDecoder with the WebSocket08FrameDecoder --- .../providers/netty/NettyAsyncHttpProvider.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java index ade1a85e66..be632c411f 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java @@ -303,8 +303,8 @@ public ChannelPipeline getPipeline() throws Exception { /* @Override */ public ChannelPipeline getPipeline() throws Exception { ChannelPipeline pipeline = pipeline(); - pipeline.addLast("ws-decoder", new HttpResponseDecoder()); - pipeline.addLast("ws-encoder", new HttpRequestEncoder()); + pipeline.addLast("http-decoder", new HttpResponseDecoder()); + pipeline.addLast("http-encoder", new HttpRequestEncoder()); pipeline.addLast("httpProcessor", NettyAsyncHttpProvider.this); return pipeline; } @@ -384,8 +384,8 @@ public ChannelPipeline getPipeline() throws Exception { abort(cl.future(), ex); } - pipeline.addLast("ws-decoder", new HttpResponseDecoder()); - pipeline.addLast("ws-encoder", new HttpRequestEncoder()); + pipeline.addLast("http-decoder", new HttpResponseDecoder()); + pipeline.addLast("http-encoder", new HttpRequestEncoder()); pipeline.addLast("httpProcessor", NettyAsyncHttpProvider.this); return pipeline; @@ -2451,8 +2451,8 @@ public void handle(ChannelHandlerContext ctx, MessageEvent e) throws Exception { throw new IOException(String.format("Invalid challenge. Actual: %s. Expected: %s", accept, key)); } - ctx.getPipeline().replace("ws-decoder", "ws-decoder", new WebSocket08FrameDecoder(false, false)); - ctx.getPipeline().replace("ws-encoder", "ws-encoder", new WebSocket08FrameEncoder(true)); + ctx.getPipeline().get(HttpResponseDecoder.class).replace("ws-decoder", new WebSocket08FrameDecoder(false, false)); + ctx.getPipeline().replace("http-encoder", "ws-encoder", new WebSocket08FrameEncoder(true)); if (h.onHeadersReceived(responseHeaders) == STATE.CONTINUE) { h.onSuccess(new NettyWebSocket(ctx.getChannel())); } From c14a9622484bdc87cbdfb048fb048512968e98bf Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 14 May 2013 17:45:23 +0200 Subject: [PATCH 131/264] As of #292, GET request can have a body --- .../http/client/async/AsyncProvidersBasicTest.java | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java b/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java index eb6bb5eda5..84b460fca0 100755 --- a/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java +++ b/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java @@ -1650,18 +1650,6 @@ public void onThrowable(Throwable t) { } } - @Test(groups = { "standalone", "default_provider" }, expectedExceptions = IllegalArgumentException.class) - public void getShouldNotAllowBody() throws IllegalArgumentException, IOException { - AsyncHttpClient client = getAsyncHttpClient(null); - try { - AsyncHttpClient.BoundRequestBuilder builder = client.prepareGet(getTargetUrl()); - builder.setBody("Boo!"); - builder.execute(); - } finally { - client.close(); - } - } - @Test(groups = { "standalone", "default_provider" }, expectedExceptions = IllegalArgumentException.class) public void headShouldNotAllowBody() throws IllegalArgumentException, IOException { AsyncHttpClient client = getAsyncHttpClient(null); From b7a0ae2467c349804da13aa3ecca7ec7dade5bba Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 14 May 2013 17:59:49 +0200 Subject: [PATCH 132/264] Multiparts should support Content-ID header, close #296 --- pom.xml | 2 + .../com/ning/http/multipart/FilePart.java | 123 +++++++--------- .../java/com/ning/http/multipart/Part.java | 137 ++++++++++-------- .../com/ning/http/multipart/PartBase.java | 44 +++--- .../com/ning/http/multipart/StringPart.java | 43 +++--- 5 files changed, 179 insertions(+), 170 deletions(-) diff --git a/pom.xml b/pom.xml index ee3c61cfb4..b46ea1d6ca 100644 --- a/pom.xml +++ b/pom.xml @@ -466,6 +466,8 @@ **/NettyResponse **/AsyncHttpProviderUtils **/Cookie + **/Part + **/PartBase diff --git a/src/main/java/com/ning/http/multipart/FilePart.java b/src/main/java/com/ning/http/multipart/FilePart.java index 5548085f08..7f160580b3 100644 --- a/src/main/java/com/ning/http/multipart/FilePart.java +++ b/src/main/java/com/ning/http/multipart/FilePart.java @@ -23,7 +23,7 @@ /** * This class is an adaptation of the Apache HttpClient implementation - * + * * @link http://hc.apache.org/httpclient-3.x/ */ public class FilePart extends PartBase { @@ -51,32 +51,24 @@ public class FilePart extends PartBase { /** * Attachment's file name as a byte array */ - private static final byte[] FILE_NAME_BYTES = - MultipartEncodingUtil.getAsciiBytes(FILE_NAME); + private static final byte[] FILE_NAME_BYTES = MultipartEncodingUtil.getAsciiBytes(FILE_NAME); /** * Source of the file part. */ - private PartSource source; + private final PartSource source; /** * FilePart Constructor. - * - * @param name the name for this part - * @param partSource the source for this part - * @param contentType the content type for this part, if null the - * {@link #DEFAULT_CONTENT_TYPE default} is used - * @param charset the charset encoding for this part, if null the - * {@link #DEFAULT_CHARSET default} is used + * + * @param name the name for this part + * @param partSource the source for this part + * @param contentType the content type for this part, if null the {@link #DEFAULT_CONTENT_TYPE default} is used + * @param charset the charset encoding for this part, if null the {@link #DEFAULT_CHARSET default} is used */ - public FilePart(String name, PartSource partSource, String contentType, String charset) { + public FilePart(String name, PartSource partSource, String contentType, String charset, String contentId) { - super( - name, - contentType == null ? DEFAULT_CONTENT_TYPE : contentType, - charset == null ? "ISO-8859-1" : charset, - DEFAULT_TRANSFER_ENCODING - ); + super(name, contentType == null ? DEFAULT_CONTENT_TYPE : contentType, charset == null ? "ISO-8859-1" : charset, DEFAULT_TRANSFER_ENCODING, contentId); if (partSource == null) { throw new IllegalArgumentException("Source may not be null"); @@ -84,10 +76,14 @@ public FilePart(String name, PartSource partSource, String contentType, String c this.source = partSource; } + public FilePart(String name, PartSource partSource, String contentType, String charset) { + this(name, partSource, contentType, charset, null); + } + /** * FilePart Constructor. - * - * @param name the name for this part + * + * @param name the name for this part * @param partSource the source for this part */ public FilePart(String name, PartSource partSource) { @@ -96,74 +92,61 @@ public FilePart(String name, PartSource partSource) { /** * FilePart Constructor. - * + * * @param name the name of the file part * @param file the file to post - * @throws java.io.FileNotFoundException if the file is not a normal - * file or if it is not readable. + * @throws java.io.FileNotFoundException if the file is not a normal file or if it is not readable. */ - public FilePart(String name, File file) - throws FileNotFoundException { + public FilePart(String name, File file) throws FileNotFoundException { this(name, new FilePartSource(file), null, null); } /** * FilePart Constructor. - * - * @param name the name of the file part - * @param file the file to post - * @param contentType the content type for this part, if null the - * {@link #DEFAULT_CONTENT_TYPE default} is used - * @param charset the charset encoding for this part, if null the - * {@link #DEFAULT_CHARSET default} is used - * @throws FileNotFoundException if the file is not a normal - * file or if it is not readable. - */ - public FilePart(String name, File file, String contentType, String charset) - throws FileNotFoundException { + * + * @param name the name of the file part + * @param file the file to post + * @param contentType the content type for this part, if null the {@link #DEFAULT_CONTENT_TYPE default} is used + * @param charset the charset encoding for this part, if null the {@link #DEFAULT_CHARSET default} is used + * @throws FileNotFoundException if the file is not a normal file or if it is not readable. + */ + public FilePart(String name, File file, String contentType, String charset) throws FileNotFoundException { this(name, new FilePartSource(file), contentType, charset); } /** * FilePart Constructor. - * - * @param name the name of the file part + * + * @param name the name of the file part * @param fileName the file name - * @param file the file to post - * @throws FileNotFoundException if the file is not a normal - * file or if it is not readable. + * @param file the file to post + * @throws FileNotFoundException if the file is not a normal file or if it is not readable. */ - public FilePart(String name, String fileName, File file) - throws FileNotFoundException { + public FilePart(String name, String fileName, File file) throws FileNotFoundException { this(name, new FilePartSource(fileName, file), null, null); } /** * FilePart Constructor. - * - * @param name the name of the file part - * @param fileName the file name - * @param file the file to post - * @param contentType the content type for this part, if null the - * {@link #DEFAULT_CONTENT_TYPE default} is used - * @param charset the charset encoding for this part, if null the - * {@link #DEFAULT_CHARSET default} is used - * @throws FileNotFoundException if the file is not a normal - * file or if it is not readable. - */ - public FilePart(String name, String fileName, File file, String contentType, String charset) - throws FileNotFoundException { + * + * @param name the name of the file part + * @param fileName the file name + * @param file the file to post + * @param contentType the content type for this part, if null the {@link #DEFAULT_CONTENT_TYPE default} is used + * @param charset the charset encoding for this part, if null the {@link #DEFAULT_CHARSET default} is used + * @throws FileNotFoundException if the file is not a normal file or if it is not readable. + */ + public FilePart(String name, String fileName, File file, String contentType, String charset) throws FileNotFoundException { this(name, new FilePartSource(fileName, file), contentType, charset); } /** * Write the disposition header to the output stream - * + * * @param out The output stream * @throws java.io.IOException If an IO problem occurs */ - protected void sendDispositionHeader(OutputStream out) - throws IOException { + protected void sendDispositionHeader(OutputStream out) throws IOException { super.sendDispositionHeader(out); String filename = this.source.getFileName(); if (filename != null) { @@ -176,7 +159,7 @@ protected void sendDispositionHeader(OutputStream out) /** * Write the data in "source" to the specified stream. - * + * * @param out The output stream. * @throws IOException if an IO problem occurs. */ @@ -202,17 +185,17 @@ protected void sendData(OutputStream out) throws IOException { } } - public void setStalledTime(long ms) { - _stalledTime = ms; - } + public void setStalledTime(long ms) { + _stalledTime = ms; + } - public long getStalledTime() { - return _stalledTime; - } + public long getStalledTime() { + return _stalledTime; + } /** * Returns the source of the file part. - * + * * @return The source. */ protected PartSource getSource() { @@ -221,7 +204,7 @@ protected PartSource getSource() { /** * Return the length of the data. - * + * * @return The length. * @throws IOException if an IO problem occurs */ @@ -229,6 +212,6 @@ protected long lengthOfData() throws IOException { return source.getLength(); } - private long _stalledTime = -1; + private long _stalledTime = -1; } diff --git a/src/main/java/com/ning/http/multipart/Part.java b/src/main/java/com/ning/http/multipart/Part.java index f1d5d30807..8edf01ad1a 100644 --- a/src/main/java/com/ning/http/multipart/Part.java +++ b/src/main/java/com/ning/http/multipart/Part.java @@ -21,7 +21,7 @@ /** * This class is an adaptation of the Apache HttpClient implementation - * + * * @link http://hc.apache.org/httpclient-3.x/ */ public abstract class Part implements com.ning.http.client.Part { @@ -32,8 +32,7 @@ public abstract class Part implements com.ning.http.client.Part { protected static final String BOUNDARY = "----------------314159265358979323846"; /** - * The default boundary to be used if etBoundaryBytes(byte[]) has not - * been called. + * The default boundary to be used if etBoundaryBytes(byte[]) has not been called. */ private static final byte[] DEFAULT_BOUNDARY_BYTES = MultipartEncodingUtil.getAsciiBytes(BOUNDARY); @@ -105,12 +104,21 @@ public abstract class Part implements com.ning.http.client.Part { /** * Content type header as a byte array */ - static final byte[] CONTENT_TRANSFER_ENCODING_BYTES = - MultipartEncodingUtil.getAsciiBytes(CONTENT_TRANSFER_ENCODING); + static final byte[] CONTENT_TRANSFER_ENCODING_BYTES = MultipartEncodingUtil.getAsciiBytes(CONTENT_TRANSFER_ENCODING); + + /** + * Content type header + */ + protected static final String CONTENT_ID = "Content-ID: "; + + /** + * Content type header as a byte array + */ + static final byte[] CONTENT_ID_BYTES = MultipartEncodingUtil.getAsciiBytes(CONTENT_ID); /** * Return the boundary string. - * + * * @return the boundary string * @deprecated uses a constant string. Rather use {@link #getPartBoundary} */ @@ -125,36 +133,42 @@ public static String getBoundary() { /** * Return the name of this part. - * + * * @return The name. */ public abstract String getName(); /** * Returns the content type of this part. - * + * * @return the content type, or null to exclude the content type header */ public abstract String getContentType(); /** * Return the character encoding of this part. - * - * @return the character encoding, or null to exclude the character - * encoding header + * + * @return the character encoding, or null to exclude the character encoding header */ public abstract String getCharSet(); /** * Return the transfer encoding of this part. - * + * * @return the transfer encoding, or null to exclude the transfer encoding header */ public abstract String getTransferEncoding(); + /** + * Return the content ID of this part. + * + * @return the content ID, or null to exclude the content ID header + */ + public abstract String getContentId(); + /** * Gets the part boundary to be used. - * + * * @return the part boundary as an array of bytes. * @since 3.0 */ @@ -168,10 +182,8 @@ protected byte[] getPartBoundary() { } /** - * Sets the part boundary. Only meant to be used by - * {@link Part#sendParts(java.io.OutputStream, Part[], byte[])} - * and {@link Part#getLengthOfParts(Part[], byte[])} - * + * Sets the part boundary. Only meant to be used by {@link Part#sendParts(java.io.OutputStream, Part[], byte[])} and {@link Part#getLengthOfParts(Part[], byte[])} + * * @param boundaryBytes An array of ASCII bytes. * @since 3.0 */ @@ -181,9 +193,8 @@ void setPartBoundary(byte[] boundaryBytes) { /** * Tests if this part can be sent more than once. - * - * @return true if {@link #sendData(java.io.OutputStream)} can be successfully called - * more than once. + * + * @return true if {@link #sendData(java.io.OutputStream)} can be successfully called more than once. * @since 3.0 */ public boolean isRepeatable() { @@ -192,7 +203,7 @@ public boolean isRepeatable() { /** * Write the start to the specified output stream - * + * * @param out The output stream * @throws java.io.IOException If an IO problem occurs. */ @@ -204,7 +215,7 @@ protected void sendStart(OutputStream out) throws IOException { /** * Write the content disposition header to the specified output stream - * + * * @param out The output stream * @throws IOException If an IO problem occurs. */ @@ -217,7 +228,7 @@ protected void sendDispositionHeader(OutputStream out) throws IOException { /** * Write the content type header to the specified output stream - * + * * @param out The output stream * @throws IOException If an IO problem occurs. */ @@ -236,9 +247,8 @@ protected void sendContentTypeHeader(OutputStream out) throws IOException { } /** - * Write the content transfer encoding header to the specified - * output stream - * + * Write the content transfer encoding header to the specified output stream + * * @param out The output stream * @throws IOException If an IO problem occurs. */ @@ -251,9 +261,24 @@ protected void sendTransferEncodingHeader(OutputStream out) throws IOException { } } + /** + * Write the content ID header to the specified output stream + * + * @param out The output stream + * @throws IOException If an IO problem occurs. + */ + protected void sendContentIDHeader(OutputStream out) throws IOException { + String contentId = getContentId(); + if (contentId != null) { + out.write(CRLF_BYTES); + out.write(CONTENT_ID_BYTES); + out.write(MultipartEncodingUtil.getAsciiBytes(contentId)); + } + } + /** * Write the end of the header to the output stream - * + * * @param out The output stream * @throws IOException If an IO problem occurs. */ @@ -264,7 +289,7 @@ protected void sendEndOfHeader(OutputStream out) throws IOException { /** * Write the data to the specified output stream - * + * * @param out The output stream * @throws IOException If an IO problem occurs. */ @@ -272,7 +297,7 @@ protected void sendEndOfHeader(OutputStream out) throws IOException { /** * Return the length of the main content - * + * * @return long The length. * @throws IOException If an IO problem occurs */ @@ -280,7 +305,7 @@ protected void sendEndOfHeader(OutputStream out) throws IOException { /** * Write the end data to the output stream. - * + * * @param out The output stream * @throws IOException If an IO problem occurs. */ @@ -289,10 +314,8 @@ protected void sendEnd(OutputStream out) throws IOException { } /** - * Write all the data to the output stream. - * If you override this method make sure to override - * #length() as well - * + * Write all the data to the output stream. If you override this method make sure to override #length() as well + * * @param out The output stream * @throws IOException If an IO problem occurs. */ @@ -301,17 +324,15 @@ public void send(OutputStream out) throws IOException { sendDispositionHeader(out); sendContentTypeHeader(out); sendTransferEncodingHeader(out); + sendContentIDHeader(out); sendEndOfHeader(out); sendData(out); sendEnd(out); } - /** - * Return the full length of all the data. - * If you override this method make sure to override - * #send(OutputStream) as well - * + * Return the full length of all the data. If you override this method make sure to override #send(OutputStream) as well + * * @return long The length. * @throws IOException If an IO problem occurs */ @@ -324,6 +345,7 @@ public long length() throws IOException { sendDispositionHeader(overhead); sendContentTypeHeader(overhead); sendTransferEncodingHeader(overhead); + sendContentIDHeader(overhead); sendEndOfHeader(overhead); sendEnd(overhead); return overhead.size() + lengthOfData(); @@ -331,7 +353,7 @@ public long length() throws IOException { /** * Return a string representation of this object. - * + * * @return A string representation of this object. * @see java.lang.Object#toString() */ @@ -341,27 +363,25 @@ public String toString() { /** * Write all parts and the last boundary to the specified output stream. - * - * @param out The stream to write to. + * + * @param out The stream to write to. * @param parts The parts to write. * @throws IOException If an I/O error occurs while writing the parts. */ - public static void sendParts(OutputStream out, final Part[] parts) - throws IOException { + public static void sendParts(OutputStream out, final Part[] parts) throws IOException { sendParts(out, parts, DEFAULT_BOUNDARY_BYTES); } /** * Write all parts and the last boundary to the specified output stream. - * - * @param out The stream to write to. - * @param parts The parts to write. + * + * @param out The stream to write to. + * @param parts The parts to write. * @param partBoundary The ASCII bytes to use as the part boundary. * @throws IOException If an I/O error occurs while writing the parts. * @since 3.0 */ - public static void sendParts(OutputStream out, Part[] parts, byte[] partBoundary) - throws IOException { + public static void sendParts(OutputStream out, Part[] parts, byte[] partBoundary) throws IOException { if (parts == null) { throw new IllegalArgumentException("Parts may not be null"); @@ -380,8 +400,7 @@ public static void sendParts(OutputStream out, Part[] parts, byte[] partBoundary out.write(CRLF_BYTES); } - public static void sendMessageEnd(OutputStream out, byte[] partBoundary) - throws IOException { + public static void sendMessageEnd(OutputStream out, byte[] partBoundary) throws IOException { if (partBoundary == null || partBoundary.length == 0) { throw new IllegalArgumentException("partBoundary may not be empty"); @@ -395,14 +414,13 @@ public static void sendMessageEnd(OutputStream out, byte[] partBoundary) /** * Write all parts and the last boundary to the specified output stream. - * - * @param out The stream to write to. + * + * @param out The stream to write to. * @param part The part to write. * @throws IOException If an I/O error occurs while writing the parts. * @since N/A */ - public static void sendPart(OutputStream out, Part part, byte[] partBoundary) - throws IOException { + public static void sendPart(OutputStream out, Part part, byte[] partBoundary) throws IOException { if (part == null) { throw new IllegalArgumentException("Parts may not be null"); @@ -414,20 +432,19 @@ public static void sendPart(OutputStream out, Part part, byte[] partBoundary) /** * Return the total sum of all parts and that of the last boundary - * + * * @param parts The parts. * @return The total length * @throws IOException If an I/O error occurs while writing the parts. */ - public static long getLengthOfParts(Part[] parts) - throws IOException { + public static long getLengthOfParts(Part[] parts) throws IOException { return getLengthOfParts(parts, DEFAULT_BOUNDARY_BYTES); } /** * Gets the length of the multipart message including the given parts. - * - * @param parts The parts. + * + * @param parts The parts. * @param partBoundary The ASCII bytes to use as the part boundary. * @return The total length * @throws IOException If an I/O error occurs while writing the parts. diff --git a/src/main/java/com/ning/http/multipart/PartBase.java b/src/main/java/com/ning/http/multipart/PartBase.java index 415bb49186..b37bbad292 100644 --- a/src/main/java/com/ning/http/multipart/PartBase.java +++ b/src/main/java/com/ning/http/multipart/PartBase.java @@ -17,7 +17,7 @@ /** * This class is an adaptation of the Apache HttpClient implementation - * + * * @link http://hc.apache.org/httpclient-3.x/ */ public abstract class PartBase extends Part { @@ -42,15 +42,17 @@ public abstract class PartBase extends Part { */ private String transferEncoding; + private String contentId; + /** * Constructor. - * - * @param name The name of the part - * @param contentType The content type, or null - * @param charSet The character encoding, or null + * + * @param name The name of the part + * @param contentType The content type, or null + * @param charSet The character encoding, or null * @param transferEncoding The transfer encoding, or null */ - public PartBase(String name, String contentType, String charSet, String transferEncoding) { + public PartBase(String name, String contentType, String charSet, String transferEncoding, String contentId) { if (name == null) { throw new IllegalArgumentException("Name must not be null"); @@ -59,11 +61,12 @@ public PartBase(String name, String contentType, String charSet, String transfer this.contentType = contentType; this.charSet = charSet; this.transferEncoding = transferEncoding; + this.contentId = contentId; } /** * Returns the name. - * + * * @return The name. */ public String getName() { @@ -72,7 +75,7 @@ public String getName() { /** * Returns the content type of this part. - * + * * @return String The name. */ public String getContentType() { @@ -81,7 +84,7 @@ public String getContentType() { /** * Return the character encoding of this part. - * + * * @return String The name. */ public String getCharSet() { @@ -90,7 +93,7 @@ public String getCharSet() { /** * Returns the transfer encoding of this part. - * + * * @return String The name. */ public String getTransferEncoding() { @@ -99,9 +102,8 @@ public String getTransferEncoding() { /** * Sets the character encoding. - * - * @param charSet the character encoding, or null to exclude the character - * encoding header + * + * @param charSet the character encoding, or null to exclude the character encoding header */ public void setCharSet(String charSet) { this.charSet = charSet; @@ -109,7 +111,7 @@ public void setCharSet(String charSet) { /** * Sets the content type. - * + * * @param contentType the content type, or null to exclude the content type header */ public void setContentType(String contentType) { @@ -118,7 +120,7 @@ public void setContentType(String contentType) { /** * Sets the part name. - * + * * @param name */ public void setName(String name) { @@ -130,12 +132,18 @@ public void setName(String name) { /** * Sets the transfer encoding. - * - * @param transferEncoding the transfer encoding, or null to exclude the - * transfer encoding header + * + * @param transferEncoding the transfer encoding, or null to exclude the transfer encoding header */ public void setTransferEncoding(String transferEncoding) { this.transferEncoding = transferEncoding; } + public String getContentId() { + return contentId; + } + + public void setContentId(String contentId) { + this.contentId = contentId; + } } diff --git a/src/main/java/com/ning/http/multipart/StringPart.java b/src/main/java/com/ning/http/multipart/StringPart.java index 431362c8bb..6cd36c0ebc 100644 --- a/src/main/java/com/ning/http/multipart/StringPart.java +++ b/src/main/java/com/ning/http/multipart/StringPart.java @@ -20,7 +20,7 @@ /** * This class is an adaptation of the Apache HttpClient implementation - * + * * @link http://hc.apache.org/httpclient-3.x/ */ public class StringPart extends PartBase { @@ -48,24 +48,18 @@ public class StringPart extends PartBase { /** * The String value of this part. */ - private String value; + private final String value; /** * Constructor. - * - * @param name The name of the part - * @param value the string to post - * @param charset the charset to be used to encode the string, if null - * the {@link #DEFAULT_CHARSET default} is used + * + * @param name The name of the part + * @param value the string to post + * @param charset the charset to be used to encode the string, if null the {@link #DEFAULT_CHARSET default} is used */ - public StringPart(String name, String value, String charset) { + public StringPart(String name, String value, String charset, String contentId) { - super( - name, - DEFAULT_CONTENT_TYPE, - charset == null ? DEFAULT_CHARSET : charset, - DEFAULT_TRANSFER_ENCODING - ); + super(name, DEFAULT_CONTENT_TYPE, charset == null ? DEFAULT_CHARSET : charset, DEFAULT_TRANSFER_ENCODING, contentId); if (value == null) { throw new IllegalArgumentException("Value may not be null"); } @@ -76,10 +70,14 @@ public StringPart(String name, String value, String charset) { this.value = value; } + public StringPart(String name, String value, String charset) { + this(name, value, charset, null); + } + /** * Constructor. - * - * @param name The name of the part + * + * @param name The name of the part * @param value the string to post */ public StringPart(String name, String value) { @@ -87,9 +85,8 @@ public StringPart(String name, String value) { } /** - * Gets the content in bytes. Bytes are lazily created to allow the charset to be changed - * after the part is created. - * + * Gets the content in bytes. Bytes are lazily created to allow the charset to be changed after the part is created. + * * @return the content in bytes */ private byte[] getContent() { @@ -101,7 +98,7 @@ private byte[] getContent() { /** * Writes the data to the given OutputStream. - * + * * @param out the OutputStream to write to * @throws java.io.IOException if there is a write error */ @@ -111,7 +108,7 @@ protected void sendData(OutputStream out) throws IOException { /** * Return the length of the data. - * + * * @return The length of the data. * @throws IOException If an IO problem occurs */ @@ -119,7 +116,9 @@ protected long lengthOfData() throws IOException { return getContent().length; } - /* (non-Javadoc) + /* + * (non-Javadoc) + * * @see org.apache.commons.httpclient.methods.multipart.BasePart#setCharSet(java.lang.String) */ public void setCharSet(String charSet) { From d8a2e0ae137061ce91d113b5b73bfe550465588a Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 17 May 2013 15:54:47 +0200 Subject: [PATCH 133/264] Various multipart fixes, close #296, #297, #298 --- pom.xml | 1 + .../grizzly/GrizzlyAsyncHttpProvider.java | 2 +- .../providers/jdk/JDKAsyncHttpProvider.java | 3 +- .../netty/NettyAsyncHttpProvider.java | 8 +- .../com/ning/http/multipart/FilePart.java | 3 +- .../ning/http/multipart/FilePartSource.java | 6 +- .../ning/http/multipart/MultipartBody.java | 6 +- .../multipart/MultipartRequestEntity.java | 75 ++++++++++--------- .../java/com/ning/http/multipart/Part.java | 6 +- .../http/util/AsyncHttpProviderUtils.java | 7 +- 10 files changed, 63 insertions(+), 54 deletions(-) diff --git a/pom.xml b/pom.xml index b46ea1d6ca..9755f31942 100644 --- a/pom.xml +++ b/pom.xml @@ -468,6 +468,7 @@ **/Cookie **/Part **/PartBase + **/MultipartRequestEntity diff --git a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java index 7b241cbf5c..5eae0fd8c0 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java @@ -2072,7 +2072,7 @@ public boolean doHandle(final FilterChainContext ctx, MultipartRequestEntity mre = AsyncHttpProviderUtils.createMultipartRequestEntity( request.getParts(), - request.getParams()); + request.getHeaders()); requestPacket.setContentLengthLong(mre.getContentLength()); requestPacket.setContentType(mre.getContentType()); final MemoryManager mm = ctx.getMemoryManager(); diff --git a/src/main/java/com/ning/http/client/providers/jdk/JDKAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/jdk/JDKAsyncHttpProvider.java index 7a315facec..37b3cd7880 100644 --- a/src/main/java/com/ning/http/client/providers/jdk/JDKAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/jdk/JDKAsyncHttpProvider.java @@ -43,6 +43,7 @@ import com.ning.http.util.ProxyUtils; import com.ning.http.util.SslUtils; import com.ning.http.util.UTF8UrlEncoder; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -617,7 +618,7 @@ private void configure(URI uri, HttpURLConnection urlConnection, Request request lenght = MAX_BUFFERED_BYTES; } - MultipartRequestEntity mre = AsyncHttpProviderUtils.createMultipartRequestEntity(request.getParts(), request.getParams()); + MultipartRequestEntity mre = AsyncHttpProviderUtils.createMultipartRequestEntity(request.getParts(), request.getHeaders()); urlConnection.setRequestProperty("Content-Type", mre.getContentType()); urlConnection.setRequestProperty("Content-Length", String.valueOf(mre.getContentLength())); diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java index be632c411f..9db866f3e6 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java @@ -554,9 +554,9 @@ public void operationComplete(ChannelFuture cf) { * TODO: AHC-78: SSL + zero copy isn't supported by the MultiPart class and pretty complex to implements. */ if (future.getRequest().getParts() != null) { - String boundary = future.getNettyRequest().getHeader("Content-Type"); + String contentType = future.getNettyRequest().getHeader("Content-Type"); String length = future.getNettyRequest().getHeader("Content-Length"); - body = new MultipartBody(future.getRequest().getParts(), boundary, length); + body = new MultipartBody(future.getRequest().getParts(), contentType, length); } ChannelFuture writeFuture; @@ -858,8 +858,8 @@ else if (uri.getRawQuery() != null) lenght = MAX_BUFFERED_BYTES; } - MultipartRequestEntity mre = AsyncHttpProviderUtils.createMultipartRequestEntity(request.getParts(), request.getParams()); - + MultipartRequestEntity mre = AsyncHttpProviderUtils.createMultipartRequestEntity(request.getParts(), request.getHeaders()); + nettyRequest.setHeader(HttpHeaders.Names.CONTENT_TYPE, mre.getContentType()); nettyRequest.setHeader(HttpHeaders.Names.CONTENT_LENGTH, String.valueOf(mre.getContentLength())); diff --git a/src/main/java/com/ning/http/multipart/FilePart.java b/src/main/java/com/ning/http/multipart/FilePart.java index 7f160580b3..ac6c1972b9 100644 --- a/src/main/java/com/ning/http/multipart/FilePart.java +++ b/src/main/java/com/ning/http/multipart/FilePart.java @@ -69,7 +69,6 @@ public class FilePart extends PartBase { public FilePart(String name, PartSource partSource, String contentType, String charset, String contentId) { super(name, contentType == null ? DEFAULT_CONTENT_TYPE : contentType, charset == null ? "ISO-8859-1" : charset, DEFAULT_TRANSFER_ENCODING, contentId); - if (partSource == null) { throw new IllegalArgumentException("Source may not be null"); } @@ -147,9 +146,9 @@ public FilePart(String name, String fileName, File file, String contentType, Str * @throws java.io.IOException If an IO problem occurs */ protected void sendDispositionHeader(OutputStream out) throws IOException { - super.sendDispositionHeader(out); String filename = this.source.getFileName(); if (filename != null) { + super.sendDispositionHeader(out); out.write(FILE_NAME_BYTES); out.write(QUOTE_BYTES); out.write(MultipartEncodingUtil.getAsciiBytes(filename)); diff --git a/src/main/java/com/ning/http/multipart/FilePartSource.java b/src/main/java/com/ning/http/multipart/FilePartSource.java index 3f652047cc..ddb772ba7c 100644 --- a/src/main/java/com/ning/http/multipart/FilePartSource.java +++ b/src/main/java/com/ning/http/multipart/FilePartSource.java @@ -70,9 +70,7 @@ public FilePartSource(File file) throws FileNotFoundException { public FilePartSource(String fileName, File file) throws FileNotFoundException { this(file); - if (fileName != null) { - this.fileName = fileName; - } + this.fileName = fileName; } /** @@ -96,7 +94,7 @@ public long getLength() { * @see PartSource#getFileName() */ public String getFileName() { - return (fileName == null) ? "noname" : fileName; + return fileName; } /** diff --git a/src/main/java/com/ning/http/multipart/MultipartBody.java b/src/main/java/com/ning/http/multipart/MultipartBody.java index d12a5f0cf2..1f336c21aa 100644 --- a/src/main/java/com/ning/http/multipart/MultipartBody.java +++ b/src/main/java/com/ning/http/multipart/MultipartBody.java @@ -48,8 +48,9 @@ public class MultipartBody implements RandomAccessBody { enum FileLocation {NONE, START, MIDDLE, END} - public MultipartBody(List parts, String boundary, String contentLength) { - this.boundary = MultipartEncodingUtil.getAsciiBytes(boundary.substring("multipart/form-data; boundary=".length())); + public MultipartBody(List parts, String contentType, String contentLength) { + this.boundary = MultipartEncodingUtil.getAsciiBytes(contentType.substring(contentType.indexOf("boundary=") + "boundary=".length())); + this.contentLength = Long.parseLong(contentLength); this.parts = parts; @@ -430,6 +431,7 @@ private ByteArrayOutputStream generateFileStart(FilePart filePart) filePart.sendDispositionHeader(overhead); filePart.sendContentTypeHeader(overhead); filePart.sendTransferEncodingHeader(overhead); + filePart.sendContentIdHeader(overhead); filePart.sendEndOfHeader(overhead); return overhead; } diff --git a/src/main/java/com/ning/http/multipart/MultipartRequestEntity.java b/src/main/java/com/ning/http/multipart/MultipartRequestEntity.java index 0d93447a22..e9fd24c88e 100644 --- a/src/main/java/com/ning/http/multipart/MultipartRequestEntity.java +++ b/src/main/java/com/ning/http/multipart/MultipartRequestEntity.java @@ -15,7 +15,10 @@ */ package com.ning.http.multipart; -import com.ning.http.client.FluentStringsMap; +import static com.ning.http.util.MiscUtil.isNonEmpty; + +import com.ning.http.client.FluentCaseInsensitiveStringsMap; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -25,7 +28,7 @@ /** * This class is an adaptation of the Apache HttpClient implementation - * + * * @link http://hc.apache.org/httpclient-3.x/ */ public class MultipartRequestEntity implements RequestEntity { @@ -38,15 +41,14 @@ public class MultipartRequestEntity implements RequestEntity { /** * The pool of ASCII chars to be used for generating a multipart boundary. */ - private static byte[] MULTIPART_CHARS = MultipartEncodingUtil.getAsciiBytes( - "-_1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"); + private static byte[] MULTIPART_CHARS = MultipartEncodingUtil.getAsciiBytes("-_1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"); /** * Generates a random multipart boundary string. - * + * * @return */ - private static byte[] generateMultipartBoundary() { + public static byte[] generateMultipartBoundary() { Random rand = new Random(); byte[] bytes = new byte[rand.nextInt(11) + 30]; // a random size from 30 to 40 for (int i = 0; i < bytes.length; i++) { @@ -64,42 +66,35 @@ private static byte[] generateMultipartBoundary() { private byte[] multipartBoundary; - private FluentStringsMap methodParams; + private final String contentType; /** * Creates a new multipart entity containing the given parts. - * - * @param parts The parts to include. - * @param methodParams The params of the HttpMethod using this entity. + * + * @param parts The parts to include. */ - public MultipartRequestEntity(Part[] parts, FluentStringsMap methodParams) { + public MultipartRequestEntity(Part[] parts, FluentCaseInsensitiveStringsMap requestHeaders) { if (parts == null) { throw new IllegalArgumentException("parts cannot be null"); } - if (methodParams == null) { - methodParams = new FluentStringsMap(); - } this.parts = parts; - this.methodParams = methodParams; + String contentTypeHeader = requestHeaders.getFirstValue("Content-Type"); + if (isNonEmpty(contentTypeHeader)) + this.contentType = contentTypeHeader; + else + this.contentType = MULTIPART_FORM_CONTENT_TYPE; + } /** - * Returns the MIME boundary string that is used to demarcate boundaries of - * this part. The first call to this method will implicitly create a new - * boundary string. To create a boundary string first the - * HttpMethodParams.MULTIPART_BOUNDARY parameter is considered. Otherwise - * a random one is generated. - * + * Returns the MIME boundary string that is used to demarcate boundaries of this part. The first call to this method will implicitly create a new boundary string. To create a boundary string first the HttpMethodParams.MULTIPART_BOUNDARY parameter is considered. Otherwise a + * random one is generated. + * * @return The boundary string of this entity in ASCII encoding. */ protected byte[] getMultipartBoundary() { if (multipartBoundary == null) { - String temp = methodParams.get("") == null ? null : methodParams.get("").iterator().next(); - if (temp != null) { - multipartBoundary = MultipartEncodingUtil.getAsciiBytes(temp); - } else { - multipartBoundary = generateMultipartBoundary(); - } + multipartBoundary = generateMultipartBoundary(); } return multipartBoundary; } @@ -116,14 +111,18 @@ public boolean isRepeatable() { return true; } - /* (non-Javadoc) + /* + * (non-Javadoc) + * * @see org.apache.commons.httpclient.methods.RequestEntity#writeRequest(java.io.OutputStream) */ public void writeRequest(OutputStream out) throws IOException { Part.sendParts(out, parts, getMultipartBoundary()); } - /* (non-Javadoc) + /* + * (non-Javadoc) + * * @see org.apache.commons.httpclient.methods.RequestEntity#getContentLength() */ public long getContentLength() { @@ -135,14 +134,22 @@ public long getContentLength() { } } - /* (non-Javadoc) + /* + * (non-Javadoc) + * * @see org.apache.commons.httpclient.methods.RequestEntity#getContentType() */ public String getContentType() { - StringBuffer buffer = new StringBuffer(MULTIPART_FORM_CONTENT_TYPE); - buffer.append("; boundary="); - buffer.append(MultipartEncodingUtil.getAsciiString(getMultipartBoundary())); - return buffer.toString(); + if (contentType.contains("boundary=")) + return contentType; + else { + StringBuffer buffer = new StringBuffer(contentType); + if (!contentType.endsWith(";")) + buffer.append(";"); + buffer.append(" boundary="); + buffer.append(MultipartEncodingUtil.getAsciiString(getMultipartBoundary())); + return buffer.toString(); + } } } diff --git a/src/main/java/com/ning/http/multipart/Part.java b/src/main/java/com/ning/http/multipart/Part.java index 8edf01ad1a..94dece3008 100644 --- a/src/main/java/com/ning/http/multipart/Part.java +++ b/src/main/java/com/ning/http/multipart/Part.java @@ -267,7 +267,7 @@ protected void sendTransferEncodingHeader(OutputStream out) throws IOException { * @param out The output stream * @throws IOException If an IO problem occurs. */ - protected void sendContentIDHeader(OutputStream out) throws IOException { + protected void sendContentIdHeader(OutputStream out) throws IOException { String contentId = getContentId(); if (contentId != null) { out.write(CRLF_BYTES); @@ -324,7 +324,7 @@ public void send(OutputStream out) throws IOException { sendDispositionHeader(out); sendContentTypeHeader(out); sendTransferEncodingHeader(out); - sendContentIDHeader(out); + sendContentIdHeader(out); sendEndOfHeader(out); sendData(out); sendEnd(out); @@ -345,7 +345,7 @@ public long length() throws IOException { sendDispositionHeader(overhead); sendContentTypeHeader(overhead); sendTransferEncodingHeader(overhead); - sendContentIDHeader(overhead); + sendContentIdHeader(overhead); sendEndOfHeader(overhead); sendEnd(overhead); return overhead.size() + lengthOfData(); diff --git a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java index d7aca075e3..ef42196e27 100644 --- a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java +++ b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java @@ -31,6 +31,7 @@ import com.ning.http.client.ByteArrayPart; import com.ning.http.client.Cookie; import com.ning.http.client.FilePart; +import com.ning.http.client.FluentCaseInsensitiveStringsMap; import com.ning.http.client.FluentStringsMap; import com.ning.http.client.HttpResponseBodyPart; import com.ning.http.client.HttpResponseBodyPartsInputStream; @@ -287,11 +288,11 @@ public final static int getPort(URI uri) { * This is quite ugly as our internal names are duplicated, but we build on top of HTTP Client implementation. * * @param params - * @param methodParams + * @param requestHeaders * @return a MultipartRequestEntity. * @throws java.io.FileNotFoundException */ - public final static MultipartRequestEntity createMultipartRequestEntity(List params, FluentStringsMap methodParams) throws FileNotFoundException { + public final static MultipartRequestEntity createMultipartRequestEntity(List params, FluentCaseInsensitiveStringsMap requestHeaders) throws FileNotFoundException { com.ning.http.multipart.Part[] parts = new com.ning.http.multipart.Part[params.size()]; int i = 0; @@ -323,7 +324,7 @@ public final static MultipartRequestEntity createMultipartRequestEntity(List Date: Mon, 20 May 2013 14:39:51 -0400 Subject: [PATCH 134/264] [maven-release-plugin] prepare release async-http-client-1.7.16 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 9755f31942..4c8bd04759 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.7.16-SNAPSHOT + 1.7.16 jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From 1139a21645f68bed92d3115aea95fc623e2984f6 Mon Sep 17 00:00:00 2001 From: jfarcand Date: Mon, 20 May 2013 14:39:58 -0400 Subject: [PATCH 135/264] [maven-release-plugin] prepare for next development iteration --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 4c8bd04759..9081e6cd72 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.7.16 + 1.7.17-SNAPSHOT jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From eb03603533a5ae365ea48fb7342d2d713527d4e7 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 21 May 2013 18:20:10 +0200 Subject: [PATCH 136/264] Fix Netty privider's ReaperFuture messages, close #281 --- .../netty/NettyAsyncHttpProvider.java | 631 +++++++----------- .../providers/netty/NettyResponseFuture.java | 130 ++-- 2 files changed, 323 insertions(+), 438 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java index 9db866f3e6..ad66cd64eb 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java @@ -15,50 +15,42 @@ */ package com.ning.http.client.providers.netty; +import static com.ning.http.util.AsyncHttpProviderUtils.DEFAULT_CHARSET; +import static com.ning.http.util.DateUtil.millisTime; import static com.ning.http.util.MiscUtil.isNonEmpty; +import static org.jboss.netty.channel.Channels.pipeline; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.net.ConnectException; +import java.net.InetSocketAddress; +import java.net.MalformedURLException; +import java.net.URI; +import java.nio.channels.ClosedChannelException; +import java.nio.channels.FileChannel; +import java.nio.channels.WritableByteChannel; +import java.nio.charset.Charset; +import java.security.GeneralSecurityException; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map.Entry; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.net.ssl.SSLEngine; -import com.ning.org.jboss.netty.handler.codec.http.CookieDecoder; -import com.ning.http.client.AsyncHandler; -import com.ning.http.client.AsyncHandler.STATE; -import com.ning.http.client.AsyncHttpClientConfig; -import com.ning.http.client.AsyncHttpProvider; -import com.ning.http.client.Body; -import com.ning.http.client.BodyGenerator; -import com.ning.http.client.ConnectionPoolKeyStrategy; -import com.ning.http.client.ConnectionsPool; -import com.ning.http.client.Cookie; -import com.ning.http.client.FluentCaseInsensitiveStringsMap; -import com.ning.http.client.HttpResponseBodyPart; -import com.ning.http.client.HttpResponseHeaders; -import com.ning.http.client.HttpResponseStatus; -import com.ning.http.client.ListenableFuture; -import com.ning.http.client.MaxRedirectException; -import com.ning.http.client.PerRequestConfig; -import com.ning.http.client.ProgressAsyncHandler; -import com.ning.http.client.ProxyServer; -import com.ning.http.client.RandomAccessBody; -import com.ning.http.client.Realm; -import com.ning.http.client.Request; -import com.ning.http.client.RequestBuilder; -import com.ning.http.client.Response; -import com.ning.http.client.filter.FilterContext; -import com.ning.http.client.filter.FilterException; -import com.ning.http.client.filter.IOExceptionFilter; -import com.ning.http.client.filter.ResponseFilter; -import com.ning.http.client.generators.InputStreamBodyGenerator; -import com.ning.http.client.listener.TransferCompletionHandler; -import com.ning.http.client.ntlm.NTLMEngine; -import com.ning.http.client.ntlm.NTLMEngineException; -import com.ning.http.client.providers.netty.spnego.SpnegoEngine; -import com.ning.http.client.websocket.WebSocketUpgradeHandler; -import com.ning.http.multipart.MultipartBody; -import com.ning.http.multipart.MultipartRequestEntity; -import com.ning.http.util.AsyncHttpProviderUtils; -import com.ning.http.util.AuthenticatorUtils; -import com.ning.http.util.CleanupChannelGroup; -import com.ning.http.util.ProxyUtils; -import com.ning.http.util.SslUtils; -import com.ning.http.util.UTF8UrlEncoder; import org.jboss.netty.bootstrap.ClientBootstrap; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBufferOutputStream; @@ -107,38 +99,48 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.net.ssl.SSLEngine; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.RandomAccessFile; -import java.net.ConnectException; -import java.net.InetSocketAddress; -import java.net.MalformedURLException; -import java.net.URI; -import java.nio.channels.ClosedChannelException; -import java.nio.channels.FileChannel; -import java.nio.channels.WritableByteChannel; -import java.nio.charset.Charset; -import java.security.GeneralSecurityException; -import java.security.NoSuchAlgorithmException; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.Map.Entry; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.RejectedExecutionException; -import java.util.concurrent.Semaphore; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import java.util.concurrent.atomic.AtomicBoolean; - -import static com.ning.http.util.AsyncHttpProviderUtils.DEFAULT_CHARSET; -import static org.jboss.netty.channel.Channels.pipeline; +import com.ning.http.client.AsyncHandler; +import com.ning.http.client.AsyncHandler.STATE; +import com.ning.http.client.AsyncHttpClientConfig; +import com.ning.http.client.AsyncHttpProvider; +import com.ning.http.client.Body; +import com.ning.http.client.BodyGenerator; +import com.ning.http.client.ConnectionPoolKeyStrategy; +import com.ning.http.client.ConnectionsPool; +import com.ning.http.client.Cookie; +import com.ning.http.client.FluentCaseInsensitiveStringsMap; +import com.ning.http.client.HttpResponseBodyPart; +import com.ning.http.client.HttpResponseHeaders; +import com.ning.http.client.HttpResponseStatus; +import com.ning.http.client.ListenableFuture; +import com.ning.http.client.MaxRedirectException; +import com.ning.http.client.PerRequestConfig; +import com.ning.http.client.ProgressAsyncHandler; +import com.ning.http.client.ProxyServer; +import com.ning.http.client.RandomAccessBody; +import com.ning.http.client.Realm; +import com.ning.http.client.Request; +import com.ning.http.client.RequestBuilder; +import com.ning.http.client.Response; +import com.ning.http.client.filter.FilterContext; +import com.ning.http.client.filter.FilterException; +import com.ning.http.client.filter.IOExceptionFilter; +import com.ning.http.client.filter.ResponseFilter; +import com.ning.http.client.generators.InputStreamBodyGenerator; +import com.ning.http.client.listener.TransferCompletionHandler; +import com.ning.http.client.ntlm.NTLMEngine; +import com.ning.http.client.ntlm.NTLMEngineException; +import com.ning.http.client.providers.netty.spnego.SpnegoEngine; +import com.ning.http.client.websocket.WebSocketUpgradeHandler; +import com.ning.http.multipart.MultipartBody; +import com.ning.http.multipart.MultipartRequestEntity; +import com.ning.http.util.AsyncHttpProviderUtils; +import com.ning.http.util.AuthenticatorUtils; +import com.ning.http.util.CleanupChannelGroup; +import com.ning.http.util.ProxyUtils; +import com.ning.http.util.SslUtils; +import com.ning.http.util.UTF8UrlEncoder; +import com.ning.org.jboss.netty.handler.codec.http.CookieDecoder; public class NettyAsyncHttpProvider extends SimpleChannelUpstreamHandler implements AsyncHttpProvider { private final static String WEBSOCKET_KEY = "Sec-WebSocket-Key"; @@ -166,17 +168,16 @@ public class NettyAsyncHttpProvider extends SimpleChannelUpstreamHandler impleme private int httpsClientCodecMaxHeaderSize = 8192; private int httpsClientCodecMaxChunkSize = 8192; - private final ChannelGroup openChannels = new - CleanupChannelGroup("asyncHttpClient") { - @Override - public boolean remove(Object o) { - boolean removed = super.remove(o); - if (removed && trackConnections) { - freeConnections.release(); - } - return removed; - } - }; + private final ChannelGroup openChannels = new CleanupChannelGroup("asyncHttpClient") { + @Override + public boolean remove(Object o) { + boolean removed = super.remove(o); + if (removed && trackConnections) { + freeConnections.release(); + } + return removed; + } + }; private final ConnectionsPool connectionsPool; private Semaphore freeConnections = null; private final NettyAsyncHttpProviderConfig asyncHttpProviderConfig; @@ -191,8 +192,7 @@ public boolean remove(Object o) { public NettyAsyncHttpProvider(AsyncHttpClientConfig config) { - if (config.getAsyncHttpProviderConfig() != null - && NettyAsyncHttpProviderConfig.class.isAssignableFrom(config.getAsyncHttpProviderConfig().getClass())) { + if (config.getAsyncHttpProviderConfig() != null && NettyAsyncHttpProviderConfig.class.isAssignableFrom(config.getAsyncHttpProviderConfig().getClass())) { asyncHttpProviderConfig = NettyAsyncHttpProviderConfig.class.cast(config.getAsyncHttpProviderConfig()); } else { asyncHttpProviderConfig = new NettyAsyncHttpProviderConfig(); @@ -252,9 +252,9 @@ public NettyAsyncHttpProvider(AsyncHttpClientConfig config) { @Override public String toString() { - return String.format("NettyAsyncHttpProvider:\n\t- maxConnections: %d\n\t- openChannels: %s\n\t- connectionPools: %s", - config.getMaxTotalConnections() - freeConnections.availablePermits(), - openChannels.toString(), + return String.format("NettyAsyncHttpProvider:\n\t- maxConnections: %d\n\t- openChannels: %s\n\t- connectionPools: %s",// + config.getMaxTotalConnections() - freeConnections.availablePermits(),// + openChannels.toString(),// connectionsPool.toString()); } @@ -312,39 +312,15 @@ public ChannelPipeline getPipeline() throws Exception { } protected void configureHttpClientCodec() { - httpClientCodecMaxInitialLineLength = asyncHttpProviderConfig.getProperty( - NettyAsyncHttpProviderConfig.HTTP_CLIENT_CODEC_MAX_INITIAL_LINE_LENGTH, - Integer.class, - httpClientCodecMaxInitialLineLength - ); - httpClientCodecMaxHeaderSize = asyncHttpProviderConfig.getProperty( - NettyAsyncHttpProviderConfig.HTTP_CLIENT_CODEC_MAX_HEADER_SIZE, - Integer.class, - httpClientCodecMaxHeaderSize - ); - httpClientCodecMaxChunkSize = asyncHttpProviderConfig.getProperty( - NettyAsyncHttpProviderConfig.HTTP_CLIENT_CODEC_MAX_CHUNK_SIZE, - Integer.class, - httpClientCodecMaxChunkSize - ); + httpClientCodecMaxInitialLineLength = asyncHttpProviderConfig.getProperty(NettyAsyncHttpProviderConfig.HTTP_CLIENT_CODEC_MAX_INITIAL_LINE_LENGTH, Integer.class, httpClientCodecMaxInitialLineLength); + httpClientCodecMaxHeaderSize = asyncHttpProviderConfig.getProperty(NettyAsyncHttpProviderConfig.HTTP_CLIENT_CODEC_MAX_HEADER_SIZE, Integer.class, httpClientCodecMaxHeaderSize); + httpClientCodecMaxChunkSize = asyncHttpProviderConfig.getProperty(NettyAsyncHttpProviderConfig.HTTP_CLIENT_CODEC_MAX_CHUNK_SIZE, Integer.class, httpClientCodecMaxChunkSize); } protected void configureHttpsClientCodec() { - httpsClientCodecMaxInitialLineLength = asyncHttpProviderConfig.getProperty( - NettyAsyncHttpProviderConfig.HTTPS_CLIENT_CODEC_MAX_INITIAL_LINE_LENGTH, - Integer.class, - httpsClientCodecMaxInitialLineLength - ); - httpsClientCodecMaxHeaderSize = asyncHttpProviderConfig.getProperty( - NettyAsyncHttpProviderConfig.HTTPS_CLIENT_CODEC_MAX_HEADER_SIZE, - Integer.class, - httpsClientCodecMaxHeaderSize - ); - httpsClientCodecMaxChunkSize = asyncHttpProviderConfig.getProperty( - NettyAsyncHttpProviderConfig.HTTPS_CLIENT_CODEC_MAX_CHUNK_SIZE, - Integer.class, - httpsClientCodecMaxChunkSize - ); + httpsClientCodecMaxInitialLineLength = asyncHttpProviderConfig.getProperty(NettyAsyncHttpProviderConfig.HTTPS_CLIENT_CODEC_MAX_INITIAL_LINE_LENGTH, Integer.class, httpsClientCodecMaxInitialLineLength); + httpsClientCodecMaxHeaderSize = asyncHttpProviderConfig.getProperty(NettyAsyncHttpProviderConfig.HTTPS_CLIENT_CODEC_MAX_HEADER_SIZE, Integer.class, httpsClientCodecMaxHeaderSize); + httpsClientCodecMaxChunkSize = asyncHttpProviderConfig.getProperty(NettyAsyncHttpProviderConfig.HTTPS_CLIENT_CODEC_MAX_CHUNK_SIZE, Integer.class, httpsClientCodecMaxChunkSize); } void constructSSLPipeline(final NettyConnectListener cl) { @@ -427,11 +403,11 @@ private SSLEngine createSSLEngine() throws IOException, GeneralSecurityException } private HttpClientCodec createHttpClientCodec() { - return new HttpClientCodec(httpClientCodecMaxInitialLineLength, httpClientCodecMaxHeaderSize, httpClientCodecMaxChunkSize); + return new HttpClientCodec(httpClientCodecMaxInitialLineLength, httpClientCodecMaxHeaderSize, httpClientCodecMaxChunkSize); } private HttpClientCodec createHttpsClientCodec() { - return new HttpClientCodec(httpsClientCodecMaxInitialLineLength, httpsClientCodecMaxHeaderSize, httpsClientCodecMaxChunkSize); + return new HttpClientCodec(httpsClientCodecMaxInitialLineLength, httpsClientCodecMaxHeaderSize, httpsClientCodecMaxChunkSize); } private Channel verifyChannelPipeline(Channel channel, String scheme) throws IOException, GeneralSecurityException { @@ -446,14 +422,10 @@ private Channel verifyChannelPipeline(Channel channel, String scheme) throws IOE return channel; } - protected final void writeRequest(final Channel channel, - final AsyncHttpClientConfig config, - final NettyResponseFuture future, - final HttpRequest nettyRequest) { + protected final void writeRequest(final Channel channel, final AsyncHttpClientConfig config, final NettyResponseFuture future, final HttpRequest nettyRequest) { try { /** - * If the channel is dead because it was pooled and the remote server decided to close it, - * we just let it go and the closeChannel do it's work. + * If the channel is dead because it was pooled and the remote server decided to close it, we just let it go and the closeChannel do it's work. */ if (!channel.isOpen() || !channel.isConnected()) { return; @@ -493,8 +465,7 @@ protected final void writeRequest(final Channel channel, } } - TransferCompletionHandler.class.cast(future.getAsyncHandler()).transferAdapter( - new NettyTransferAdapter(h, nettyRequest.getContent(), future.getRequest().getFile())); + TransferCompletionHandler.class.cast(future.getAsyncHandler()).transferAdapter(new NettyTransferAdapter(h, nettyRequest.getContent(), future.getRequest().getFile())); } // Leave it to true. @@ -592,7 +563,7 @@ public void operationComplete(ChannelFuture cf) { try { future.touch(); - int delay = Math.min(config.getIdleConnectionTimeoutInMs(), requestTimeout(config, future.getRequest().getPerRequestConfig())); + int delay = Math.min(config.getIdleConnectionTimeoutInMs(), requestTimeoutInMs(config, future.getRequest().getPerRequestConfig())); if (delay != -1 && !future.isDone() && !future.isCancelled()) { ReaperFuture reaperFuture = new ReaperFuture(future); Future scheduledFuture = config.reaper().scheduleAtFixedRate(reaperFuture, 0, delay, TimeUnit.MILLISECONDS); @@ -605,8 +576,7 @@ public void operationComplete(ChannelFuture cf) { } - protected final static HttpRequest buildRequest(AsyncHttpClientConfig config, Request request, URI uri, - boolean allowConnect, ChannelBuffer buffer, ProxyServer proxyServer) throws IOException { + protected final static HttpRequest buildRequest(AsyncHttpClientConfig config, Request request, URI uri, boolean allowConnect, ChannelBuffer buffer, ProxyServer proxyServer) throws IOException { String method = request.getMethod(); if (allowConnect && proxyServer != null && isSecure(uri)) { @@ -616,17 +586,12 @@ protected final static HttpRequest buildRequest(AsyncHttpClientConfig config, Re } private static SpnegoEngine getSpnegoEngine() { - if(spnegoEngine == null) + if (spnegoEngine == null) spnegoEngine = new SpnegoEngine(); return spnegoEngine; } - private static HttpRequest construct(AsyncHttpClientConfig config, - Request request, - HttpMethod m, - URI uri, - ChannelBuffer buffer, - ProxyServer proxyServer) throws IOException { + private static HttpRequest construct(AsyncHttpClientConfig config, Request request, HttpMethod m, URI uri, ChannelBuffer buffer, ProxyServer proxyServer) throws IOException { String host = AsyncHttpProviderUtils.getHost(uri); @@ -704,47 +669,44 @@ else if (uri.getRawQuery() != null) } switch (realm.getAuthScheme()) { - case BASIC: - nettyRequest.setHeader(HttpHeaders.Names.AUTHORIZATION, - AuthenticatorUtils.computeBasicAuthentication(realm)); - break; - case DIGEST: - if (isNonEmpty(realm.getNonce())) { - try { - nettyRequest.setHeader(HttpHeaders.Names.AUTHORIZATION, - AuthenticatorUtils.computeDigestAuthentication(realm)); - } catch (NoSuchAlgorithmException e) { - throw new SecurityException(e); - } - } - break; - case NTLM: - try { - nettyRequest.setHeader(HttpHeaders.Names.AUTHORIZATION, - ntlmEngine.generateType1Msg("NTLM " + domain, authHost)); - } catch (NTLMEngineException e) { - IOException ie = new IOException(); - ie.initCause(e); - throw ie; - } - break; - case KERBEROS: - case SPNEGO: - String challengeHeader = null; - String server = proxyServer == null ? host : proxyServer.getHost(); + case BASIC: + nettyRequest.setHeader(HttpHeaders.Names.AUTHORIZATION, AuthenticatorUtils.computeBasicAuthentication(realm)); + break; + case DIGEST: + if (isNonEmpty(realm.getNonce())) { try { - challengeHeader = getSpnegoEngine().generateToken(server); - } catch (Throwable e) { - IOException ie = new IOException(); - ie.initCause(e); - throw ie; + nettyRequest.setHeader(HttpHeaders.Names.AUTHORIZATION, AuthenticatorUtils.computeDigestAuthentication(realm)); + } catch (NoSuchAlgorithmException e) { + throw new SecurityException(e); } - nettyRequest.setHeader(HttpHeaders.Names.AUTHORIZATION, "Negotiate " + challengeHeader); - break; - case NONE: - break; - default: - throw new IllegalStateException(String.format("Invalid Authentication %s", realm.toString())); + } + break; + case NTLM: + try { + nettyRequest.setHeader(HttpHeaders.Names.AUTHORIZATION, ntlmEngine.generateType1Msg("NTLM " + domain, authHost)); + } catch (NTLMEngineException e) { + IOException ie = new IOException(); + ie.initCause(e); + throw ie; + } + break; + case KERBEROS: + case SPNEGO: + String challengeHeader = null; + String server = proxyServer == null ? host : proxyServer.getHost(); + try { + challengeHeader = getSpnegoEngine().generateToken(server); + } catch (Throwable e) { + IOException ie = new IOException(); + ie.initCause(e); + throw ie; + } + nettyRequest.setHeader(HttpHeaders.Names.AUTHORIZATION, "Negotiate " + challengeHeader); + break; + case NONE: + break; + default: + throw new IllegalStateException(String.format("Invalid Authentication %s", realm.toString())); } } @@ -763,8 +725,7 @@ else if (uri.getRawQuery() != null) List auth = request.getHeaders().get(HttpHeaders.Names.PROXY_AUTHORIZATION); if (!(auth != null && auth.size() > 0 && auth.get(0).startsWith("NTLM"))) { try { - String msg = ntlmEngine.generateType1Msg(proxyServer.getNtlmDomain(), - proxyServer.getHost()); + String msg = ntlmEngine.generateType1Msg(proxyServer.getNtlmDomain(), proxyServer.getHost()); nettyRequest.setHeader(HttpHeaders.Names.PROXY_AUTHORIZATION, "NTLM " + msg); } catch (NTLMEngineException e) { IOException ie = new IOException(); @@ -773,8 +734,7 @@ else if (uri.getRawQuery() != null) } } } else { - nettyRequest.setHeader(HttpHeaders.Names.PROXY_AUTHORIZATION, - AuthenticatorUtils.computeBasicAuthentication(proxyServer)); + nettyRequest.setHeader(HttpHeaders.Names.PROXY_AUTHORIZATION, AuthenticatorUtils.computeBasicAuthentication(proxyServer)); } } } @@ -859,7 +819,7 @@ else if (uri.getRawQuery() != null) } MultipartRequestEntity mre = AsyncHttpProviderUtils.createMultipartRequestEntity(request.getParts(), request.getHeaders()); - + nettyRequest.setHeader(HttpHeaders.Names.CONTENT_TYPE, mre.getContentType()); nettyRequest.setHeader(HttpHeaders.Names.CONTENT_LENGTH, String.valueOf(mre.getContentLength())); @@ -925,9 +885,7 @@ public void close() { /* @Override */ - public Response prepareResponse(final HttpResponseStatus status, - final HttpResponseHeaders headers, - final List bodyParts) { + public Response prepareResponse(final HttpResponseStatus status, final HttpResponseHeaders headers, final List bodyParts) { return new NettyResponse(status, headers, bodyParts); } @@ -941,8 +899,7 @@ private void execute(final Request request, final NettyResponseFuture f, doConnect(request, f.getAsyncHandler(), f, useCache, asyncConnect, reclaimCache); } - private ListenableFuture doConnect(final Request request, final AsyncHandler asyncHandler, NettyResponseFuture f, - boolean useCache, boolean asyncConnect, boolean reclaimCache) throws IOException { + private ListenableFuture doConnect(final Request request, final AsyncHandler asyncHandler, NettyResponseFuture f, boolean useCache, boolean asyncConnect, boolean reclaimCache) throws IOException { if (isClose.get()) { throw new IOException("Closed"); @@ -967,14 +924,13 @@ private ListenableFuture doConnect(final Request request, final AsyncHand if (f != null && f.reuseChannel() && f.channel() != null) { channel = f.channel(); } else { - URI connectionKeyUri = useProxy? proxyServer.getURI() : uri; + URI connectionKeyUri = useProxy ? proxyServer.getURI() : uri; channel = lookupInCache(connectionKeyUri, request.getConnectionPoolKeyStrategy()); } } ChannelBuffer bufferedBytes = null; - if (f != null && f.getRequest().getFile() == null && - !f.getNettyRequest().getMethod().getName().equals(HttpMethod.CONNECT.getName())) { + if (f != null && f.getRequest().getFile() == null && !f.getNettyRequest().getMethod().getName().equals(HttpMethod.CONNECT.getName())) { bufferedBytes = f.getNettyRequest().getContent(); } @@ -1069,9 +1025,9 @@ private ListenableFuture doConnect(final Request request, final AsyncHand remoteAddress = new InetSocketAddress(proxyServer.getHost(), proxyServer.getPort()); } - if(request.getLocalAddress() != null){ + if (request.getLocalAddress() != null) { channelFuture = bootstrap.connect(remoteAddress, new InetSocketAddress(request.getLocalAddress(), 0)); - }else{ + } else { channelFuture = bootstrap.connect(remoteAddress); } @@ -1126,7 +1082,7 @@ private ListenableFuture doConnect(final Request request, final AsyncHand return c.future(); } - protected static int requestTimeout(AsyncHttpClientConfig config, PerRequestConfig perRequestConfig) { + protected static int requestTimeoutInMs(AsyncHttpClientConfig config, PerRequestConfig perRequestConfig) { int result; if (perRequestConfig != null) { int prRequestTimeout = perRequestConfig.getRequestTimeoutInMs(); @@ -1152,7 +1108,6 @@ private void finishChannel(final ChannelHandlerContext ctx) { log.debug("Closing Channel {} ", ctx.getChannel()); - try { ctx.getChannel().close(); } catch (Throwable t) { @@ -1167,7 +1122,7 @@ private void finishChannel(final ChannelHandlerContext ctx) { @Override public void messageReceived(final ChannelHandlerContext ctx, MessageEvent e) throws Exception { - //call super to reset the read timeout + // call super to reset the read timeout super.messageReceived(ctx, e); IN_IO_THREAD.set(Boolean.TRUE); if (ctx.getAttachment() == null) { @@ -1204,12 +1159,7 @@ public void messageReceived(final ChannelHandlerContext ctx, MessageEvent e) thr p.handle(ctx, e); } - private Realm kerberosChallenge(List proxyAuth, - Request request, - ProxyServer proxyServer, - FluentCaseInsensitiveStringsMap headers, - Realm realm, - NettyResponseFuture future) throws NTLMEngineException { + private Realm kerberosChallenge(List proxyAuth, Request request, ProxyServer proxyServer, FluentCaseInsensitiveStringsMap headers, Realm realm, NettyResponseFuture future) throws NTLMEngineException { URI uri = request.getURI(); String host = request.getVirtualHost() == null ? AsyncHttpProviderUtils.getHost(uri) : request.getVirtualHost(); @@ -1225,10 +1175,7 @@ private Realm kerberosChallenge(List proxyAuth, } else { realmBuilder = new Realm.RealmBuilder(); } - return realmBuilder.setUri(uri.getRawPath()) - .setMethodName(request.getMethod()) - .setScheme(Realm.AuthScheme.KERBEROS) - .build(); + return realmBuilder.setUri(uri.getRawPath()).setMethodName(request.getMethod()).setScheme(Realm.AuthScheme.KERBEROS).build(); } catch (Throwable throwable) { if (proxyAuth.contains("NTLM")) { return ntlmChallenge(proxyAuth, request, proxyServer, headers, realm, future); @@ -1238,12 +1185,7 @@ private Realm kerberosChallenge(List proxyAuth, } } - private Realm ntlmChallenge(List wwwAuth, - Request request, - ProxyServer proxyServer, - FluentCaseInsensitiveStringsMap headers, - Realm realm, - NettyResponseFuture future) throws NTLMEngineException { + private Realm ntlmChallenge(List wwwAuth, Request request, ProxyServer proxyServer, FluentCaseInsensitiveStringsMap headers, Realm realm, NettyResponseFuture future) throws NTLMEngineException { boolean useRealm = (proxyServer == null && realm != null); @@ -1258,19 +1200,14 @@ private Realm ntlmChallenge(List wwwAuth, URI uri = request.getURI(); headers.add(HttpHeaders.Names.AUTHORIZATION, "NTLM " + challengeHeader); - newRealm = new Realm.RealmBuilder().clone(realm).setScheme(realm.getAuthScheme()) - .setUri(uri.getRawPath()) - .setMethodName(request.getMethod()) - .setNtlmMessageType2Received(true) - .build(); + newRealm = new Realm.RealmBuilder().clone(realm).setScheme(realm.getAuthScheme()).setUri(uri.getRawPath()).setMethodName(request.getMethod()).setNtlmMessageType2Received(true).build(); future.getAndSetAuth(false); } else { headers.remove(HttpHeaders.Names.AUTHORIZATION); if (wwwAuth.get(0).startsWith("NTLM ")) { String serverChallenge = wwwAuth.get(0).trim().substring("NTLM ".length()); - String challengeHeader = ntlmEngine.generateType3Msg(principal, password, - ntlmDomain, ntlmHost, serverChallenge); + String challengeHeader = ntlmEngine.generateType3Msg(principal, password, ntlmDomain, ntlmHost, serverChallenge); headers.add(HttpHeaders.Names.AUTHORIZATION, "NTLM " + challengeHeader); } @@ -1284,31 +1221,19 @@ private Realm ntlmChallenge(List wwwAuth, realmBuilder = new Realm.RealmBuilder(); authScheme = Realm.AuthScheme.NTLM; } - newRealm = realmBuilder.setScheme(authScheme) - .setUri(request.getURI().getPath()) - .setMethodName(request.getMethod()) - .build(); + newRealm = realmBuilder.setScheme(authScheme).setUri(request.getURI().getPath()).setMethodName(request.getMethod()).build(); } return newRealm; } - private Realm ntlmProxyChallenge(List wwwAuth, - Request request, - ProxyServer proxyServer, - FluentCaseInsensitiveStringsMap headers, - Realm realm, - NettyResponseFuture future) throws NTLMEngineException { + private Realm ntlmProxyChallenge(List wwwAuth, Request request, ProxyServer proxyServer, FluentCaseInsensitiveStringsMap headers, Realm realm, NettyResponseFuture future) throws NTLMEngineException { future.getAndSetAuth(false); headers.remove(HttpHeaders.Names.PROXY_AUTHORIZATION); if (wwwAuth.get(0).startsWith("NTLM ")) { String serverChallenge = wwwAuth.get(0).trim().substring("NTLM ".length()); - String challengeHeader = ntlmEngine.generateType3Msg(proxyServer.getPrincipal(), - proxyServer.getPassword(), - proxyServer.getNtlmDomain(), - proxyServer.getHost(), - serverChallenge); + String challengeHeader = ntlmEngine.generateType3Msg(proxyServer.getPrincipal(), proxyServer.getPassword(), proxyServer.getNtlmDomain(), proxyServer.getHost(), serverChallenge); headers.add(HttpHeaders.Names.PROXY_AUTHORIZATION, "NTLM " + challengeHeader); } Realm newRealm; @@ -1318,14 +1243,11 @@ private Realm ntlmProxyChallenge(List wwwAuth, } else { realmBuilder = new Realm.RealmBuilder(); } - newRealm = realmBuilder - .setUri(request.getURI().getPath()) - .setMethodName(request.getMethod()) - .build(); + newRealm = realmBuilder.setUri(request.getURI().getPath()).setMethodName(request.getMethod()).build(); return newRealm; } - + private String getPoolKey(NettyResponseFuture future) throws MalformedURLException { URI uri = future.getProxyServer() != null ? future.getProxyServer().getURI() : future.getURI(); return future.getConnectionPoolKeyStrategy().getKey(uri); @@ -1334,7 +1256,7 @@ private String getPoolKey(NettyResponseFuture future) throws MalformedURLExce private void drainChannel(final ChannelHandlerContext ctx, final NettyResponseFuture future) { ctx.setAttachment(new AsyncCallable(future) { public Object call() throws Exception { - + if (future.getKeepAlive() && ctx.getChannel().isReadable() && connectionsPool.offer(getPoolKey(future), ctx.getChannel())) { return null; } @@ -1454,8 +1376,7 @@ public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws future.touch(); if (config.getIOExceptionFilters().size() > 0) { - FilterContext fc = new FilterContext.FilterContextBuilder().asyncHandler(future.getAsyncHandler()) - .request(future.getRequest()).ioException(new IOException("Channel Closed")).build(); + FilterContext fc = new FilterContext.FilterContextBuilder().asyncHandler(future.getAsyncHandler()).request(future.getRequest()).ioException(new IOException("Channel Closed")).build(); fc = handleIoException(fc, future); if (fc.replayRequest() && !future.cannotBeReplay()) { @@ -1485,11 +1406,8 @@ protected boolean remotelyClosed(Channel channel, NettyResponseFuture future) connectionsPool.removeAll(channel); - if (future == null && channel.getPipeline().getContext(NettyAsyncHttpProvider.class).getAttachment() != null - && NettyResponseFuture.class.isAssignableFrom( - channel.getPipeline().getContext(NettyAsyncHttpProvider.class).getAttachment().getClass())) { - future = (NettyResponseFuture) - channel.getPipeline().getContext(NettyAsyncHttpProvider.class).getAttachment(); + if (future == null && channel.getPipeline().getContext(NettyAsyncHttpProvider.class).getAttachment() != null && NettyResponseFuture.class.isAssignableFrom(channel.getPipeline().getContext(NettyAsyncHttpProvider.class).getAttachment().getClass())) { + future = (NettyResponseFuture) channel.getPipeline().getContext(NettyAsyncHttpProvider.class).getAttachment(); } if (future == null || future.cannotBeReplay()) { @@ -1558,23 +1476,20 @@ private final boolean updateBodyAndInterrupt(final NettyResponseFuture future return state; } - //Simple marker for stopping publishing bytes. + // Simple marker for stopping publishing bytes. final static class DiscardEvent { } @Override - public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) - throws Exception { + public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { Channel channel = e.getChannel(); Throwable cause = e.getCause(); NettyResponseFuture future = null; - /** Issue 81 - if (e.getCause() != null && e.getCause().getClass().isAssignableFrom(PrematureChannelClosureException.class)) { - return; - } - */ + /** + * Issue 81 if (e.getCause() != null && e.getCause().getClass().isAssignableFrom(PrematureChannelClosureException.class)) { return; } + */ if (e.getCause() != null && e.getCause().getClass().getSimpleName().equals("PrematureChannelClosureException")) { return; } @@ -1597,8 +1512,7 @@ public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) if (IOException.class.isAssignableFrom(cause.getClass())) { if (config.getIOExceptionFilters().size() > 0) { - FilterContext fc = new FilterContext.FilterContextBuilder().asyncHandler(future.getAsyncHandler()) - .request(future.getRequest()).ioException(new IOException("Channel Closed")).build(); + FilterContext fc = new FilterContext.FilterContextBuilder().asyncHandler(future.getAsyncHandler()).request(future.getRequest()).ioException(new IOException("Channel Closed")).build(); fc = handleIoException(fc, future); if (fc.replayRequest()) { @@ -1646,8 +1560,7 @@ public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) protected static boolean abortOnConnectCloseException(Throwable cause) { try { for (StackTraceElement element : cause.getStackTrace()) { - if (element.getClassName().equals("sun.nio.ch.SocketChannelImpl") - && element.getMethodName().equals("checkConnect")) { + if (element.getClassName().equals("sun.nio.ch.SocketChannelImpl") && element.getMethodName().equals("checkConnect")) { return true; } } @@ -1664,8 +1577,7 @@ protected static boolean abortOnConnectCloseException(Throwable cause) { protected static boolean abortOnDisconnectException(Throwable cause) { try { for (StackTraceElement element : cause.getStackTrace()) { - if (element.getClassName().equals("org.jboss.netty.handler.ssl.SslHandler") - && element.getMethodName().equals("channelDisconnected")) { + if (element.getClassName().equals("org.jboss.netty.handler.ssl.SslHandler") && element.getMethodName().equals("channelDisconnected")) { return true; } } @@ -1682,8 +1594,7 @@ protected static boolean abortOnDisconnectException(Throwable cause) { protected static boolean abortOnReadCloseException(Throwable cause) { for (StackTraceElement element : cause.getStackTrace()) { - if (element.getClassName().equals("sun.nio.ch.SocketDispatcher") - && element.getMethodName().equals("read")) { + if (element.getClassName().equals("sun.nio.ch.SocketDispatcher") && element.getMethodName().equals("read")) { return true; } } @@ -1698,8 +1609,7 @@ protected static boolean abortOnReadCloseException(Throwable cause) { protected static boolean abortOnWriteCloseException(Throwable cause) { for (StackTraceElement element : cause.getStackTrace()) { - if (element.getClassName().equals("sun.nio.ch.SocketDispatcher") - && element.getMethodName().equals("write")) { + if (element.getClassName().equals("sun.nio.ch.SocketDispatcher") && element.getMethodName().equals("write")) { return true; } } @@ -1723,19 +1633,19 @@ private final static int computeAndSetContentLength(Request request, HttpRequest return length; } - public static NettyResponseFuture newFuture(URI uri, - Request request, - AsyncHandler asyncHandler, - HttpRequest nettyRequest, - AsyncHttpClientConfig config, - NettyAsyncHttpProvider provider, - ProxyServer proxyServer) { + public static NettyResponseFuture newFuture(URI uri, Request request, AsyncHandler asyncHandler, HttpRequest nettyRequest, AsyncHttpClientConfig config, NettyAsyncHttpProvider provider, ProxyServer proxyServer) { - NettyResponseFuture f = new NettyResponseFuture(uri, request, asyncHandler, nettyRequest, - requestTimeout(config, request.getPerRequestConfig()), config.getIdleConnectionTimeoutInMs(), provider, request.getConnectionPoolKeyStrategy(), proxyServer); + NettyResponseFuture f = new NettyResponseFuture(uri,// + request,// + asyncHandler,// + nettyRequest,// + requestTimeoutInMs(config, request.getPerRequestConfig()),// + config.getIdleConnectionTimeoutInMs(),// + provider,// + request.getConnectionPoolKeyStrategy(),// + proxyServer); - if (request.getHeaders().getFirstValue("Expect") != null - && request.getHeaders().getFirstValue("Expect").equalsIgnoreCase("100-Continue")) { + if (request.getHeaders().getFirstValue("Expect") != null && request.getHeaders().getFirstValue("Expect").equalsIgnoreCase("100-Continue")) { f.getAndSetWriteBody(false); } return f; @@ -1769,9 +1679,7 @@ public void operationComplete(ChannelFuture cf) { return; } - if (ClosedChannelException.class.isAssignableFrom(cause.getClass()) - || abortOnReadCloseException(cause) - || abortOnWriteCloseException(cause)) { + if (ClosedChannelException.class.isAssignableFrom(cause.getClass()) || abortOnReadCloseException(cause) || abortOnWriteCloseException(cause)) { if (log.isDebugEnabled()) { log.debug(cf.getCause() == null ? "" : cf.getCause().getMessage(), cf.getCause()); @@ -1791,13 +1699,10 @@ public void operationComplete(ChannelFuture cf) { future.touch(); /** - * We need to make sure we aren't in the middle of an authorization process before publishing events - * as we will re-publish again the same event after the authorization, causing unpredictable behavior. + * We need to make sure we aren't in the middle of an authorization process before publishing events as we will re-publish again the same event after the authorization, causing unpredictable behavior. */ Realm realm = future.getRequest().getRealm() != null ? future.getRequest().getRealm() : NettyAsyncHttpProvider.this.getConfig().getRealm(); - boolean startPublishing = future.isInAuth() - || realm == null - || realm.getUsePreemptiveAuth() == true; + boolean startPublishing = future.isInAuth() || realm == null || realm.getUsePreemptiveAuth() == true; if (startPublishing && ProgressAsyncHandler.class.isAssignableFrom(asyncHandler.getClass())) { if (notifyHeaders) { @@ -1817,10 +1722,8 @@ public void operationProgressed(ChannelFuture cf, long amount, long current, lon } /** - * Because some implementation of the ThreadSchedulingService do not clean up cancel task until they try to run - * them, we wrap the task with the future so the when the NettyResponseFuture cancel the reaper future - * this wrapper will release the references to the channel and the nettyResponseFuture immediately. Otherwise, - * the memory referenced this way will only be released after the request timeout period which can be arbitrary long. + * Because some implementation of the ThreadSchedulingService do not clean up cancel task until they try to run them, we wrap the task with the future so the when the NettyResponseFuture cancel the reaper future this wrapper will release the references to the channel and the + * nettyResponseFuture immediately. Otherwise, the memory referenced this way will only be released after the request timeout period which can be arbitrary long. */ private final class ReaperFuture implements Future, Runnable { private Future scheduledFuture; @@ -1870,6 +1773,12 @@ public boolean isDone() { return scheduledFuture.isDone(); } + private void expire(String message) { + log.debug("{} for {}", message, nettyResponseFuture); + abort(nettyResponseFuture, new TimeoutException(message)); + nettyResponseFuture = null; + } + /** * @Override */ @@ -1879,22 +1788,22 @@ public synchronized void run() { return; } - if (nettyResponseFuture != null && nettyResponseFuture.hasExpired() - && !nettyResponseFuture.isDone() && !nettyResponseFuture.isCancelled()) { - log.debug("Request Timeout expired for {}\n", nettyResponseFuture); + boolean futureDone = nettyResponseFuture.isDone(); + boolean futureCanceled = nettyResponseFuture.isCancelled(); - int requestTimeout = config.getRequestTimeoutInMs(); - PerRequestConfig p = nettyResponseFuture.getRequest().getPerRequestConfig(); - if (p != null && p.getRequestTimeoutInMs() != -1) { - requestTimeout = p.getRequestTimeoutInMs(); - } + if (nettyResponseFuture != null && !futureDone && !futureCanceled) { - abort(nettyResponseFuture, new TimeoutException(String.format("No response received after %s", requestTimeout))); + long now = millisTime(); + if (nettyResponseFuture.hasRequestTimedOut(now)) { + long age = (now - nettyResponseFuture.getStart()) / 1000000; + expire("Request reached time out of " + nettyResponseFuture.getRequestTimeoutInMs() + " ms after " + age + " ms"); - nettyResponseFuture = null; - } + } else if (nettyResponseFuture.hasConnectionIdleTimedOut(now)) { + long age = (now - nettyResponseFuture.getStart()) / 1000000; + expire("Request reached idle time out of " + nettyResponseFuture.getIdleConnectionTimeoutInMs() + " ms after " + age + " ms"); + } - if (nettyResponseFuture == null || nettyResponseFuture.isDone() || nettyResponseFuture.isCancelled()) { + } else if (nettyResponseFuture == null || futureDone || futureCanceled) { cancel(true); } } @@ -1959,9 +1868,7 @@ public long getCount() { public long transferTo(WritableByteChannel target, long position) throws IOException { long count = this.count - position; if (count < 0 || position < 0) { - throw new IllegalArgumentException( - "position out of range: " + position + - " (expected: 0 - " + (this.count - 1) + ")"); + throw new IllegalArgumentException("position out of range: " + position + " (expected: 0 - " + (this.count - 1) + ")"); } if (count == 0) { return 0L; @@ -2054,17 +1961,11 @@ private static final boolean validateWebSocketRequest(Request request, AsyncHand return true; } - private boolean redirect(Request request, - NettyResponseFuture future, - HttpResponse response, - final ChannelHandlerContext ctx) throws Exception { + private boolean redirect(Request request, NettyResponseFuture future, HttpResponse response, final ChannelHandlerContext ctx) throws Exception { int statusCode = response.getStatus().getCode(); boolean redirectEnabled = request.isRedirectOverrideSet() ? request.isRedirectEnabled() : config.isRedirectEnabled(); - if (redirectEnabled && (statusCode == 302 - || statusCode == 301 - || statusCode == 303 - || statusCode == 307)) { + if (redirectEnabled && (statusCode == 302 || statusCode == 301 || statusCode == 303 || statusCode == 307)) { if (future.incrementAndGetCurrentRedirectCount() < config.getMaxRedirects()) { // We must allow 401 handling again. @@ -2074,13 +1975,9 @@ private boolean redirect(Request request, URI uri = AsyncHttpProviderUtils.getRedirectUri(future.getURI(), location); boolean stripQueryString = config.isRemoveQueryParamOnRedirect(); if (!uri.toString().equals(future.getURI().toString())) { - final RequestBuilder nBuilder = stripQueryString ? - new RequestBuilder(future.getRequest()).setQueryParameters(null) - : new RequestBuilder(future.getRequest()); + final RequestBuilder nBuilder = stripQueryString ? new RequestBuilder(future.getRequest()).setQueryParameters(null) : new RequestBuilder(future.getRequest()); - if (!(statusCode < 302 || statusCode > 303) - && !(statusCode == 302 - && config.isStrict302Handling())) { + if (!(statusCode < 302 || statusCode > 303) && !(statusCode == 302 && config.isStrict302Handling())) { nBuilder.setMethod("GET"); } final boolean initialConnectionKeepAlive = future.getKeepAlive(); @@ -2166,12 +2063,7 @@ public void handle(final ChannelHandlerContext ctx, final MessageEvent e) throws HttpResponseStatus status = new ResponseStatus(future.getURI(), response, NettyAsyncHttpProvider.this); HttpResponseHeaders responseHeaders = new ResponseHeaders(future.getURI(), response, NettyAsyncHttpProvider.this); - FilterContext fc = new FilterContext.FilterContextBuilder() - .asyncHandler(handler) - .request(request) - .responseStatus(status) - .responseHeaders(responseHeaders) - .build(); + FilterContext fc = new FilterContext.FilterContextBuilder().asyncHandler(handler).request(request).responseStatus(status).responseHeaders(responseHeaders).build(); for (ResponseFilter asyncFilter : config.getResponseFilters()) { try { @@ -2198,14 +2090,11 @@ public void handle(final ChannelHandlerContext ctx, final MessageEvent e) throws final FluentCaseInsensitiveStringsMap headers = request.getHeaders(); final RequestBuilder builder = new RequestBuilder(future.getRequest()); - //if (realm != null && !future.getURI().getPath().equalsIgnoreCase(realm.getUri())) { - // builder.setUrl(future.getURI().toString()); - //} + // if (realm != null && !future.getURI().getPath().equalsIgnoreCase(realm.getUri())) { + // builder.setUrl(future.getURI().toString()); + // } - if (statusCode == 401 - && realm != null - && wwwAuth.size() > 0 - && !future.getAndSetAuth(true)) { + if (statusCode == 401 && realm != null && wwwAuth.size() > 0 && !future.getAndSetAuth(true)) { future.setState(NettyResponseFuture.STATE.NEW); // NTLM @@ -2214,25 +2103,19 @@ public void handle(final ChannelHandlerContext ctx, final MessageEvent e) throws // SPNEGO KERBEROS } else if (wwwAuth.contains("Negotiate")) { newRealm = kerberosChallenge(wwwAuth, request, proxyServer, headers, realm, future); - if (newRealm == null) return; + if (newRealm == null) + return; } else { Realm.RealmBuilder realmBuilder; if (realm != null) { - realmBuilder = new Realm.RealmBuilder().clone(realm).setScheme(realm.getAuthScheme()) - ; + realmBuilder = new Realm.RealmBuilder().clone(realm).setScheme(realm.getAuthScheme()); } else { realmBuilder = new Realm.RealmBuilder(); } - newRealm = realmBuilder - .setUri(request.getURI().getPath()) - .setMethodName(request.getMethod()) - .setUsePreemptiveAuth(true) - .parseWWWAuthenticateHeader(wwwAuth.get(0)) - .build(); + newRealm = realmBuilder.setUri(request.getURI().getPath()).setMethodName(request.getMethod()).setUsePreemptiveAuth(true).parseWWWAuthenticateHeader(wwwAuth.get(0)).build(); } - final Realm nr = new Realm.RealmBuilder().clone(newRealm) - .setUri(request.getUrl()).build(); + final Realm nr = new Realm.RealmBuilder().clone(newRealm).setUri(request.getUrl()).build(); log.debug("Sending authentication to {}", request.getUrl()); AsyncCallable ac = new AsyncCallable(future) { @@ -2260,10 +2143,7 @@ public Object call() throws Exception { } List proxyAuth = getAuthorizationToken(response.getHeaders(), HttpHeaders.Names.PROXY_AUTHENTICATE); - if (statusCode == 407 - && realm != null - && proxyAuth.size() > 0 - && !future.getAndSetAuth(true)) { + if (statusCode == 407 && realm != null && proxyAuth.size() > 0 && !future.getAndSetAuth(true)) { log.debug("Sending proxy authentication to {}", request.getUrl()); @@ -2274,7 +2154,8 @@ public Object call() throws Exception { // SPNEGO KERBEROS } else if (proxyAuth.contains("Negotiate")) { newRealm = kerberosChallenge(proxyAuth, request, proxyServer, headers, realm, future); - if (newRealm == null) return; + if (newRealm == null) + return; } else { newRealm = future.getRequest().getRealm(); } @@ -2286,8 +2167,7 @@ public Object call() throws Exception { return; } - if (future.getNettyRequest().getMethod().equals(HttpMethod.CONNECT) - && statusCode == 200) { + if (future.getNettyRequest().getMethod().equals(HttpMethod.CONNECT) && statusCode == 200) { log.debug("Connected to {}:{}", proxyServer.getHost(), proxyServer.getPort()); @@ -2308,7 +2188,8 @@ public Object call() throws Exception { return; } - if (redirect(request, future, response, ctx)) return; + if (redirect(request, future, response, ctx)) + return; if (!future.getAndSetStatusReceived(true) && updateStatusAndInterrupt(handler, status)) { finishUpdate(future, ctx, response.isChunked()); @@ -2334,11 +2215,9 @@ public Object call() throws Exception { HttpChunk chunk = (HttpChunk) e.getMessage(); if (handler != null) { - if (chunk.isLast() || updateBodyAndInterrupt(future, handler, - new ResponseBodyPart(future.getURI(), null, NettyAsyncHttpProvider.this, chunk, chunk.isLast()))) { + if (chunk.isLast() || updateBodyAndInterrupt(future, handler, new ResponseBodyPart(future.getURI(), null, NettyAsyncHttpProvider.this, chunk, chunk.isLast()))) { if (chunk instanceof DefaultHttpChunkTrailer) { - updateHeadersAndInterrupt(handler, new ResponseHeaders(future.getURI(), - future.getHttpResponse(), NettyAsyncHttpProvider.this, (HttpChunkTrailer) chunk)); + updateHeadersAndInterrupt(handler, new ResponseHeaders(future.getURI(), future.getHttpResponse(), NettyAsyncHttpProvider.this, (HttpChunkTrailer) chunk)); } finishUpdate(future, ctx, !chunk.isLast()); } @@ -2346,8 +2225,7 @@ public Object call() throws Exception { } } catch (Exception t) { if (IOException.class.isAssignableFrom(t.getClass()) && config.getIOExceptionFilters().size() > 0) { - FilterContext fc = new FilterContext.FilterContextBuilder().asyncHandler(future.getAsyncHandler()) - .request(future.getRequest()).ioException(IOException.class.cast(t)).build(); + FilterContext fc = new FilterContext.FilterContextBuilder().asyncHandler(future.getAsyncHandler()).request(future.getRequest()).ioException(IOException.class.cast(t)).build(); fc = handleIoException(fc, future); if (fc.replayRequest()) { @@ -2380,10 +2258,10 @@ private final class WebSocketProtocol implements Protocol { private static final byte OPCODE_BINARY = 0x2; private static final byte OPCODE_UNKNOWN = -1; - protected ChannelBuffer byteBuffer = null; - protected StringBuilder textBuffer = null; - protected byte pendingOpcode = OPCODE_UNKNOWN; - + protected ChannelBuffer byteBuffer = null; + protected StringBuilder textBuffer = null; + protected byte pendingOpcode = OPCODE_UNKNOWN; + // @Override public void handle(ChannelHandlerContext ctx, MessageEvent e) throws Exception { NettyResponseFuture future = NettyResponseFuture.class.cast(ctx.getAttachment()); @@ -2395,12 +2273,7 @@ public void handle(ChannelHandlerContext ctx, MessageEvent e) throws Exception { HttpResponseStatus s = new ResponseStatus(future.getURI(), response, NettyAsyncHttpProvider.this); HttpResponseHeaders responseHeaders = new ResponseHeaders(future.getURI(), response, NettyAsyncHttpProvider.this); - FilterContext fc = new FilterContext.FilterContextBuilder() - .asyncHandler(h) - .request(request) - .responseStatus(s) - .responseHeaders(responseHeaders) - .build(); + FilterContext fc = new FilterContext.FilterContextBuilder().asyncHandler(h).request(request).responseStatus(s).responseHeaders(responseHeaders).build(); for (ResponseFilter asyncFilter : config.getResponseFilters()) { try { fc = asyncFilter.filter(fc); @@ -2423,10 +2296,10 @@ public void handle(ChannelHandlerContext ctx, MessageEvent e) throws Exception { } future.setHttpResponse(response); - if (redirect(request, future, response, ctx)) return; + if (redirect(request, future, response, ctx)) + return; - final org.jboss.netty.handler.codec.http.HttpResponseStatus status = - new org.jboss.netty.handler.codec.http.HttpResponseStatus(101, "Web Socket Protocol Handshake"); + final org.jboss.netty.handler.codec.http.HttpResponseStatus status = new org.jboss.netty.handler.codec.http.HttpResponseStatus(101, "Web Socket Protocol Handshake"); final boolean validStatus = response.getStatus().equals(status); final boolean validUpgrade = response.getHeader(HttpHeaders.Names.UPGRADE) != null; @@ -2460,13 +2333,12 @@ public void handle(ChannelHandlerContext ctx, MessageEvent e) throws Exception { } else if (e.getMessage() instanceof WebSocketFrame) { final WebSocketFrame frame = (WebSocketFrame) e.getMessage(); - if(frame instanceof TextWebSocketFrame) { + if (frame instanceof TextWebSocketFrame) { pendingOpcode = OPCODE_TEXT; - } - else if(frame instanceof BinaryWebSocketFrame) { + } else if (frame instanceof BinaryWebSocketFrame) { pendingOpcode = OPCODE_BINARY; } - + HttpChunk webSocketChunk = new HttpChunk() { private ChannelBuffer content; @@ -2494,11 +2366,10 @@ public void setContent(ChannelBuffer content) { NettyWebSocket webSocket = NettyWebSocket.class.cast(h.onCompleted()); if (webSocket != null) { - if(pendingOpcode == OPCODE_BINARY) { - webSocket.onBinaryFragment(rp.getBodyPartBytes(),frame.isFinalFragment()); - } - else { - webSocket.onTextFragment(frame.getBinaryData().toString(UTF8),frame.isFinalFragment()); + if (pendingOpcode == OPCODE_BINARY) { + webSocket.onBinaryFragment(rp.getBodyPartBytes(), frame.isFinalFragment()); + } else { + webSocket.onTextFragment(frame.getBinaryData().toString(UTF8), frame.isFinalFragment()); } if (CloseWebSocketFrame.class.isAssignableFrom(frame.getClass())) { @@ -2518,7 +2389,7 @@ public void setContent(ChannelBuffer content) { } } - //@Override + // @Override public void onError(ChannelHandlerContext ctx, ExceptionEvent e) { try { log.warn("onError {}", e); @@ -2539,7 +2410,7 @@ public void onError(ChannelHandlerContext ctx, ExceptionEvent e) { } } - //@Override + // @Override public void onClose(ChannelHandlerContext ctx, ChannelStateEvent e) { log.trace("onClose {}", e); if (ctx.getAttachment() == null || !NettyResponseFuture.class.isAssignableFrom(ctx.getAttachment().getClass())) { diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyResponseFuture.java b/src/main/java/com/ning/http/client/providers/netty/NettyResponseFuture.java index dae8095c46..fff32feca8 100755 --- a/src/main/java/com/ning/http/client/providers/netty/NettyResponseFuture.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyResponseFuture.java @@ -17,17 +17,6 @@ import static com.ning.http.util.DateUtil.millisTime; -import com.ning.http.client.AsyncHandler; -import com.ning.http.client.ConnectionPoolKeyStrategy; -import com.ning.http.client.ProxyServer; -import com.ning.http.client.Request; -import com.ning.http.client.listenable.AbstractListenableFuture; -import org.jboss.netty.channel.Channel; -import org.jboss.netty.handler.codec.http.HttpRequest; -import org.jboss.netty.handler.codec.http.HttpResponse; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import java.net.MalformedURLException; import java.net.URI; import java.util.concurrent.Callable; @@ -42,9 +31,21 @@ import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; +import org.jboss.netty.channel.Channel; +import org.jboss.netty.handler.codec.http.HttpRequest; +import org.jboss.netty.handler.codec.http.HttpResponse; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.ning.http.client.AsyncHandler; +import com.ning.http.client.ConnectionPoolKeyStrategy; +import com.ning.http.client.ProxyServer; +import com.ning.http.client.Request; +import com.ning.http.client.listenable.AbstractListenableFuture; + /** * A {@link Future} that can be used to track when an asynchronous HTTP request has been fully processed. - * + * * @param */ public final class NettyResponseFuture extends AbstractListenableFuture { @@ -53,17 +54,14 @@ public final class NettyResponseFuture extends AbstractListenableFuture { public final static String MAX_RETRY = "com.ning.http.client.providers.netty.maxRetry"; enum STATE { - NEW, - POOLED, - RECONNECTED, - CLOSED, + NEW, POOLED, RECONNECTED, CLOSED, } private final CountDownLatch latch = new CountDownLatch(1); private final AtomicBoolean isDone = new AtomicBoolean(false); private final AtomicBoolean isCancelled = new AtomicBoolean(false); private AsyncHandler asyncHandler; - private final int responseTimeoutInMs; + private final int requestTimeoutInMs; private final int idleConnectionTimeoutInMs; private Request request; private HttpRequest nettyRequest; @@ -92,18 +90,18 @@ enum STATE { private final ConnectionPoolKeyStrategy connectionPoolKeyStrategy; private final ProxyServer proxyServer; - public NettyResponseFuture(URI uri, - Request request, - AsyncHandler asyncHandler, - HttpRequest nettyRequest, - int responseTimeoutInMs, - int idleConnectionTimeoutInMs, - NettyAsyncHttpProvider asyncHttpProvider, - ConnectionPoolKeyStrategy connectionPoolKeyStrategy, - ProxyServer proxyServer) { + public NettyResponseFuture(URI uri,// + Request request,// + AsyncHandler asyncHandler,// + HttpRequest nettyRequest,// + int requestTimeoutInMs,// + int idleConnectionTimeoutInMs,// + NettyAsyncHttpProvider asyncHttpProvider,// + ConnectionPoolKeyStrategy connectionPoolKeyStrategy,// + ProxyServer proxyServer) { this.asyncHandler = asyncHandler; - this.responseTimeoutInMs = responseTimeoutInMs; + this.requestTimeoutInMs = requestTimeoutInMs; this.idleConnectionTimeoutInMs = idleConnectionTimeoutInMs; this.request = request; this.nettyRequest = nettyRequest; @@ -164,7 +162,8 @@ void setAsyncHandler(AsyncHandler asyncHandler) { public boolean cancel(boolean force) { cancelReaper(); - if (isCancelled.get()) return false; + if (isCancelled.get()) + return false; try { channel.getPipeline().getContext(NettyAsyncHttpProvider.class).setAttachment(new NettyAsyncHttpProvider.DiscardEvent()); @@ -187,13 +186,20 @@ public boolean cancel(boolean force) { /** * Is the Future still valid - * + * * @return true if response has expired and should be terminated. */ public boolean hasExpired() { long now = millisTime(); - return idleConnectionTimeoutInMs != -1 && ((now - touch.get()) >= idleConnectionTimeoutInMs) - || responseTimeoutInMs != -1 && ((now - start) >= responseTimeoutInMs); + return hasConnectionIdleTimedOut(now) || hasRequestTimedOut(now); + } + + public boolean hasConnectionIdleTimedOut(long now) { + return idleConnectionTimeoutInMs != -1 && (now - touch.get()) >= idleConnectionTimeoutInMs; + } + + public boolean hasRequestTimedOut(long now) { + return requestTimeoutInMs != -1 && (now - start) >= requestTimeoutInMs; } /** @@ -202,7 +208,7 @@ public boolean hasExpired() { /* @Override */ public V get() throws InterruptedException, ExecutionException { try { - return get(responseTimeoutInMs, TimeUnit.MILLISECONDS); + return get(requestTimeoutInMs, TimeUnit.MILLISECONDS); } catch (TimeoutException e) { cancelReaper(); throw new ExecutionException(e); @@ -324,7 +330,8 @@ public final void done(Callable callable) { public final void abort(final Throwable t) { cancelReaper(); - if (isDone.get() || isCancelled.get()) return; + if (isDone.get() || isCancelled.get()) + return; exEx.compareAndSet(null, new ExecutionException(t)); if (!throwableCalled.getAndSet(true)) { @@ -478,38 +485,45 @@ public void setRequest(Request request) { } /** - * Return true if the {@link Future} cannot be recovered. There is some scenario where a connection can be - * closed by an unexpected IOException, and in some situation we can recover from that exception. - * + * Return true if the {@link Future} cannot be recovered. There is some scenario where a connection can be closed by an unexpected IOException, and in some situation we can recover from that exception. + * * @return true if that {@link Future} cannot be recovered. */ public boolean cannotBeReplay() { - return isDone() - || !canRetry() - || isCancelled() - || (channel() != null && channel().isOpen() && uri.getScheme().compareToIgnoreCase("https") != 0) - || isInAuth(); + return isDone() || !canRetry() || isCancelled() || (channel() != null && channel().isOpen() && uri.getScheme().compareToIgnoreCase("https") != 0) || isInAuth(); + } + + public long getStart() { + return start; + } + + public long getRequestTimeoutInMs() { + return requestTimeoutInMs; + } + + public long getIdleConnectionTimeoutInMs() { + return idleConnectionTimeoutInMs; } @Override public String toString() { - return "NettyResponseFuture{" + - "currentRetry=" + currentRetry + - ",\n\tisDone=" + isDone + - ",\n\tisCancelled=" + isCancelled + - ",\n\tasyncHandler=" + asyncHandler + - ",\n\tresponseTimeoutInMs=" + responseTimeoutInMs + - ",\n\tnettyRequest=" + nettyRequest + - ",\n\tcontent=" + content + - ",\n\turi=" + uri + - ",\n\tkeepAlive=" + keepAlive + - ",\n\thttpResponse=" + httpResponse + - ",\n\texEx=" + exEx + - ",\n\tredirectCount=" + redirectCount + - ",\n\treaperFuture=" + reaperFuture + - ",\n\tinAuth=" + inAuth + - ",\n\tstatusReceived=" + statusReceived + - ",\n\ttouch=" + touch + + return "NettyResponseFuture{" + // + "currentRetry=" + currentRetry + // + ",\n\tisDone=" + isDone + // + ",\n\tisCancelled=" + isCancelled + // + ",\n\tasyncHandler=" + asyncHandler + // + ",\n\trequestTimeoutInMs=" + requestTimeoutInMs + // + ",\n\tnettyRequest=" + nettyRequest + // + ",\n\tcontent=" + content + // + ",\n\turi=" + uri + // + ",\n\tkeepAlive=" + keepAlive + // + ",\n\thttpResponse=" + httpResponse + // + ",\n\texEx=" + exEx + // + ",\n\tredirectCount=" + redirectCount + // + ",\n\treaperFuture=" + reaperFuture + // + ",\n\tinAuth=" + inAuth + // + ",\n\tstatusReceived=" + statusReceived + // + ",\n\ttouch=" + touch + // '}'; } From edc685c830e6ae95bb1dab375f888f1c2a141188 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 22 May 2013 05:17:03 +0200 Subject: [PATCH 137/264] Make idleConnectionTimeout effective when less than requestTimeout, backport #120 --- .../client/providers/netty/NettyAsyncHttpProvider.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java index ad66cd64eb..cc1af94a3c 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java @@ -563,10 +563,11 @@ public void operationComplete(ChannelFuture cf) { try { future.touch(); - int delay = Math.min(config.getIdleConnectionTimeoutInMs(), requestTimeoutInMs(config, future.getRequest().getPerRequestConfig())); - if (delay != -1 && !future.isDone() && !future.isCancelled()) { + int requestTimeout = requestTimeoutInMs(config, future.getRequest().getPerRequestConfig()); + int schedulePeriod = requestTimeout != -1 ? (config.getIdleConnectionTimeoutInMs() != -1 ? Math.min(requestTimeout, config.getIdleConnectionTimeoutInMs()) : requestTimeout) : config.getIdleConnectionTimeoutInMs(); + if (schedulePeriod != -1 && !future.isDone() && !future.isCancelled()) { ReaperFuture reaperFuture = new ReaperFuture(future); - Future scheduledFuture = config.reaper().scheduleAtFixedRate(reaperFuture, 0, delay, TimeUnit.MILLISECONDS); + Future scheduledFuture = config.reaper().scheduleAtFixedRate(reaperFuture, 0, schedulePeriod, TimeUnit.MILLISECONDS); reaperFuture.setScheduledFuture(scheduledFuture); future.setReaperFuture(reaperFuture); } From 0b25cc5271ad6685fdcd8dc6ad3625f03240bc3d Mon Sep 17 00:00:00 2001 From: jfarcand Date: Fri, 24 May 2013 10:26:07 -0400 Subject: [PATCH 138/264] Fixes #302 --- .../http/client/providers/netty/NettyAsyncHttpProvider.java | 2 +- .../ning/http/client/providers/netty/NettyWebSocket.java | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java index cc1af94a3c..e9020c32e4 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java @@ -2423,7 +2423,7 @@ public void onClose(ChannelHandlerContext ctx, ChannelStateEvent e) { WebSocketUpgradeHandler h = WebSocketUpgradeHandler.class.cast(nettyResponse.getAsyncHandler()); NettyWebSocket webSocket = NettyWebSocket.class.cast(h.onCompleted()); - webSocket.close(); + webSocket.close(1006, "Connection was closed abnormally (that is, with no close frame being sent)."); } catch (Throwable t) { log.error("onError", t); } diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyWebSocket.java b/src/main/java/com/ning/http/client/providers/netty/NettyWebSocket.java index b572dcf0f4..bd8704f8e3 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyWebSocket.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyWebSocket.java @@ -122,6 +122,12 @@ public void close() { } } + // @Override + public void close(int statusCode, String reason) { + onClose(statusCode, reason); + listeners.clear(); + } + protected void onBinaryFragment(byte[] message, boolean last) { for (WebSocketListener l : listeners) { if (WebSocketByteListener.class.isAssignableFrom(l.getClass())) { From 92d2d4ba45f8522d535e9bca13772bbab7019c79 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 28 May 2013 21:30:12 +0200 Subject: [PATCH 139/264] Fix timeout tests, close #304 --- .../client/providers/netty/NettyAsyncHttpProvider.java | 4 ++-- .../ning/http/client/async/PerRequestTimeoutTest.java | 10 ++++------ .../async/grizzly/GrizzlyPerRequestTimeoutTest.java | 6 ++++-- .../client/async/netty/NettyPerRequestTimeoutTest.java | 7 +++++++ 4 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java index e9020c32e4..5b482c74d6 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java @@ -1796,11 +1796,11 @@ public synchronized void run() { long now = millisTime(); if (nettyResponseFuture.hasRequestTimedOut(now)) { - long age = (now - nettyResponseFuture.getStart()) / 1000000; + long age = now - nettyResponseFuture.getStart(); expire("Request reached time out of " + nettyResponseFuture.getRequestTimeoutInMs() + " ms after " + age + " ms"); } else if (nettyResponseFuture.hasConnectionIdleTimedOut(now)) { - long age = (now - nettyResponseFuture.getStart()) / 1000000; + long age = now - nettyResponseFuture.getStart(); expire("Request reached idle time out of " + nettyResponseFuture.getIdleConnectionTimeoutInMs() + " ms after " + age + " ms"); } diff --git a/src/test/java/com/ning/http/client/async/PerRequestTimeoutTest.java b/src/test/java/com/ning/http/client/async/PerRequestTimeoutTest.java index 22655effcb..599775a71b 100644 --- a/src/test/java/com/ning/http/client/async/PerRequestTimeoutTest.java +++ b/src/test/java/com/ning/http/client/async/PerRequestTimeoutTest.java @@ -52,9 +52,7 @@ public abstract class PerRequestTimeoutTest extends AbstractBasicTest { private static final String MSG = "Enough is enough."; - protected String getExpectedTimeoutMessage() { - return "No response received after 100"; - } + protected abstract void checkTimeoutMessage(String message); @Override public AbstractHandler configureHandler() throws Exception { @@ -111,7 +109,7 @@ public void testRequestTimeout() throws IOException { fail("Interrupted.", e); } catch (ExecutionException e) { assertTrue(e.getCause() instanceof TimeoutException); - assertEquals(e.getCause().getMessage(), getExpectedTimeoutMessage()); + checkTimeoutMessage(e.getCause().getMessage()); } catch (TimeoutException e) { fail("Timeout.", e); } finally { @@ -133,7 +131,7 @@ public void testGlobalDefaultPerRequestInfiniteTimeout() throws IOException { fail("Interrupted.", e); } catch (ExecutionException e) { assertTrue(e.getCause() instanceof TimeoutException); - assertEquals(e.getCause().getMessage(), getExpectedTimeoutMessage()); + checkTimeoutMessage(e.getCause().getMessage()); } finally { client.close(); } @@ -151,7 +149,7 @@ public void testGlobalRequestTimeout() throws IOException { fail("Interrupted.", e); } catch (ExecutionException e) { assertTrue(e.getCause() instanceof TimeoutException); - assertEquals(e.getCause().getMessage(), getExpectedTimeoutMessage()); + checkTimeoutMessage(e.getCause().getMessage()); } catch (TimeoutException e) { fail("Timeout.", e); } finally { diff --git a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyPerRequestTimeoutTest.java b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyPerRequestTimeoutTest.java index e13d10ac42..6c1ce2d3b4 100644 --- a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyPerRequestTimeoutTest.java +++ b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyPerRequestTimeoutTest.java @@ -13,6 +13,8 @@ package com.ning.http.client.async.grizzly; +import static org.testng.Assert.assertEquals; + import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.async.PerRequestTimeoutTest; @@ -21,8 +23,8 @@ public class GrizzlyPerRequestTimeoutTest extends PerRequestTimeoutTest { @Override - protected String getExpectedTimeoutMessage() { - return "Timeout exceeded"; + protected void checkTimeoutMessage(String message) { + assertEquals("Timeout exceeded", message); } @Override diff --git a/src/test/java/com/ning/http/client/async/netty/NettyPerRequestTimeoutTest.java b/src/test/java/com/ning/http/client/async/netty/NettyPerRequestTimeoutTest.java index 6b74df734b..aa42d7f46f 100644 --- a/src/test/java/com/ning/http/client/async/netty/NettyPerRequestTimeoutTest.java +++ b/src/test/java/com/ning/http/client/async/netty/NettyPerRequestTimeoutTest.java @@ -12,12 +12,19 @@ */ package com.ning.http.client.async.netty; +import static org.testng.Assert.assertTrue; + import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.async.PerRequestTimeoutTest; import com.ning.http.client.async.ProviderUtil; public class NettyPerRequestTimeoutTest extends PerRequestTimeoutTest { + + protected void checkTimeoutMessage(String message) { + assertTrue(message.startsWith("Request reached time out of 100 ms after ")); + } + @Override public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { return ProviderUtil.nettyProvider(config); From be0fed7c52afdde8d4bf499e647af60e2f1a99e8 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 28 May 2013 21:32:50 +0200 Subject: [PATCH 140/264] Use StringBuilders instead of StringBuffers, close #305 --- .../client/resumable/PropertiesBasedResumableProcessor.java | 2 +- .../java/com/ning/http/multipart/MultipartRequestEntity.java | 2 +- src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java | 2 +- src/test/java/com/ning/http/client/async/BasicAuthTest.java | 2 +- .../com/ning/http/client/async/SimpleAsyncHttpClientTest.java | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/ning/http/client/resumable/PropertiesBasedResumableProcessor.java b/src/main/java/com/ning/http/client/resumable/PropertiesBasedResumableProcessor.java index efb6dea06b..a893088879 100644 --- a/src/main/java/com/ning/http/client/resumable/PropertiesBasedResumableProcessor.java +++ b/src/main/java/com/ning/http/client/resumable/PropertiesBasedResumableProcessor.java @@ -90,7 +90,7 @@ public void save(Map map) { } private static String append(Map.Entry e) { - return new StringBuffer(e.getKey()).append("=").append(e.getValue()).append("\n").toString(); + return new StringBuilder(e.getKey()).append("=").append(e.getValue()).append("\n").toString(); } /** diff --git a/src/main/java/com/ning/http/multipart/MultipartRequestEntity.java b/src/main/java/com/ning/http/multipart/MultipartRequestEntity.java index e9fd24c88e..cad76f9a5a 100644 --- a/src/main/java/com/ning/http/multipart/MultipartRequestEntity.java +++ b/src/main/java/com/ning/http/multipart/MultipartRequestEntity.java @@ -143,7 +143,7 @@ public String getContentType() { if (contentType.contains("boundary=")) return contentType; else { - StringBuffer buffer = new StringBuffer(contentType); + StringBuilder buffer = new StringBuilder(contentType); if (!contentType.endsWith(";")) buffer.append(";"); buffer.append(" boundary="); diff --git a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java index ef42196e27..81421fd108 100644 --- a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java +++ b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java @@ -456,7 +456,7 @@ private static void add(StringBuilder sb, String name, int val) { } public static String constructUserAgent(Class httpProvider) { - StringBuffer b = new StringBuffer("AsyncHttpClient/1.0") + StringBuilder b = new StringBuilder("AsyncHttpClient/1.0") .append(" ") .append("(") .append(httpProvider.getSimpleName()) diff --git a/src/test/java/com/ning/http/client/async/BasicAuthTest.java b/src/test/java/com/ning/http/client/async/BasicAuthTest.java index 4c7aec83ea..0886b887c3 100644 --- a/src/test/java/com/ning/http/client/async/BasicAuthTest.java +++ b/src/test/java/com/ning/http/client/async/BasicAuthTest.java @@ -474,7 +474,7 @@ public AbstractHandler configureHandler() throws Exception { } @Test(groups = { "standalone", "default_provider" }) - public void StringBufferBodyConsumerTest() throws Throwable { + public void StringBuilderBodyConsumerTest() throws Throwable { SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setRealmPrincipal(user).setRealmPassword(admin).setUrl(getTargetUrl()).setHeader("Content-Type", "text/html").build(); try { StringBuilder s = new StringBuilder(); diff --git a/src/test/java/com/ning/http/client/async/SimpleAsyncHttpClientTest.java b/src/test/java/com/ning/http/client/async/SimpleAsyncHttpClientTest.java index 8039591c3b..27d1248c8a 100644 --- a/src/test/java/com/ning/http/client/async/SimpleAsyncHttpClientTest.java +++ b/src/test/java/com/ning/http/client/async/SimpleAsyncHttpClientTest.java @@ -56,7 +56,7 @@ public void inpuStreamBodyConsumerTest() throws Throwable { } @Test(groups = { "standalone", "default_provider" }) - public void StringBufferBodyConsumerTest() throws Throwable { + public void StringBuilderBodyConsumerTest() throws Throwable { SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setIdleConnectionInPoolTimeoutInMs(100).setMaximumConnectionsTotal(50).setRequestTimeoutInMs(5 * 60 * 1000).setUrl(getTargetUrl()).setHeader("Content-Type", "text/html").build(); try { From 01cb2752c33fedebcf8a2ffbaf5eee51c652274a Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 28 May 2013 21:41:16 +0200 Subject: [PATCH 141/264] Upgrade Netty 3.6.6.Final, close #306 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 9081e6cd72..95a37ca430 100644 --- a/pom.xml +++ b/pom.xml @@ -81,7 +81,7 @@ io.netty netty - 3.6.3.Final + 3.6.6.Final From 5f42b960a406ca85169345dd3f5b0ba07c8ba2a4 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 28 May 2013 21:57:08 +0200 Subject: [PATCH 142/264] Upgrade Slf4j 1.7.5, close #307 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 95a37ca430..76609a94ed 100644 --- a/pom.xml +++ b/pom.xml @@ -87,7 +87,7 @@ org.slf4j slf4j-api - 1.6.2 + 1.7.5 @@ -101,7 +101,7 @@ ch.qos.logback logback-classic - 0.9.26 + 1.0.13 test From 93b6f3cd0baf4f910319366e05b69f7db657552e Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 29 May 2013 12:37:54 +0200 Subject: [PATCH 143/264] Backport 13b9bd45e44b8dfd9e257add65eb40374622970c --- .../client/resumable/PropertiesBasedResumableProcessor.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/ning/http/client/resumable/PropertiesBasedResumableProcessor.java b/src/main/java/com/ning/http/client/resumable/PropertiesBasedResumableProcessor.java index a893088879..d6ed2fc43b 100644 --- a/src/main/java/com/ning/http/client/resumable/PropertiesBasedResumableProcessor.java +++ b/src/main/java/com/ning/http/client/resumable/PropertiesBasedResumableProcessor.java @@ -60,11 +60,11 @@ public void save(Map map) { FileOutputStream os = null; try { - if (!TMP.mkdirs()) { + if (!TMP.exists() && !TMP.mkdirs()) { throw new IllegalStateException("Unable to create directory: " + TMP.getAbsolutePath()); } File f = new File(TMP, storeName); - if (!f.createNewFile()) { + if (!f.exists() && !f.createNewFile()) { throw new IllegalStateException("Unable to create temp file: " + f.getAbsolutePath()); } if (!f.canWrite()) { From e4c2e0e058285188eaaaaf7d412bf4bdcc460dbd Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 30 May 2013 10:28:00 +0200 Subject: [PATCH 144/264] Remove additional CRLF when there's no Content-Disposition, close #309 --- src/main/java/com/ning/http/multipart/Part.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/ning/http/multipart/Part.java b/src/main/java/com/ning/http/multipart/Part.java index 94dece3008..7fcfdf603c 100644 --- a/src/main/java/com/ning/http/multipart/Part.java +++ b/src/main/java/com/ning/http/multipart/Part.java @@ -210,7 +210,6 @@ public boolean isRepeatable() { protected void sendStart(OutputStream out) throws IOException { out.write(EXTRA_BYTES); out.write(getPartBoundary()); - out.write(CRLF_BYTES); } /** @@ -220,10 +219,13 @@ protected void sendStart(OutputStream out) throws IOException { * @throws IOException If an IO problem occurs. */ protected void sendDispositionHeader(OutputStream out) throws IOException { - out.write(CONTENT_DISPOSITION_BYTES); - out.write(QUOTE_BYTES); - out.write(MultipartEncodingUtil.getAsciiBytes(getName())); - out.write(QUOTE_BYTES); + if (getName() != null) { + out.write(CRLF_BYTES); + out.write(CONTENT_DISPOSITION_BYTES); + out.write(QUOTE_BYTES); + out.write(MultipartEncodingUtil.getAsciiBytes(getName())); + out.write(QUOTE_BYTES); + } } /** From e7656e431e294950ed97c4d3f6d0aad1bb670763 Mon Sep 17 00:00:00 2001 From: jfarcand Date: Thu, 30 May 2013 09:43:21 -0400 Subject: [PATCH 145/264] Make sure onClose is called once --- .../netty/NettyAsyncHttpProvider.java | 158 +++++++++--------- 1 file changed, 79 insertions(+), 79 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java index 5b482c74d6..6b90a10a37 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java @@ -15,42 +15,48 @@ */ package com.ning.http.client.providers.netty; -import static com.ning.http.util.AsyncHttpProviderUtils.DEFAULT_CHARSET; -import static com.ning.http.util.DateUtil.millisTime; -import static com.ning.http.util.MiscUtil.isNonEmpty; -import static org.jboss.netty.channel.Channels.pipeline; - -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.RandomAccessFile; -import java.net.ConnectException; -import java.net.InetSocketAddress; -import java.net.MalformedURLException; -import java.net.URI; -import java.nio.channels.ClosedChannelException; -import java.nio.channels.FileChannel; -import java.nio.channels.WritableByteChannel; -import java.nio.charset.Charset; -import java.security.GeneralSecurityException; -import java.security.NoSuchAlgorithmException; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.Map.Entry; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.RejectedExecutionException; -import java.util.concurrent.Semaphore; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import java.util.concurrent.atomic.AtomicBoolean; - -import javax.net.ssl.SSLEngine; - +import com.ning.http.client.AsyncHandler; +import com.ning.http.client.AsyncHandler.STATE; +import com.ning.http.client.AsyncHttpClientConfig; +import com.ning.http.client.AsyncHttpProvider; +import com.ning.http.client.Body; +import com.ning.http.client.BodyGenerator; +import com.ning.http.client.ConnectionPoolKeyStrategy; +import com.ning.http.client.ConnectionsPool; +import com.ning.http.client.Cookie; +import com.ning.http.client.FluentCaseInsensitiveStringsMap; +import com.ning.http.client.HttpResponseBodyPart; +import com.ning.http.client.HttpResponseHeaders; +import com.ning.http.client.HttpResponseStatus; +import com.ning.http.client.ListenableFuture; +import com.ning.http.client.MaxRedirectException; +import com.ning.http.client.PerRequestConfig; +import com.ning.http.client.ProgressAsyncHandler; +import com.ning.http.client.ProxyServer; +import com.ning.http.client.RandomAccessBody; +import com.ning.http.client.Realm; +import com.ning.http.client.Request; +import com.ning.http.client.RequestBuilder; +import com.ning.http.client.Response; +import com.ning.http.client.filter.FilterContext; +import com.ning.http.client.filter.FilterException; +import com.ning.http.client.filter.IOExceptionFilter; +import com.ning.http.client.filter.ResponseFilter; +import com.ning.http.client.generators.InputStreamBodyGenerator; +import com.ning.http.client.listener.TransferCompletionHandler; +import com.ning.http.client.ntlm.NTLMEngine; +import com.ning.http.client.ntlm.NTLMEngineException; +import com.ning.http.client.providers.netty.spnego.SpnegoEngine; +import com.ning.http.client.websocket.WebSocketUpgradeHandler; +import com.ning.http.multipart.MultipartBody; +import com.ning.http.multipart.MultipartRequestEntity; +import com.ning.http.util.AsyncHttpProviderUtils; +import com.ning.http.util.AuthenticatorUtils; +import com.ning.http.util.CleanupChannelGroup; +import com.ning.http.util.ProxyUtils; +import com.ning.http.util.SslUtils; +import com.ning.http.util.UTF8UrlEncoder; +import com.ning.org.jboss.netty.handler.codec.http.CookieDecoder; import org.jboss.netty.bootstrap.ClientBootstrap; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBufferOutputStream; @@ -99,48 +105,40 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.ning.http.client.AsyncHandler; -import com.ning.http.client.AsyncHandler.STATE; -import com.ning.http.client.AsyncHttpClientConfig; -import com.ning.http.client.AsyncHttpProvider; -import com.ning.http.client.Body; -import com.ning.http.client.BodyGenerator; -import com.ning.http.client.ConnectionPoolKeyStrategy; -import com.ning.http.client.ConnectionsPool; -import com.ning.http.client.Cookie; -import com.ning.http.client.FluentCaseInsensitiveStringsMap; -import com.ning.http.client.HttpResponseBodyPart; -import com.ning.http.client.HttpResponseHeaders; -import com.ning.http.client.HttpResponseStatus; -import com.ning.http.client.ListenableFuture; -import com.ning.http.client.MaxRedirectException; -import com.ning.http.client.PerRequestConfig; -import com.ning.http.client.ProgressAsyncHandler; -import com.ning.http.client.ProxyServer; -import com.ning.http.client.RandomAccessBody; -import com.ning.http.client.Realm; -import com.ning.http.client.Request; -import com.ning.http.client.RequestBuilder; -import com.ning.http.client.Response; -import com.ning.http.client.filter.FilterContext; -import com.ning.http.client.filter.FilterException; -import com.ning.http.client.filter.IOExceptionFilter; -import com.ning.http.client.filter.ResponseFilter; -import com.ning.http.client.generators.InputStreamBodyGenerator; -import com.ning.http.client.listener.TransferCompletionHandler; -import com.ning.http.client.ntlm.NTLMEngine; -import com.ning.http.client.ntlm.NTLMEngineException; -import com.ning.http.client.providers.netty.spnego.SpnegoEngine; -import com.ning.http.client.websocket.WebSocketUpgradeHandler; -import com.ning.http.multipart.MultipartBody; -import com.ning.http.multipart.MultipartRequestEntity; -import com.ning.http.util.AsyncHttpProviderUtils; -import com.ning.http.util.AuthenticatorUtils; -import com.ning.http.util.CleanupChannelGroup; -import com.ning.http.util.ProxyUtils; -import com.ning.http.util.SslUtils; -import com.ning.http.util.UTF8UrlEncoder; -import com.ning.org.jboss.netty.handler.codec.http.CookieDecoder; +import javax.net.ssl.SSLEngine; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.net.ConnectException; +import java.net.InetSocketAddress; +import java.net.MalformedURLException; +import java.net.URI; +import java.nio.channels.ClosedChannelException; +import java.nio.channels.FileChannel; +import java.nio.channels.WritableByteChannel; +import java.nio.charset.Charset; +import java.security.GeneralSecurityException; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map.Entry; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicBoolean; + +import static com.ning.http.util.AsyncHttpProviderUtils.DEFAULT_CHARSET; +import static com.ning.http.util.DateUtil.millisTime; +import static com.ning.http.util.MiscUtil.isNonEmpty; +import static org.jboss.netty.channel.Channels.pipeline; public class NettyAsyncHttpProvider extends SimpleChannelUpstreamHandler implements AsyncHttpProvider { private final static String WEBSOCKET_KEY = "Sec-WebSocket-Key"; @@ -2375,6 +2373,7 @@ public void setContent(ChannelBuffer content) { if (CloseWebSocketFrame.class.isAssignableFrom(frame.getClass())) { try { + ctx.setAttachment(DiscardEvent.class); webSocket.onClose(CloseWebSocketFrame.class.cast(frame).getStatusCode(), CloseWebSocketFrame.class.cast(frame).getReasonText()); } catch (Throwable t) { // Swallow any exception that may comes from a Netty version released before 3.4.0 @@ -2423,7 +2422,8 @@ public void onClose(ChannelHandlerContext ctx, ChannelStateEvent e) { WebSocketUpgradeHandler h = WebSocketUpgradeHandler.class.cast(nettyResponse.getAsyncHandler()); NettyWebSocket webSocket = NettyWebSocket.class.cast(h.onCompleted()); - webSocket.close(1006, "Connection was closed abnormally (that is, with no close frame being sent)."); + if (ctx.getAttachment() == null || !DiscardEvent.class.isAssignableFrom(ctx.getAttachment().getClass())) + webSocket.close(1006, "Connection was closed abnormally (that is, with no close frame being sent)."); } catch (Throwable t) { log.error("onError", t); } From f7429c6075fa2aed755c8ef1bfa475d0aad87e68 Mon Sep 17 00:00:00 2001 From: jfarcand Date: Thu, 30 May 2013 17:03:17 -0400 Subject: [PATCH 146/264] [maven-release-plugin] prepare release async-http-client-1.7.17 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 76609a94ed..62e71da4f3 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.7.17-SNAPSHOT + 1.7.17 jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From ab14306ab64b59c201e8c5aae5c901b83a99c261 Mon Sep 17 00:00:00 2001 From: jfarcand Date: Thu, 30 May 2013 17:03:27 -0400 Subject: [PATCH 147/264] [maven-release-plugin] prepare for next development iteration --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 62e71da4f3..132577b540 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.7.17 + 1.7.18-SNAPSHOT jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From ac43f650c3fae9a0463a6fa745e2ca3f491c56ad Mon Sep 17 00:00:00 2001 From: Liuichi Kumai Date: Sat, 1 Jun 2013 00:44:50 +0900 Subject: [PATCH 148/264] Added an option for netty connection pool to limit the time when connection can be put back to pool. In case of Amazon Cloud DNS records can change in seconds, and taking into account that AHC caches already resolved connection and never re-resolve DNS records if response if ok, introducing option to limit life for cached connection, to be able to gracefully route traffic to new host in case dns records changed. Conflicts: src/main/java/com/ning/http/client/AsyncHttpClientConfig.java src/main/java/com/ning/http/client/providers/netty/NettyConnectionsPool.java --- .../http/client/AsyncHttpClientConfig.java | 26 +++++++++++++++++++ .../providers/netty/NettyConnectionsPool.java | 18 +++++++++++-- 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java b/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java index fde73329fb..c4c9341345 100644 --- a/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java @@ -85,6 +85,7 @@ public class AsyncHttpClientConfig { protected int ioThreadMultiplier; protected boolean strict302Handling; protected boolean useRelativeURIsWithSSLProxies; + protected int maxConnectionLifeTimeInMs; protected AsyncHttpClientConfig() { } @@ -96,6 +97,7 @@ private AsyncHttpClientConfig(int maxTotalConnections, int idleConnectionInPoolTimeoutInMs, int idleConnectionTimeoutInMs, int requestTimeoutInMs, + int connectionMaxLifeTimeInMs, boolean redirectEnabled, int maxDefaultRedirects, boolean compressionEnabled, @@ -128,6 +130,7 @@ private AsyncHttpClientConfig(int maxTotalConnections, this.idleConnectionInPoolTimeoutInMs = idleConnectionInPoolTimeoutInMs; this.idleConnectionTimeoutInMs = idleConnectionTimeoutInMs; this.requestTimeoutInMs = requestTimeoutInMs; + this.maxConnectionLifeTimeInMs = connectionMaxLifeTimeInMs; this.redirectEnabled = redirectEnabled; this.maxDefaultRedirects = maxDefaultRedirects; this.compressionEnabled = compressionEnabled; @@ -488,6 +491,15 @@ public boolean isUseRelativeURIsWithSSLProxies() { return useRelativeURIsWithSSLProxies; } + /** + * Return the maximum time in millisecond an {@link com.ning.http.client.AsyncHttpClient} will keep connection in the pool, or -1 to keep connection while possible. + * + * @return the maximum time in millisecond an {@link com.ning.http.client.AsyncHttpClient} will keep connection in the pool, or -1 to keep connection while possible. + */ + public int getMaxConnectionLifeTimeInMs() { + return maxConnectionLifeTimeInMs; + } + /** * Builder for an {@link AsyncHttpClient} */ @@ -499,6 +511,7 @@ public static class Builder { private int defaultIdleConnectionInPoolTimeoutInMs = Integer.getInteger(ASYNC_CLIENT + "defaultIdleConnectionInPoolTimeoutInMS", 60 * 1000); private int defaultIdleConnectionTimeoutInMs = Integer.getInteger(ASYNC_CLIENT + "defaultIdleConnectionTimeoutInMS", 60 * 1000); private int defaultRequestTimeoutInMs = Integer.getInteger(ASYNC_CLIENT + "defaultRequestTimeoutInMS", 60 * 1000); + private int defaultMaxConnectionLifeTimeInMs = Integer.getInteger(ASYNC_CLIENT + "defaultMaxConnectionLifeTimeInMs", -1); private boolean redirectEnabled = Boolean.getBoolean(ASYNC_CLIENT + "defaultRedirectsEnabled"); private int maxDefaultRedirects = Integer.getInteger(ASYNC_CLIENT + "defaultMaxRedirects", 5); private boolean compressionEnabled = Boolean.getBoolean(ASYNC_CLIENT + "compressionEnabled"); @@ -982,6 +995,17 @@ public Builder setUseRelativeURIsWithSSLProxies(boolean useRelativeURIsWithSSLPr return this; } + /** + * Set the maximum time in millisecond connection can be added to the pool for further reuse + * + * @param maxConnectionLifeTimeInMs the maximum time in millisecond connection can be added to the pool for further reuse + * @return a {@link Builder} + */ + public Builder setMaxConnectionLifeTimeInMs(int maxConnectionLifeTimeInMs) { + this.defaultMaxConnectionLifeTimeInMs = maxConnectionLifeTimeInMs; + return this; + } + /** * Create a config builder with values taken from the given prototype configuration. * @@ -995,6 +1019,7 @@ public Builder(AsyncHttpClientConfig prototype) { defaultIdleConnectionInPoolTimeoutInMs = prototype.getIdleConnectionInPoolTimeoutInMs(); defaultIdleConnectionTimeoutInMs = prototype.getIdleConnectionTimeoutInMs(); defaultMaxConnectionPerHost = prototype.getMaxConnectionPerHost(); + defaultMaxConnectionLifeTimeInMs = prototype.getMaxConnectionLifeTimeInMs(); maxDefaultRedirects = prototype.getMaxRedirects(); defaultMaxTotalConnections = prototype.getMaxTotalConnections(); proxyServer = prototype.getProxyServer(); @@ -1048,6 +1073,7 @@ public AsyncHttpClientConfig build() { defaultIdleConnectionInPoolTimeoutInMs, defaultIdleConnectionTimeoutInMs, defaultRequestTimeoutInMs, + defaultMaxConnectionLifeTimeInMs, redirectEnabled, maxDefaultRedirects, compressionEnabled, diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyConnectionsPool.java b/src/main/java/com/ning/http/client/providers/netty/NettyConnectionsPool.java index 2c232fb2a9..ed91845c14 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyConnectionsPool.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyConnectionsPool.java @@ -36,22 +36,25 @@ public class NettyConnectionsPool implements ConnectionsPool { private final static Logger log = LoggerFactory.getLogger(NettyConnectionsPool.class); private final ConcurrentHashMap> connectionsPool = new ConcurrentHashMap>(); private final ConcurrentHashMap channel2IdleChannel = new ConcurrentHashMap(); + private final ConcurrentHashMap channel2CreationDate = new ConcurrentHashMap(); private final AtomicBoolean isClosed = new AtomicBoolean(false); private final Timer idleConnectionDetector = new Timer(true); private final boolean sslConnectionPoolEnabled; private final int maxTotalConnections; private final int maxConnectionPerHost; + private final int maxConnectionLifeTimeInMs; private final long maxIdleTime; public NettyConnectionsPool(NettyAsyncHttpProvider provider) { - this(provider.getConfig().getMaxTotalConnections(), provider.getConfig().getMaxConnectionPerHost(), provider.getConfig().getIdleConnectionInPoolTimeoutInMs(), provider.getConfig().isSslConnectionPoolEnabled()); + this(provider.getConfig().getMaxTotalConnections(), provider.getConfig().getMaxConnectionPerHost(), provider.getConfig().getIdleConnectionInPoolTimeoutInMs(), provider.getConfig().getMaxConnectionLifeTimeInMs(), provider.getConfig().isSslConnectionPoolEnabled()); } - public NettyConnectionsPool(int maxTotalConnections, int maxConnectionPerHost, long maxIdleTime, boolean sslConnectionPoolEnabled) { + public NettyConnectionsPool(int maxTotalConnections, int maxConnectionPerHost, long maxIdleTime, int maxConnectionLifeTimeInMs, boolean sslConnectionPoolEnabled) { this.maxTotalConnections = maxTotalConnections; this.maxConnectionPerHost = maxConnectionPerHost; this.sslConnectionPoolEnabled = sslConnectionPoolEnabled; this.maxIdleTime = maxIdleTime; + this.maxConnectionLifeTimeInMs = maxConnectionLifeTimeInMs; this.idleConnectionDetector.schedule(new IdleChannelDetector(), maxIdleTime, maxIdleTime); } @@ -157,6 +160,14 @@ public boolean offer(String uri, Channel channel) { return false; } + Long createTime = channel2CreationDate.get(channel); + if (createTime == null) { + channel2CreationDate.putIfAbsent(channel, System.currentTimeMillis()); + } else if (maxConnectionLifeTimeInMs != -1 && (createTime + maxConnectionLifeTimeInMs) < System.currentTimeMillis()) { + log.debug("Channel {} expired", channel); + return false; + } + log.debug("Adding uri: {} for channel {}", uri, channel); channel.getPipeline().getContext(NettyAsyncHttpProvider.class).setAttachment(new NettyAsyncHttpProvider.DiscardEvent()); @@ -234,6 +245,7 @@ private boolean remove(IdleChannel pooledChannel) { * {@inheritDoc} */ public boolean removeAll(Channel channel) { + channel2CreationDate.remove(channel); return !isClosed.get() && remove(channel2IdleChannel.get(channel)); } @@ -263,11 +275,13 @@ public void destroy() { } connectionsPool.clear(); channel2IdleChannel.clear(); + channel2CreationDate.clear(); } private void close(Channel channel) { try { channel.getPipeline().getContext(NettyAsyncHttpProvider.class).setAttachment(new NettyAsyncHttpProvider.DiscardEvent()); + channel2CreationDate.remove(channel); channel.close(); } catch (Throwable t) { // noop From ce36eccf2a55db9bca1db6a1ea883e65f9040895 Mon Sep 17 00:00:00 2001 From: Liuichi Kumai Date: Sat, 1 Jun 2013 11:34:39 +0900 Subject: [PATCH 149/264] SSL connection pooling doesn't work with grizzly provider --- .../http/client/providers/grizzly/GrizzlyConnectionsPool.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyConnectionsPool.java b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyConnectionsPool.java index e3478e5769..226cb2acb7 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyConnectionsPool.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyConnectionsPool.java @@ -94,7 +94,7 @@ public void onClosed(Connection connection, Connection.CloseType closeType) thro */ public boolean offer(String uri, Connection connection) { - if (cacheSSLConnections && isSecure(uri)) { + if (!cacheSSLConnections && isSecure(uri)) { return false; } From b5aff2515cc008265b58526658f5930bccaec6f4 Mon Sep 17 00:00:00 2001 From: Liuichi Kumai Date: Mon, 3 Jun 2013 10:09:43 +0900 Subject: [PATCH 150/264] Uses DateUtil.millisTime() instead of System.currentTimeMillis() --- .../http/client/providers/netty/NettyConnectionsPool.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyConnectionsPool.java b/src/main/java/com/ning/http/client/providers/netty/NettyConnectionsPool.java index ed91845c14..fc467fecce 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyConnectionsPool.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyConnectionsPool.java @@ -162,8 +162,8 @@ public boolean offer(String uri, Channel channel) { Long createTime = channel2CreationDate.get(channel); if (createTime == null) { - channel2CreationDate.putIfAbsent(channel, System.currentTimeMillis()); - } else if (maxConnectionLifeTimeInMs != -1 && (createTime + maxConnectionLifeTimeInMs) < System.currentTimeMillis()) { + channel2CreationDate.putIfAbsent(channel, millisTime()); + } else if (maxConnectionLifeTimeInMs != -1 && (createTime + maxConnectionLifeTimeInMs) < millisTime()) { log.debug("Channel {} expired", channel); return false; } From 0d25e97d65f4b51a8d19a66dc0d3b20eff1146b6 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 3 Jun 2013 22:27:52 +0200 Subject: [PATCH 151/264] Don't use StringBuilder.deleteCharAt to remove last char, close #313 --- .../grizzly/GrizzlyAsyncHttpProvider.java | 4 ++-- .../http/util/AsyncHttpProviderUtils.java | 1 - .../client/async/AsyncProvidersBasicTest.java | 20 +++++++++---------- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java index 5eae0fd8c0..80313f05c9 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java @@ -1030,11 +1030,11 @@ private void addQueryString(final Request request, } } } - String queryString = sb.deleteCharAt((sb.length() - 1)).toString(); + sb.setLength(sb.length() - 1); + String queryString = sb.toString(); requestPacket.setQueryString(queryString); } - } } // END AsyncHttpClientFiler diff --git a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java index 81421fd108..acb2317687 100644 --- a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java +++ b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java @@ -32,7 +32,6 @@ import com.ning.http.client.Cookie; import com.ning.http.client.FilePart; import com.ning.http.client.FluentCaseInsensitiveStringsMap; -import com.ning.http.client.FluentStringsMap; import com.ning.http.client.HttpResponseBodyPart; import com.ning.http.client.HttpResponseBodyPartsInputStream; import com.ning.http.client.Part; diff --git a/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java b/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java index 84b460fca0..52bd48bfe3 100755 --- a/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java +++ b/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java @@ -557,7 +557,7 @@ public void asyncDoPostBytesTest() throws Throwable { sb.append(i); sb.append("&"); } - sb.deleteCharAt(sb.length() - 1); + sb.setLength(sb.length() - 1); client.preparePost(getTargetUrl()).setHeaders(h).setBody(sb.toString()).execute(new AsyncCompletionHandlerAdapter() { @@ -600,7 +600,7 @@ public void asyncDoPostInputStreamTest() throws Throwable { sb.append(i); sb.append("&"); } - sb.deleteCharAt(sb.length() - 1); + sb.setLength(sb.length() - 1); ByteArrayInputStream is = new ByteArrayInputStream(sb.toString().getBytes()); client.preparePost(getTargetUrl()).setHeaders(h).setBody(is).execute(new AsyncCompletionHandlerAdapter() { @@ -643,7 +643,7 @@ public void asyncDoPutInputStreamTest() throws Throwable { sb.append(i); sb.append("&"); } - sb.deleteCharAt(sb.length() - 1); + sb.setLength(sb.length() - 1); ByteArrayInputStream is = new ByteArrayInputStream(sb.toString().getBytes()); client.preparePut(getTargetUrl()).setHeaders(h).setBody(is).execute(new AsyncCompletionHandlerAdapter() { @@ -687,7 +687,7 @@ public void asyncDoPostEntityWriterTest() throws Throwable { sb.append(i); sb.append("&"); } - sb.deleteCharAt(sb.length() - 1); + sb.setLength(sb.length() - 1); byte[] bytes = sb.toString().getBytes(); h.add("Content-Length", String.valueOf(bytes.length)); @@ -769,7 +769,7 @@ public void asyncDoPostBasicGZIPTest() throws Throwable { sb.append(i); sb.append("&"); } - sb.deleteCharAt(sb.length() - 1); + sb.setLength(sb.length() - 1); client.preparePost(getTargetUrl()).setHeaders(h).setBody(sb.toString()).execute(new AsyncCompletionHandlerAdapter() { @@ -807,7 +807,7 @@ public void asyncDoPostProxyTest() throws Throwable { sb.append(i); sb.append("&"); } - sb.deleteCharAt(sb.length() - 1); + sb.setLength(sb.length() - 1); Response response = client.preparePost(getTargetUrl()).setHeaders(h).setBody(sb.toString()).execute(new AsyncCompletionHandler() { @Override @@ -867,7 +867,7 @@ public void asyncDoPutTest() throws Throwable { sb.append(i); sb.append("&"); } - sb.deleteCharAt(sb.length() - 1); + sb.setLength(sb.length() - 1); Response response = client.preparePut(getTargetUrl()).setHeaders(h).setBody(sb.toString()).execute(new AsyncCompletionHandlerAdapter()).get(); @@ -892,7 +892,7 @@ public void asyncDoPostLatchBytesTest() throws Throwable { sb.append(i); sb.append("&"); } - sb.deleteCharAt(sb.length() - 1); + sb.setLength(sb.length() - 1); client.preparePost(getTargetUrl()).setHeaders(h).setBody(sb.toString()).execute(new AsyncCompletionHandlerAdapter() { @@ -994,7 +994,7 @@ public void asyncDoPostNullBytesTest() throws Throwable { sb.append(i); sb.append("&"); } - sb.deleteCharAt(sb.length() - 1); + sb.setLength(sb.length() - 1); Future future = client.preparePost(getTargetUrl()).setHeaders(h).setBody(sb.toString()).execute(new AsyncCompletionHandlerAdapter()); @@ -1020,7 +1020,7 @@ public void asyncDoPostListenerBytesTest() throws Throwable { sb.append(i); sb.append("&"); } - sb.deleteCharAt(sb.length() - 1); + sb.setLength(sb.length() - 1); final CountDownLatch l = new CountDownLatch(1); From 3931cd4ab44532c12e23645ef873974a72d8e6aa Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 4 Jun 2013 05:51:05 +0200 Subject: [PATCH 152/264] Drop clirr --- pom.xml | 55 ------------------------------------------------------- 1 file changed, 55 deletions(-) diff --git a/pom.xml b/pom.xml index 132577b540..6219acf768 100644 --- a/pom.xml +++ b/pom.xml @@ -426,61 +426,6 @@ - - org.codehaus.mojo - clirr-maven-plugin - 2.3 - - - **/NettyAsyncHttpProvider$* - **/AsyncHandler$STATE - **/ProxyServer$Protocol - **/Realm$AuthScheme - **/SimpleAsyncHttpClient$ErrorDocumentBehaviour - **/SpnegoEngine - **/Request - **/Request$EntityWriter - **/RequestBuilderBase - **/Response - **/Response$* - **/FilterContext - **/FilterContext$* - **/NettyResponseFuture - **/NettyResponseFuture$* - **/**ResponseBodyPart - **/**WebSocket - **/AsyncHttpProvider - **/HttpResponseBodyPartsInputStream - **/AsyncHttpProvider - **/ApacheAsyncHttpProvider - **/ApacheAsyncHttpProvider$* - **/ApacheResponse - **/GrizzlyAsyncHttpProvider - **/GrizzlyAsyncHttpProvider$* - **/GrizzlyResponse - **/JDKAsyncHttpProvider - **/JDKAsyncHttpProvider$* - **/JDKResponse - **/NettyAsyncHttpProvider - **/NettyAsyncHttpProvider$* - **/NettyResponse - **/AsyncHttpProviderUtils - **/Cookie - **/Part - **/PartBase - **/MultipartRequestEntity - - - - - check-api-compat - verify - - check-no-fork - - - - From 7c6e5d486b5e9a891b7ffc35722c863cdb2ebb35 Mon Sep 17 00:00:00 2001 From: Liu Kumai Date: Tue, 4 Jun 2013 13:11:12 +0900 Subject: [PATCH 153/264] Enable maxConnectionLifeTimeInMs option for Grizzly connection pool. --- .../grizzly/GrizzlyConnectionsPool.java | 38 +++++++++++++++---- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyConnectionsPool.java b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyConnectionsPool.java index 226cb2acb7..9f93fd364f 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyConnectionsPool.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyConnectionsPool.java @@ -13,6 +13,8 @@ package com.ning.http.client.providers.grizzly; +import static com.ning.http.util.DateUtil.millisTime; + import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.ConnectionsPool; @@ -55,6 +57,7 @@ public class GrizzlyConnectionsPool implements ConnectionsPool= 0) { - resolver.setTimeoutMs(c, System.currentTimeMillis() + timeout); + long timeoutMs = UNSET_TIMEOUT; + long currentTime = millisTime(); + if (maxConnectionLifeTimeInMs < 0 && timeout >= 0) { + timeoutMs = currentTime + timeout; + } else if (maxConnectionLifeTimeInMs >= 0) { + long t = resolver.getTimeoutMs(c); + if (t == UNSET_TIMEOUT) { + if (timeout >= 0) { + timeoutMs = currentTime + Math.min(maxConnectionLifeTimeInMs, timeout); + } else { + timeoutMs = currentTime + maxConnectionLifeTimeInMs; + } + } else { + if (timeout >= 0) { + timeoutMs = Math.min(t, currentTime + timeout); + } + } } + resolver.setTimeoutMs(c, timeoutMs); queue.offer(c); count.incrementAndGet(); } @@ -458,7 +480,7 @@ void setTimeoutMs(final Connection c, final long timeoutMs) { static final class IdleRecord { - volatile long timeoutMs; + volatile long timeoutMs = UNSET_TIMEOUT; } // END IdleRecord From aa8a2514d71422527968770c51dbfadaf1ef420c Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 4 Jun 2013 23:42:23 +0200 Subject: [PATCH 154/264] Don't force FluentStringsMap null values into empty strings, close #234 --- .../ning/http/client/FluentStringsMap.java | 30 +++---------------- .../client/async/FluentStringsMapTest.java | 4 +-- .../http/client/async/PostWithQSTest.java | 23 ++++++++++++++ 3 files changed, 29 insertions(+), 28 deletions(-) diff --git a/src/main/java/com/ning/http/client/FluentStringsMap.java b/src/main/java/com/ning/http/client/FluentStringsMap.java index 0ca87cab48..b540b70896 100644 --- a/src/main/java/com/ning/http/client/FluentStringsMap.java +++ b/src/main/java/com/ning/http/client/FluentStringsMap.java @@ -69,24 +69,6 @@ public FluentStringsMap add(String key, String... values) { return this; } - private List fetchValues(Collection values) { - List result = null; - - if (values != null) { - for (String value : values) { - if (value == null) { - value = ""; - } - if (result == null) { - // lazy initialization - result = new ArrayList(); - } - result.add(value); - } - } - return result; - } - /** * Adds the specified values and returns this object. * @@ -97,16 +79,14 @@ private List fetchValues(Collection values) { */ public FluentStringsMap add(String key, Collection values) { if (key != null) { - List nonNullValues = fetchValues(values); - - if (nonNullValues != null) { + if (isNonEmpty(values)) { List curValues = this.values.get(key); if (curValues == null) { curValues = new ArrayList(); this.values.put(key, curValues); } - curValues.addAll(nonNullValues); + curValues.addAll(values); } } return this; @@ -162,12 +142,10 @@ public FluentStringsMap replace(final String key, final String... values) { */ public FluentStringsMap replace(final String key, final Collection values) { if (key != null) { - List nonNullValues = fetchValues(values); - - if (nonNullValues == null) { + if (values == null) { this.values.remove(key); } else { - this.values.put(key, nonNullValues); + this.values.put(key, new ArrayList(values)); } } return this; diff --git a/src/test/java/com/ning/http/client/async/FluentStringsMapTest.java b/src/test/java/com/ning/http/client/async/FluentStringsMapTest.java index d6c6795985..0ca6100ed2 100644 --- a/src/test/java/com/ning/http/client/async/FluentStringsMapTest.java +++ b/src/test/java/com/ning/http/client/async/FluentStringsMapTest.java @@ -119,8 +119,8 @@ public void nullValueTest() { map.add("foo", (String) null); - assertEquals(map.getFirstValue("foo"), ""); - assertEquals(map.getJoinedValue("foo", ", "), ""); + assertEquals(map.getFirstValue("foo"), null); + assertEquals(map.getJoinedValue("foo", ", "), null); assertEquals(map.get("foo").size(), 1); } diff --git a/src/test/java/com/ning/http/client/async/PostWithQSTest.java b/src/test/java/com/ning/http/client/async/PostWithQSTest.java index 39cb9e1c7b..af49ee6728 100644 --- a/src/test/java/com/ning/http/client/async/PostWithQSTest.java +++ b/src/test/java/com/ning/http/client/async/PostWithQSTest.java @@ -113,6 +113,29 @@ public void postWithNulParamsQS() throws IOException, ExecutionException, Timeou try { Future f = client.preparePost("http://127.0.0.1/" + port1 + "/?a=b&c&d=e").setBody("abc".getBytes()).execute(new AsyncCompletionHandlerBase() { + /* @Override */ + public STATE onStatusReceived(final HttpResponseStatus status) throws Exception { + if (!status.getUrl().toURL().toString().equals("http://127.0.0.1/" + port1 + "/?a=b&c&d=e")) { + throw new IOException("failed to parse the query properly"); + } + return super.onStatusReceived(status); + } + + }); + Response resp = f.get(3, TimeUnit.SECONDS); + assertNotNull(resp); + assertEquals(resp.getStatusCode(), HttpServletResponse.SC_OK); + } finally { + client.close(); + } + } + + @Test(groups = { "standalone", "default_provider" }) + public void postWithEmptyParamsQS() throws IOException, ExecutionException, TimeoutException, InterruptedException { + AsyncHttpClient client = getAsyncHttpClient(null); + try { + Future f = client.preparePost("http://127.0.0.1/" + port1 + "/?a=b&c=&d=e").setBody("abc".getBytes()).execute(new AsyncCompletionHandlerBase() { + /* @Override */ public STATE onStatusReceived(final HttpResponseStatus status) throws Exception { if (!status.getUrl().toURL().toString().equals("http://127.0.0.1/" + port1 + "/?a=b&c=&d=e")) { From 1757e07462b4d106d66af7de820def7d9aceceda Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 5 Jun 2013 12:00:36 +0200 Subject: [PATCH 155/264] Don't eagerly create AsyncHttpClientConfig pool threads, close #315 --- .../http/client/AsyncHttpClientConfig.java | 41 +++++++++++-------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java b/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java index c4c9341345..323df1c071 100644 --- a/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java @@ -519,20 +519,8 @@ public static class Builder { private boolean useProxyProperties = Boolean.getBoolean(ASYNC_CLIENT + "useProxyProperties"); private boolean allowPoolingConnection = true; private boolean useRelativeURIsWithSSLProxies = Boolean.getBoolean(ASYNC_CLIENT + "useRelativeURIsWithSSLProxies"); - private ScheduledExecutorService reaper = Executors.newScheduledThreadPool(Runtime.getRuntime().availableProcessors(), new ThreadFactory() { - public Thread newThread(Runnable r) { - Thread t = new Thread(r, "AsyncHttpClient-Reaper"); - t.setDaemon(true); - return t; - } - }); - private ExecutorService applicationThreadPool = Executors.newCachedThreadPool(new ThreadFactory() { - public Thread newThread(Runnable r) { - Thread t = new Thread(r, "AsyncHttpClient-Callback"); - t.setDaemon(true); - return t; - } - }); + private ScheduledExecutorService reaper; + private ExecutorService applicationThreadPool; private ProxyServer proxyServer = null; private SSLContext sslContext; private SSLEngineFactory sslEngineFactory; @@ -710,7 +698,6 @@ public Builder setKeepAlive(boolean allowPoolingConnection) { * @return a {@link Builder} */ public Builder setScheduledExecutorService(ScheduledExecutorService reaper) { - if (this.reaper != null) this.reaper.shutdown(); this.reaper = reaper; return this; } @@ -724,7 +711,6 @@ public Builder setScheduledExecutorService(ScheduledExecutorService reaper) { * @return a {@link Builder} */ public Builder setExecutorService(ExecutorService applicationThreadPool) { - if (this.applicationThreadPool != null) this.applicationThreadPool.shutdown(); this.applicationThreadPool = applicationThreadPool; return this; } @@ -1058,6 +1044,29 @@ public Builder(AsyncHttpClientConfig prototype) { */ public AsyncHttpClientConfig build() { + if (reaper == null) { + reaper = Executors.newScheduledThreadPool(Runtime.getRuntime() + .availableProcessors(), new ThreadFactory() { + public Thread newThread(Runnable r) { + Thread t = new Thread(r, "AsyncHttpClient-Reaper"); + t.setDaemon(true); + return t; + } + }); + } + + if (applicationThreadPool == null) { + applicationThreadPool = Executors + .newCachedThreadPool(new ThreadFactory() { + public Thread newThread(Runnable r) { + Thread t = new Thread(r, + "AsyncHttpClient-Callback"); + t.setDaemon(true); + return t; + } + }); + } + if (applicationThreadPool.isShutdown()) { throw new IllegalStateException("ExecutorServices closed"); } From 9821305671059f0f5502c9649aa6d805fa1f174e Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 7 Jun 2013 18:41:43 +0200 Subject: [PATCH 156/264] Make Netty provider support RFC 6265 cookie encoding, close #319 --- .../http/client/AsyncHttpClientConfig.java | 33 +++- .../java/com/ning/http/client/Cookie.java | 10 +- .../netty/NettyAsyncHttpProvider.java | 18 +- .../handler/codec/http/CookieDecoder.java | 33 +++- .../handler/codec/http/CookieEncoder.java | 174 ++++++++++++++++++ .../handler/codec/http/HttpConstants.java | 60 ++++++ 6 files changed, 300 insertions(+), 28 deletions(-) create mode 100644 src/main/java/com/ning/org/jboss/netty/handler/codec/http/CookieEncoder.java create mode 100644 src/main/java/com/ning/org/jboss/netty/handler/codec/http/HttpConstants.java diff --git a/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java b/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java index 323df1c071..ef96371ad5 100644 --- a/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java @@ -86,6 +86,7 @@ public class AsyncHttpClientConfig { protected boolean strict302Handling; protected boolean useRelativeURIsWithSSLProxies; protected int maxConnectionLifeTimeInMs; + protected boolean rfc6265CookieEncoding; protected AsyncHttpClientConfig() { } @@ -121,7 +122,8 @@ private AsyncHttpClientConfig(int maxTotalConnections, HostnameVerifier hostnameVerifier, int ioThreadMultiplier, boolean strict302Handling, - boolean useRelativeURIsWithSSLProxies) { + boolean useRelativeURIsWithSSLProxies, + boolean rfc6265CookieEncoding) { this.maxTotalConnections = maxTotalConnections; this.maxConnectionPerHost = maxConnectionPerHost; @@ -152,6 +154,7 @@ private AsyncHttpClientConfig(int maxTotalConnections, this.hostnameVerifier = hostnameVerifier; this.ioThreadMultiplier = ioThreadMultiplier; this.strict302Handling = strict302Handling; + this.rfc6265CookieEncoding = rfc6265CookieEncoding; if (applicationThreadPool == null) { this.applicationThreadPool = Executors.newCachedThreadPool(); @@ -500,6 +503,16 @@ public int getMaxConnectionLifeTimeInMs() { return maxConnectionLifeTimeInMs; } + /** + * @returntrue if AHC should use rfc6265 for encoding client side cookies, + * otherwise false. + * + * @since 1.7.18 + */ + public boolean isRfc6265CookieEncoding() { + return rfc6265CookieEncoding; + } + /** * Builder for an {@link AsyncHttpClient} */ @@ -538,6 +551,7 @@ public static class Builder { private HostnameVerifier hostnameVerifier = new AllowAllHostnameVerifier(); private int ioThreadMultiplier = 2; private boolean strict302Handling; + private boolean rfc6265CookieEncoding; public Builder() { } @@ -992,6 +1006,19 @@ public Builder setMaxConnectionLifeTimeInMs(int maxConnectionLifeTimeInMs) { return this; } + /** + * Configures this AHC instance to use RFC 6265 cookie encoding style + * + * @param rfc6265CookieEncoding + * @return this + * + * @since 1.7.18 + */ + public Builder setRfc6265CookieEncoding(boolean rfc6265CookieEncoding) { + this.rfc6265CookieEncoding = rfc6265CookieEncoding; + return this; + } + /** * Create a config builder with values taken from the given prototype configuration. * @@ -1035,6 +1062,7 @@ public Builder(AsyncHttpClientConfig prototype) { removeQueryParamOnRedirect = prototype.isRemoveQueryParamOnRedirect(); hostnameVerifier = prototype.getHostnameVerifier(); strict302Handling = prototype.isStrict302Handling(); + rfc6265CookieEncoding = prototype.isRfc6265CookieEncoding(); } /** @@ -1107,7 +1135,8 @@ public Thread newThread(Runnable r) { hostnameVerifier, ioThreadMultiplier, strict302Handling, - useRelativeURIsWithSSLProxies); + useRelativeURIsWithSSLProxies, + rfc6265CookieEncoding); } } } diff --git a/src/main/java/com/ning/http/client/Cookie.java b/src/main/java/com/ning/http/client/Cookie.java index de8773f744..b3be657d5a 100644 --- a/src/main/java/com/ning/http/client/Cookie.java +++ b/src/main/java/com/ning/http/client/Cookie.java @@ -24,6 +24,7 @@ public class Cookie implements Comparable { private final String domain; private final String name; private final String value; + private final String rawValue; private final String path; private final int maxAge; private final boolean secure; @@ -41,10 +42,10 @@ public Cookie(String domain, String name, String value, String path, int maxAge, } public Cookie(String domain, String name, String value, String path, int maxAge, boolean secure, int version) { - this(domain, name, value, path, maxAge, secure, version, false, false, null, null, Collections. emptySet()); + this(domain, name, value, value, path, maxAge, secure, version, false, false, null, null, Collections. emptySet()); } - public Cookie(String domain, String name, String value, String path, int maxAge, boolean secure, int version, boolean httpOnly, boolean discard, String comment, String commentUrl, Iterable ports) { + public Cookie(String domain, String name, String value, String rawValue, String path, int maxAge, boolean secure, int version, boolean httpOnly, boolean discard, String comment, String commentUrl, Iterable ports) { if (name == null) { throw new NullPointerException("name"); @@ -85,6 +86,7 @@ public Cookie(String domain, String name, String value, String path, int maxAge, this.name = name; this.value = value; + this.rawValue = rawValue; this.domain = validateValue("domain", domain); this.path = validateValue("path", path); this.maxAge = maxAge; @@ -119,6 +121,10 @@ public String getValue() { return value == null ? "" : value; } + public String getRawValue() { + return rawValue; + } + public String getPath() { return path; } diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java index 6b90a10a37..ef248e4d91 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java @@ -57,6 +57,7 @@ import com.ning.http.util.SslUtils; import com.ning.http.util.UTF8UrlEncoder; import com.ning.org.jboss.netty.handler.codec.http.CookieDecoder; +import com.ning.org.jboss.netty.handler.codec.http.CookieEncoder; import org.jboss.netty.bootstrap.ClientBootstrap; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBufferOutputStream; @@ -77,8 +78,6 @@ import org.jboss.netty.channel.socket.ClientSocketChannelFactory; import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory; import org.jboss.netty.channel.socket.oio.OioClientSocketChannelFactory; -import org.jboss.netty.handler.codec.http.CookieEncoder; -import org.jboss.netty.handler.codec.http.DefaultCookie; import org.jboss.netty.handler.codec.http.DefaultHttpChunkTrailer; import org.jboss.netty.handler.codec.http.DefaultHttpRequest; import org.jboss.netty.handler.codec.http.HttpChunk; @@ -121,7 +120,6 @@ import java.security.GeneralSecurityException; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; -import java.util.Iterator; import java.util.List; import java.util.Map.Entry; import java.util.concurrent.Callable; @@ -753,19 +751,7 @@ else if (uri.getRawQuery() != null) if (!m.equals(HttpMethod.CONNECT)) { if (isNonEmpty(request.getCookies())) { - CookieEncoder httpCookieEncoder = new CookieEncoder(false); - Iterator ic = request.getCookies().iterator(); - Cookie c; - org.jboss.netty.handler.codec.http.Cookie cookie; - while (ic.hasNext()) { - c = ic.next(); - cookie = new DefaultCookie(c.getName(), c.getValue()); - cookie.setPath(c.getPath()); - cookie.setMaxAge(c.getMaxAge()); - cookie.setDomain(c.getDomain()); - httpCookieEncoder.addCookie(cookie); - } - nettyRequest.setHeader(HttpHeaders.Names.COOKIE, httpCookieEncoder.encode()); + nettyRequest.setHeader(HttpHeaders.Names.COOKIE, CookieEncoder.encodeClientSide(request.getCookies(), config.isRfc6265CookieEncoding())); } String reqType = request.getMethod(); diff --git a/src/main/java/com/ning/org/jboss/netty/handler/codec/http/CookieDecoder.java b/src/main/java/com/ning/org/jboss/netty/handler/codec/http/CookieDecoder.java index 138e3ac0ab..4e4eecb1b8 100644 --- a/src/main/java/com/ning/org/jboss/netty/handler/codec/http/CookieDecoder.java +++ b/src/main/java/com/ning/org/jboss/netty/handler/codec/http/CookieDecoder.java @@ -31,7 +31,7 @@ import java.util.Collections; import java.util.List; import java.util.Set; -import java.util.TreeSet; +import java.util.HashSet; import com.ning.org.jboss.netty.util.internal.StringUtil; import com.ning.http.client.Cookie; @@ -69,7 +69,8 @@ private CookieDecoder() { public static Set decode(String header) { List names = new ArrayList(8); List values = new ArrayList(8); - extractKeyValuePairs(header, names, values); + List rawValues = new ArrayList(8); + extractKeyValuePairs(header, names, values, rawValues); if (names.isEmpty()) { return Collections.emptySet(); @@ -96,16 +97,21 @@ public static Set decode(String header) { return Collections.emptySet(); } - Set cookies = new TreeSet(); + Set cookies = new HashSet(); for (; i < names.size(); i++) { String name = names.get(i); String value = values.get(i); + String rawValue = rawValues.get(i); if (value == null) { value = ""; } + if (rawValue == null) { + rawValue = ""; + } String cookieName = name; String cookieValue = value; + String cookieRawValue = rawValue; boolean discard = false; boolean secure = false; boolean httpOnly = false; @@ -164,14 +170,14 @@ public static Set decode(String header) { } } - Cookie c = new Cookie(domain, cookieName, cookieValue, path, maxAge, secure, version, httpOnly, discard, comment, commentURL, ports); + Cookie c = new Cookie(domain, cookieName, cookieValue, cookieRawValue, path, maxAge, secure, version, httpOnly, discard, comment, commentURL, ports); cookies.add(c); } return cookies; } - private static void extractKeyValuePairs(final String header, final List names, final List values) { + private static void extractKeyValuePairs(final String header, final List names, final List values, final List rawValues) { final int headerLen = header.length(); loop: for (int i = 0;;) { @@ -210,10 +216,12 @@ private static void extractKeyValuePairs(final String header, final List String name; String value; + String rawValue; if (i == headerLen) { name = null; value = null; + rawValue = null; } else { int newNameStart = i; keyValLoop: for (;;) { @@ -222,6 +230,7 @@ private static void extractKeyValuePairs(final String header, final List // NAME; (no value till ';') name = header.substring(newNameStart, i); value = null; + rawValue = null; break keyValLoop; case '=': // NAME=VALUE @@ -230,6 +239,7 @@ private static void extractKeyValuePairs(final String header, final List if (i == headerLen) { // NAME= (empty value, i.e. nothing after '=') value = ""; + rawValue = ""; break keyValLoop; } @@ -238,17 +248,21 @@ private static void extractKeyValuePairs(final String header, final List if (c == '"' || c == '\'') { // NAME="VALUE" or NAME='VALUE' StringBuilder newValueBuf = new StringBuilder(header.length() - i); + StringBuilder newRawValueBuf = new StringBuilder(header.length() - i); + newRawValueBuf.append(c); final char q = c; boolean hadBackslash = false; i++; for (;;) { if (i == headerLen) { value = newValueBuf.toString(); + rawValue = newRawValueBuf.toString(); break keyValLoop; } if (hadBackslash) { hadBackslash = false; c = header.charAt(i++); + newRawValueBuf.append(c); switch (c) { case '\\': case '"': @@ -262,8 +276,10 @@ private static void extractKeyValuePairs(final String header, final List } } else { c = header.charAt(i++); + newRawValueBuf.append(c); if (c == q) { value = newValueBuf.toString(); + rawValue = newRawValueBuf.toString(); break keyValLoop; } newValueBuf.append(c); @@ -276,10 +292,10 @@ private static void extractKeyValuePairs(final String header, final List // NAME=VALUE; int semiPos = header.indexOf(';', i); if (semiPos > 0) { - value = header.substring(newValueStart, semiPos); + value = rawValue = header.substring(newValueStart, semiPos); i = semiPos; } else { - value = header.substring(newValueStart); + value = rawValue = header.substring(newValueStart); i = headerLen; } } @@ -291,7 +307,7 @@ private static void extractKeyValuePairs(final String header, final List if (i == headerLen) { // NAME (no value till the end of string) name = header.substring(newNameStart); - value = null; + value = rawValue = null; break; } } @@ -299,6 +315,7 @@ private static void extractKeyValuePairs(final String header, final List names.add(name); values.add(value); + rawValues.add(rawValue); } } } diff --git a/src/main/java/com/ning/org/jboss/netty/handler/codec/http/CookieEncoder.java b/src/main/java/com/ning/org/jboss/netty/handler/codec/http/CookieEncoder.java new file mode 100644 index 0000000000..bc3342f745 --- /dev/null +++ b/src/main/java/com/ning/org/jboss/netty/handler/codec/http/CookieEncoder.java @@ -0,0 +1,174 @@ +/* + * Copyright 2012 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +/* + * Copyright (c) 2010-2012 Sonatype, Inc. All rights reserved. + * + * This program is licensed to you under the Apache License Version 2.0, + * and you may not use this file except in compliance with the Apache License Version 2.0. + * You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the Apache License Version 2.0 is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under. + */ +package com.ning.org.jboss.netty.handler.codec.http; + +import java.util.Collection; + +import org.jboss.netty.handler.codec.http.HttpConstants; +import org.jboss.netty.handler.codec.http.HttpRequest; +import org.jboss.netty.handler.codec.http.HttpResponse; + +import com.ning.http.client.Cookie; + +/** + * Encodes {@link Cookie}s into an HTTP header value. This encoder can encode + * the HTTP cookie version 0, 1, and 2. + *

+ * This encoder is stateful. It maintains an internal data structure that + * holds the {@link Cookie}s added by the {@link #addCookie(String, String)} + * method. Once {@link #encode()} is called, all added {@link Cookie}s are + * encoded into an HTTP header value and all {@link Cookie}s in the internal + * data structure are removed so that the encoder can start over. + *

+ * // Client-side example
+ * {@link HttpRequest} req = ...;
+ * {@link CookieEncoder} encoder = new {@link CookieEncoder}(false);
+ * encoder.addCookie("JSESSIONID", "1234");
+ * res.setHeader("Cookie", encoder.encode());
+ *
+ * // Server-side example
+ * {@link HttpResponse} res = ...;
+ * {@link CookieEncoder} encoder = new {@link CookieEncoder}(true);
+ * encoder.addCookie("JSESSIONID", "1234");
+ * res.setHeader("Set-Cookie", encoder.encode());
+ * 
+ * + * @see CookieDecoder + * + * @apiviz.stereotype utility + * @apiviz.has org.jboss.netty.handler.codec.http.Cookie oneway - - encodes + */ +// This fork brings support for RFC6265, that's used if the Cookie has a raw value +public final class CookieEncoder { + + private CookieEncoder() { + } + + public static String encodeClientSide(Collection cookies, boolean useRFC6265Style) { + StringBuilder sb = new StringBuilder(); + + for (Cookie cookie: cookies) { + if (useRFC6265Style) + encodeRFC6265Style(sb, cookie); + else + encodeRFC2965Style(sb, cookie); + } + + if (sb.length() > 0) { + sb.setLength(sb.length() - 2); + } + return sb.toString(); + } + + private static void encodeRFC6265Style(StringBuilder sb, Cookie cookie) { + addUnquoted(sb, cookie.getName(), cookie.getRawValue()); + } + + private static void encodeRFC2965Style(StringBuilder sb, Cookie cookie) { + if (cookie.getVersion() >= 1) { + add(sb, '$' + CookieHeaderNames.VERSION, 1); + } + + add(sb, cookie.getName(), cookie.getValue()); + + if (cookie.getPath() != null) { + add(sb, '$' + CookieHeaderNames.PATH, cookie.getPath()); + } + + if (cookie.getDomain() != null) { + add(sb, '$' + CookieHeaderNames.DOMAIN, cookie.getDomain()); + } + + if (cookie.getVersion() >= 1) { + if (!cookie.getPorts().isEmpty()) { + sb.append('$'); + sb.append(CookieHeaderNames.PORT); + sb.append((char) HttpConstants.EQUALS); + sb.append((char) HttpConstants.DOUBLE_QUOTE); + for (int port: cookie.getPorts()) { + sb.append(port); + sb.append((char) HttpConstants.COMMA); + } + sb.setCharAt(sb.length() - 1, (char) HttpConstants.DOUBLE_QUOTE); + sb.append((char) HttpConstants.SEMICOLON); + sb.append((char) HttpConstants.SP); + } + } + } + + private static void add(StringBuilder sb, String name, String val) { + if (val == null) { + addQuoted(sb, name, ""); + return; + } + + for (int i = 0; i < val.length(); i ++) { + char c = val.charAt(i); + switch (c) { + case '\t': case ' ': case '"': case '(': case ')': case ',': + case '/': case ':': case ';': case '<': case '=': case '>': + case '?': case '@': case '[': case '\\': case ']': + case '{': case '}': + addQuoted(sb, name, val); + return; + } + } + + addUnquoted(sb, name, val); + } + + private static void addUnquoted(StringBuilder sb, String name, String val) { + sb.append(name); + sb.append((char) HttpConstants.EQUALS); + sb.append(val); + sb.append((char) HttpConstants.SEMICOLON); + sb.append((char) HttpConstants.SP); + } + + private static void addQuoted(StringBuilder sb, String name, String val) { + if (val == null) { + val = ""; + } + + sb.append(name); + sb.append((char) HttpConstants.EQUALS); + sb.append((char) HttpConstants.DOUBLE_QUOTE); + sb.append(val.replace("\\", "\\\\").replace("\"", "\\\"")); + sb.append((char) HttpConstants.DOUBLE_QUOTE); + sb.append((char) HttpConstants.SEMICOLON); + sb.append((char) HttpConstants.SP); + } + + private static void add(StringBuilder sb, String name, int val) { + sb.append(name); + sb.append((char) HttpConstants.EQUALS); + sb.append(val); + sb.append((char) HttpConstants.SEMICOLON); + sb.append((char) HttpConstants.SP); + } +} diff --git a/src/main/java/com/ning/org/jboss/netty/handler/codec/http/HttpConstants.java b/src/main/java/com/ning/org/jboss/netty/handler/codec/http/HttpConstants.java new file mode 100644 index 0000000000..1880dc4fed --- /dev/null +++ b/src/main/java/com/ning/org/jboss/netty/handler/codec/http/HttpConstants.java @@ -0,0 +1,60 @@ +package com.ning.org.jboss.netty.handler.codec.http; + +import java.nio.charset.Charset; + +public final class HttpConstants { + + /** + * Horizontal space + */ + public static final byte SP = 32; + + /** + * Horizontal tab + */ + public static final byte HT = 9; + + /** + * Carriage return + */ + public static final byte CR = 13; + + /** + * Equals '=' + */ + public static final byte EQUALS = 61; + + /** + * Line feed character + */ + public static final byte LF = 10; + + /** + * Colon ':' + */ + public static final byte COLON = 58; + + /** + * Semicolon ';' + */ + public static final byte SEMICOLON = 59; + + /** + * Comma ',' + */ + public static final byte COMMA = 44; + + /** + * Double quote '"' + */ + public static final byte DOUBLE_QUOTE = '"'; + + /** + * Default character set (UTF-8) + */ + public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8"); + + private HttpConstants() { + // Unused + } +} From f40511b2866ce2de454f0a3a5e8214ab74f98aa7 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Sat, 8 Jun 2013 07:44:37 +0200 Subject: [PATCH 157/264] Minor clean up --- .../ning/http/client/RequestBuilderBase.java | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/ning/http/client/RequestBuilderBase.java b/src/main/java/com/ning/http/client/RequestBuilderBase.java index 1f5c273566..c1e451fa38 100644 --- a/src/main/java/com/ning/http/client/RequestBuilderBase.java +++ b/src/main/java/com/ning/http/client/RequestBuilderBase.java @@ -388,27 +388,27 @@ public T setLocalInetAddress(InetAddress address) { private URI buildURI(String url) { URI uri = URI.create(url); - StringBuilder buildedUrl = new StringBuilder(); - if (uri.getScheme() != null) { - buildedUrl.append(uri.getScheme()); - buildedUrl.append("://"); - } - - if (uri.getAuthority() != null) { - buildedUrl.append(uri.getAuthority()); - } - if (uri.getRawPath() != null) { - buildedUrl.append(uri.getRawPath()); - } else { + if (uri.getRawPath() == null) { // AHC-96 // Let's try to derive it + StringBuilder buildedUrl = new StringBuilder(); + + if (uri.getScheme() != null) { + buildedUrl.append(uri.getScheme()); + buildedUrl.append("://"); + } + + if (uri.getAuthority() != null) { + buildedUrl.append(uri.getAuthority()); + } if (url.indexOf("://") == -1) { String s = buildedUrl.toString(); url = s + url.substring(uri.getScheme().length() + 1); return buildURI(url); } else { - throw new IllegalArgumentException("Invalid url " + uri.toString()); + throw new IllegalArgumentException("Invalid url " + + uri.toString()); } } From 961396fcd2ec5c8b6c5eca2b848148ed81cac31e Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Sat, 8 Jun 2013 14:23:34 +0200 Subject: [PATCH 158/264] Remove useless imports --- .../org/jboss/netty/handler/codec/http/CookieEncoder.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/main/java/com/ning/org/jboss/netty/handler/codec/http/CookieEncoder.java b/src/main/java/com/ning/org/jboss/netty/handler/codec/http/CookieEncoder.java index bc3342f745..a2297f9029 100644 --- a/src/main/java/com/ning/org/jboss/netty/handler/codec/http/CookieEncoder.java +++ b/src/main/java/com/ning/org/jboss/netty/handler/codec/http/CookieEncoder.java @@ -29,10 +29,6 @@ import java.util.Collection; -import org.jboss.netty.handler.codec.http.HttpConstants; -import org.jboss.netty.handler.codec.http.HttpRequest; -import org.jboss.netty.handler.codec.http.HttpResponse; - import com.ning.http.client.Cookie; /** From def98a7d9e86f5b5f402a2f36162872f26d31531 Mon Sep 17 00:00:00 2001 From: jfarcand Date: Tue, 11 Jun 2013 08:28:05 -0400 Subject: [PATCH 159/264] Cosmetic, make the code vim friendly --- .../netty/NettyAsyncHttpProvider.java | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java index ef248e4d91..7dbf92efc4 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java @@ -133,6 +133,7 @@ import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicBoolean; +import static com.ning.http.client.providers.netty.NettyAsyncHttpProviderConfig.*; import static com.ning.http.util.AsyncHttpProviderUtils.DEFAULT_CHARSET; import static com.ning.http.util.DateUtil.millisTime; import static com.ning.http.util.MiscUtil.isNonEmpty; @@ -194,12 +195,12 @@ public NettyAsyncHttpProvider(AsyncHttpClientConfig config) { asyncHttpProviderConfig = new NettyAsyncHttpProviderConfig(); } - if (asyncHttpProviderConfig.getProperty(NettyAsyncHttpProviderConfig.USE_BLOCKING_IO) != null) { + if (asyncHttpProviderConfig.getProperty(USE_BLOCKING_IO) != null) { socketChannelFactory = new OioClientSocketChannelFactory(config.executorService()); this.allowReleaseSocketChannelFactory = true; } else { // check if external NioClientSocketChannelFactory is defined - Object oo = asyncHttpProviderConfig.getProperty(NettyAsyncHttpProviderConfig.SOCKET_CHANNEL_FACTORY); + Object oo = asyncHttpProviderConfig.getProperty(SOCKET_CHANNEL_FACTORY); if (oo != null && NioClientSocketChannelFactory.class.isAssignableFrom(oo.getClass())) { this.socketChannelFactory = NioClientSocketChannelFactory.class.cast(oo); @@ -207,7 +208,7 @@ public NettyAsyncHttpProvider(AsyncHttpClientConfig config) { this.allowReleaseSocketChannelFactory = false; } else { ExecutorService e; - Object o = asyncHttpProviderConfig.getProperty(NettyAsyncHttpProviderConfig.BOSS_EXECUTOR_SERVICE); + Object o = asyncHttpProviderConfig.getProperty(BOSS_EXECUTOR_SERVICE); if (o != null && ExecutorService.class.isAssignableFrom(o.getClass())) { e = ExecutorService.class.cast(o); } else { @@ -286,10 +287,10 @@ public ChannelPipeline getPipeline() throws Exception { DefaultChannelFuture.setUseDeadLockChecker(false); if (asyncHttpProviderConfig != null) { - Object value = asyncHttpProviderConfig.getProperty(NettyAsyncHttpProviderConfig.EXECUTE_ASYNC_CONNECT); + Object value = asyncHttpProviderConfig.getProperty(EXECUTE_ASYNC_CONNECT); if (value != null && Boolean.class.isAssignableFrom(value.getClass())) { executeConnectAsync = Boolean.class.cast(value); - } else if (asyncHttpProviderConfig.getProperty(NettyAsyncHttpProviderConfig.DISABLE_NESTED_REQUEST) != null) { + } else if (asyncHttpProviderConfig.getProperty(DISABLE_NESTED_REQUEST) != null) { DefaultChannelFuture.setUseDeadLockChecker(true); } } @@ -308,15 +309,15 @@ public ChannelPipeline getPipeline() throws Exception { } protected void configureHttpClientCodec() { - httpClientCodecMaxInitialLineLength = asyncHttpProviderConfig.getProperty(NettyAsyncHttpProviderConfig.HTTP_CLIENT_CODEC_MAX_INITIAL_LINE_LENGTH, Integer.class, httpClientCodecMaxInitialLineLength); - httpClientCodecMaxHeaderSize = asyncHttpProviderConfig.getProperty(NettyAsyncHttpProviderConfig.HTTP_CLIENT_CODEC_MAX_HEADER_SIZE, Integer.class, httpClientCodecMaxHeaderSize); - httpClientCodecMaxChunkSize = asyncHttpProviderConfig.getProperty(NettyAsyncHttpProviderConfig.HTTP_CLIENT_CODEC_MAX_CHUNK_SIZE, Integer.class, httpClientCodecMaxChunkSize); + httpClientCodecMaxInitialLineLength = asyncHttpProviderConfig.getProperty(HTTP_CLIENT_CODEC_MAX_INITIAL_LINE_LENGTH, Integer.class, httpClientCodecMaxInitialLineLength); + httpClientCodecMaxHeaderSize = asyncHttpProviderConfig.getProperty(HTTP_CLIENT_CODEC_MAX_HEADER_SIZE, Integer.class, httpClientCodecMaxHeaderSize); + httpClientCodecMaxChunkSize = asyncHttpProviderConfig.getProperty(HTTP_CLIENT_CODEC_MAX_CHUNK_SIZE, Integer.class, httpClientCodecMaxChunkSize); } protected void configureHttpsClientCodec() { - httpsClientCodecMaxInitialLineLength = asyncHttpProviderConfig.getProperty(NettyAsyncHttpProviderConfig.HTTPS_CLIENT_CODEC_MAX_INITIAL_LINE_LENGTH, Integer.class, httpsClientCodecMaxInitialLineLength); - httpsClientCodecMaxHeaderSize = asyncHttpProviderConfig.getProperty(NettyAsyncHttpProviderConfig.HTTPS_CLIENT_CODEC_MAX_HEADER_SIZE, Integer.class, httpsClientCodecMaxHeaderSize); - httpsClientCodecMaxChunkSize = asyncHttpProviderConfig.getProperty(NettyAsyncHttpProviderConfig.HTTPS_CLIENT_CODEC_MAX_CHUNK_SIZE, Integer.class, httpsClientCodecMaxChunkSize); + httpsClientCodecMaxInitialLineLength = asyncHttpProviderConfig.getProperty(HTTPS_CLIENT_CODEC_MAX_INITIAL_LINE_LENGTH, Integer.class, httpsClientCodecMaxInitialLineLength); + httpsClientCodecMaxHeaderSize = asyncHttpProviderConfig.getProperty(HTTPS_CLIENT_CODEC_MAX_HEADER_SIZE, Integer.class, httpsClientCodecMaxHeaderSize); + httpsClientCodecMaxChunkSize = asyncHttpProviderConfig.getProperty(HTTPS_CLIENT_CODEC_MAX_CHUNK_SIZE, Integer.class, httpsClientCodecMaxChunkSize); } void constructSSLPipeline(final NettyConnectListener cl) { @@ -997,7 +998,7 @@ private ListenableFuture doConnect(final Request request, final AsyncHand // Do no enable this with win. if (System.getProperty("os.name").toLowerCase().indexOf("win") == -1) { - bootstrap.setOption("reuseAddress", asyncHttpProviderConfig.getProperty(NettyAsyncHttpProviderConfig.REUSE_ADDRESS)); + bootstrap.setOption("reuseAddress", asyncHttpProviderConfig.getProperty(REUSE_ADDRESS)); } try { From c67129e7a2b55ab3c42dd8a8e47b2897f383f06e Mon Sep 17 00:00:00 2001 From: jfarcand Date: Wed, 12 Jun 2013 09:19:12 -0400 Subject: [PATCH 160/264] Fixes #317 --- .../http/client/providers/netty/NettyAsyncHttpProvider.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java index 7dbf92efc4..2d77be1d56 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java @@ -2310,11 +2310,11 @@ public void handle(ChannelHandlerContext ctx, MessageEvent e) throws Exception { throw new IOException(String.format("Invalid challenge. Actual: %s. Expected: %s", accept, key)); } - ctx.getPipeline().get(HttpResponseDecoder.class).replace("ws-decoder", new WebSocket08FrameDecoder(false, false)); - ctx.getPipeline().replace("http-encoder", "ws-encoder", new WebSocket08FrameEncoder(true)); if (h.onHeadersReceived(responseHeaders) == STATE.CONTINUE) { h.onSuccess(new NettyWebSocket(ctx.getChannel())); } + ctx.getPipeline().get(HttpResponseDecoder.class).replace("ws-decoder", new WebSocket08FrameDecoder(false, false)); + ctx.getPipeline().replace("http-encoder", "ws-encoder", new WebSocket08FrameEncoder(true)); future.done(null); } else if (e.getMessage() instanceof WebSocketFrame) { final WebSocketFrame frame = (WebSocketFrame) e.getMessage(); From f066cd7d7d09c0349856f167e9f365738823b961 Mon Sep 17 00:00:00 2001 From: jfarcand Date: Wed, 12 Jun 2013 10:26:56 -0400 Subject: [PATCH 161/264] One more fix for #317: allow sending message in onSucces --- .../http/client/providers/netty/NettyAsyncHttpProvider.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java index 2d77be1d56..89a8c11e79 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java @@ -2310,11 +2310,11 @@ public void handle(ChannelHandlerContext ctx, MessageEvent e) throws Exception { throw new IOException(String.format("Invalid challenge. Actual: %s. Expected: %s", accept, key)); } + ctx.getPipeline().replace("http-encoder", "ws-encoder", new WebSocket08FrameEncoder(true)); if (h.onHeadersReceived(responseHeaders) == STATE.CONTINUE) { h.onSuccess(new NettyWebSocket(ctx.getChannel())); } ctx.getPipeline().get(HttpResponseDecoder.class).replace("ws-decoder", new WebSocket08FrameDecoder(false, false)); - ctx.getPipeline().replace("http-encoder", "ws-encoder", new WebSocket08FrameEncoder(true)); future.done(null); } else if (e.getMessage() instanceof WebSocketFrame) { final WebSocketFrame frame = (WebSocketFrame) e.getMessage(); From 3dbb989dc77b48068916857c5afaf29f3c1872ce Mon Sep 17 00:00:00 2001 From: jfarcand Date: Wed, 12 Jun 2013 10:41:25 -0400 Subject: [PATCH 162/264] Final fix for #317: allow sending and receiving message in onSucces --- .../netty/NettyAsyncHttpProvider.java | 24 +++++++++++++++---- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java index 89a8c11e79..af983e4ce5 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java @@ -123,6 +123,7 @@ import java.util.List; import java.util.Map.Entry; import java.util.concurrent.Callable; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -2243,10 +2244,8 @@ private final class WebSocketProtocol implements Protocol { private static final byte OPCODE_TEXT = 0x1; private static final byte OPCODE_BINARY = 0x2; private static final byte OPCODE_UNKNOWN = -1; - - protected ChannelBuffer byteBuffer = null; - protected StringBuilder textBuffer = null; protected byte pendingOpcode = OPCODE_UNKNOWN; + private final CountDownLatch onSuccessLatch = new CountDownLatch(1); // @Override public void handle(ChannelHandlerContext ctx, MessageEvent e) throws Exception { @@ -2311,12 +2310,27 @@ public void handle(ChannelHandlerContext ctx, MessageEvent e) throws Exception { } ctx.getPipeline().replace("http-encoder", "ws-encoder", new WebSocket08FrameEncoder(true)); + ctx.getPipeline().get(HttpResponseDecoder.class).replace("ws-decoder", new WebSocket08FrameDecoder(false, false)); if (h.onHeadersReceived(responseHeaders) == STATE.CONTINUE) { - h.onSuccess(new NettyWebSocket(ctx.getChannel())); + try { + h.onSuccess(new NettyWebSocket(ctx.getChannel())); + } catch (Exception ex) { + NettyAsyncHttpProvider.this.log.warn("onSuccess unexexpected exception", ex); + } finally { + /** + * A websocket message may always be included with the handshake response. As soon as we replace + * the ws-decoder, this class can be called and we are still inside the onSuccess processing + * causing invalid state. + */ + onSuccessLatch.countDown(); + } } - ctx.getPipeline().get(HttpResponseDecoder.class).replace("ws-decoder", new WebSocket08FrameDecoder(false, false)); future.done(null); } else if (e.getMessage() instanceof WebSocketFrame) { + + // Give a chance to the onSuccess to complete before processing message. + onSuccessLatch.await(); + final WebSocketFrame frame = (WebSocketFrame) e.getMessage(); if (frame instanceof TextWebSocketFrame) { From 8d3d55cf97a784b73c336af5541faee1319607ba Mon Sep 17 00:00:00 2001 From: Ryan Lubke Date: Wed, 12 Jun 2013 09:03:38 -0700 Subject: [PATCH 163/264] Uptake Grizzly 2.3.3. --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 6219acf768..1d5800f248 100644 --- a/pom.xml +++ b/pom.xml @@ -489,7 +489,7 @@ org.glassfish.grizzly grizzly-websockets - 2.3.2 + 2.3.3 true From 7f05cca61a6a9ad5d4b1857dec2c0bba8c403d70 Mon Sep 17 00:00:00 2001 From: jfarcand Date: Fri, 14 Jun 2013 09:18:58 -0400 Subject: [PATCH 164/264] Proper Fixes #317 --- .../netty/NettyAsyncHttpProvider.java | 49 +++++++++++-------- 1 file changed, 29 insertions(+), 20 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java index af983e4ce5..097cf5d389 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java @@ -123,7 +123,6 @@ import java.util.List; import java.util.Map.Entry; import java.util.concurrent.Callable; -import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -134,7 +133,18 @@ import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicBoolean; -import static com.ning.http.client.providers.netty.NettyAsyncHttpProviderConfig.*; +import static com.ning.http.client.providers.netty.NettyAsyncHttpProviderConfig.BOSS_EXECUTOR_SERVICE; +import static com.ning.http.client.providers.netty.NettyAsyncHttpProviderConfig.DISABLE_NESTED_REQUEST; +import static com.ning.http.client.providers.netty.NettyAsyncHttpProviderConfig.EXECUTE_ASYNC_CONNECT; +import static com.ning.http.client.providers.netty.NettyAsyncHttpProviderConfig.HTTPS_CLIENT_CODEC_MAX_CHUNK_SIZE; +import static com.ning.http.client.providers.netty.NettyAsyncHttpProviderConfig.HTTPS_CLIENT_CODEC_MAX_HEADER_SIZE; +import static com.ning.http.client.providers.netty.NettyAsyncHttpProviderConfig.HTTPS_CLIENT_CODEC_MAX_INITIAL_LINE_LENGTH; +import static com.ning.http.client.providers.netty.NettyAsyncHttpProviderConfig.HTTP_CLIENT_CODEC_MAX_CHUNK_SIZE; +import static com.ning.http.client.providers.netty.NettyAsyncHttpProviderConfig.HTTP_CLIENT_CODEC_MAX_HEADER_SIZE; +import static com.ning.http.client.providers.netty.NettyAsyncHttpProviderConfig.HTTP_CLIENT_CODEC_MAX_INITIAL_LINE_LENGTH; +import static com.ning.http.client.providers.netty.NettyAsyncHttpProviderConfig.REUSE_ADDRESS; +import static com.ning.http.client.providers.netty.NettyAsyncHttpProviderConfig.SOCKET_CHANNEL_FACTORY; +import static com.ning.http.client.providers.netty.NettyAsyncHttpProviderConfig.USE_BLOCKING_IO; import static com.ning.http.util.AsyncHttpProviderUtils.DEFAULT_CHARSET; import static com.ning.http.util.DateUtil.millisTime; import static com.ning.http.util.MiscUtil.isNonEmpty; @@ -2245,7 +2255,18 @@ private final class WebSocketProtocol implements Protocol { private static final byte OPCODE_BINARY = 0x2; private static final byte OPCODE_UNKNOWN = -1; protected byte pendingOpcode = OPCODE_UNKNOWN; - private final CountDownLatch onSuccessLatch = new CountDownLatch(1); + private final AtomicBoolean onSuccesInvoked = new AtomicBoolean(); + + // We don't need to synchronize as replacing the "ws-decoder" will process using the same thread. + private void invokeOnSucces(ChannelHandlerContext ctx, WebSocketUpgradeHandler h) { + if (!onSuccesInvoked.getAndSet(true)) { + try { + h.onSuccess(new NettyWebSocket(ctx.getChannel())); + } catch (Exception ex) { + NettyAsyncHttpProvider.this.log.warn("onSuccess unexexpected exception", ex); + } + } + } // @Override public void handle(ChannelHandlerContext ctx, MessageEvent e) throws Exception { @@ -2298,7 +2319,8 @@ public void handle(ChannelHandlerContext ctx, MessageEvent e) throws Exception { s = new ResponseStatus(future.getURI(), response, NettyAsyncHttpProvider.this); final boolean statusReceived = h.onStatusReceived(s) == STATE.UPGRADE; - if (!validStatus || !validUpgrade || !validConnection || !statusReceived) { + final boolean headeOK = h.onHeadersReceived(responseHeaders) == STATE.CONTINUE; + if (!headeOK || !validStatus || !validUpgrade || !validConnection || !statusReceived) { abort(future, new IOException("Invalid handshake response")); return; } @@ -2311,25 +2333,12 @@ public void handle(ChannelHandlerContext ctx, MessageEvent e) throws Exception { ctx.getPipeline().replace("http-encoder", "ws-encoder", new WebSocket08FrameEncoder(true)); ctx.getPipeline().get(HttpResponseDecoder.class).replace("ws-decoder", new WebSocket08FrameDecoder(false, false)); - if (h.onHeadersReceived(responseHeaders) == STATE.CONTINUE) { - try { - h.onSuccess(new NettyWebSocket(ctx.getChannel())); - } catch (Exception ex) { - NettyAsyncHttpProvider.this.log.warn("onSuccess unexexpected exception", ex); - } finally { - /** - * A websocket message may always be included with the handshake response. As soon as we replace - * the ws-decoder, this class can be called and we are still inside the onSuccess processing - * causing invalid state. - */ - onSuccessLatch.countDown(); - } - } + + invokeOnSucces(ctx, h); future.done(null); } else if (e.getMessage() instanceof WebSocketFrame) { - // Give a chance to the onSuccess to complete before processing message. - onSuccessLatch.await(); + invokeOnSucces(ctx, h); final WebSocketFrame frame = (WebSocketFrame) e.getMessage(); From 52fdf69449fabd7a052955a123426337896c8d40 Mon Sep 17 00:00:00 2001 From: jfarcand Date: Fri, 14 Jun 2013 11:06:33 -0400 Subject: [PATCH 165/264] Avoid interrupting --- .../ning/http/client/providers/netty/NettyResponseFuture.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyResponseFuture.java b/src/main/java/com/ning/http/client/providers/netty/NettyResponseFuture.java index fff32feca8..8cf16dc83e 100755 --- a/src/main/java/com/ning/http/client/providers/netty/NettyResponseFuture.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyResponseFuture.java @@ -217,7 +217,7 @@ public V get() throws InterruptedException, ExecutionException { void cancelReaper() { if (reaperFuture != null) { - reaperFuture.cancel(true); + reaperFuture.cancel(false); } } From dc14f2f6681dafb9b2fcb7d9464d183b2d9ed2a6 Mon Sep 17 00:00:00 2001 From: jfarcand Date: Fri, 14 Jun 2013 11:07:44 -0400 Subject: [PATCH 166/264] Better fix for websocket handling --- .../http/client/providers/netty/NettyAsyncHttpProvider.java | 3 +-- .../ning/http/client/websocket/WebSocketUpgradeHandler.java | 5 +++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java index 097cf5d389..b2f540e436 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java @@ -2255,11 +2255,10 @@ private final class WebSocketProtocol implements Protocol { private static final byte OPCODE_BINARY = 0x2; private static final byte OPCODE_UNKNOWN = -1; protected byte pendingOpcode = OPCODE_UNKNOWN; - private final AtomicBoolean onSuccesInvoked = new AtomicBoolean(); // We don't need to synchronize as replacing the "ws-decoder" will process using the same thread. private void invokeOnSucces(ChannelHandlerContext ctx, WebSocketUpgradeHandler h) { - if (!onSuccesInvoked.getAndSet(true)) { + if (!h.touchSuccess()) { try { h.onSuccess(new NettyWebSocket(ctx.getChannel())); } catch (Exception ex) { diff --git a/src/main/java/com/ning/http/client/websocket/WebSocketUpgradeHandler.java b/src/main/java/com/ning/http/client/websocket/WebSocketUpgradeHandler.java index 64bf8b32e1..b31f1bff79 100644 --- a/src/main/java/com/ning/http/client/websocket/WebSocketUpgradeHandler.java +++ b/src/main/java/com/ning/http/client/websocket/WebSocketUpgradeHandler.java @@ -32,6 +32,7 @@ public class WebSocketUpgradeHandler implements UpgradeHandler, Async private final long maxByteSize; private final long maxTextSize; private final AtomicBoolean ok = new AtomicBoolean(false); + private final AtomicBoolean onSuccessCalled = new AtomicBoolean(false); protected WebSocketUpgradeHandler(Builder b) { l = b.l; @@ -48,6 +49,10 @@ public void onThrowable(Throwable t) { onFailure(t); } + public boolean touchSuccess(){ + return onSuccessCalled.getAndSet(true); + } + /** * {@inheritDoc} */ From d07498bf77e0aa1c2843c574480c475f9b99dc9d Mon Sep 17 00:00:00 2001 From: jfarcand Date: Fri, 14 Jun 2013 18:10:11 -0400 Subject: [PATCH 167/264] Fix regression: allow re-use of a WebSocketHandler --- .../http/client/providers/netty/NettyAsyncHttpProvider.java | 3 +++ .../ning/http/client/websocket/WebSocketUpgradeHandler.java | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java index b2f540e436..d247bb82e5 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java @@ -2387,6 +2387,8 @@ public void setContent(ChannelBuffer content) { } catch (Throwable t) { // Swallow any exception that may comes from a Netty version released before 3.4.0 log.trace("", t); + } finally { + h.resetSuccess(); } } } else { @@ -2430,6 +2432,7 @@ public void onClose(ChannelHandlerContext ctx, ChannelStateEvent e) { NettyResponseFuture nettyResponse = NettyResponseFuture.class.cast(ctx.getAttachment()); WebSocketUpgradeHandler h = WebSocketUpgradeHandler.class.cast(nettyResponse.getAsyncHandler()); NettyWebSocket webSocket = NettyWebSocket.class.cast(h.onCompleted()); + h.resetSuccess(); if (ctx.getAttachment() == null || !DiscardEvent.class.isAssignableFrom(ctx.getAttachment().getClass())) webSocket.close(1006, "Connection was closed abnormally (that is, with no close frame being sent)."); diff --git a/src/main/java/com/ning/http/client/websocket/WebSocketUpgradeHandler.java b/src/main/java/com/ning/http/client/websocket/WebSocketUpgradeHandler.java index b31f1bff79..16704bedef 100644 --- a/src/main/java/com/ning/http/client/websocket/WebSocketUpgradeHandler.java +++ b/src/main/java/com/ning/http/client/websocket/WebSocketUpgradeHandler.java @@ -53,6 +53,10 @@ public boolean touchSuccess(){ return onSuccessCalled.getAndSet(true); } + public void resetSuccess() { + onSuccessCalled.set(false); + } + /** * {@inheritDoc} */ From f26c33c61405fbc5aa0dd50add11160b6f992776 Mon Sep 17 00:00:00 2001 From: Ryan Lubke Date: Mon, 17 Jun 2013 00:52:46 -0700 Subject: [PATCH 168/264] Fix copyright. --- .../websocket/DefaultWebSocketListener.java | 44 ++++--------------- 1 file changed, 9 insertions(+), 35 deletions(-) diff --git a/src/main/java/com/ning/http/client/websocket/DefaultWebSocketListener.java b/src/main/java/com/ning/http/client/websocket/DefaultWebSocketListener.java index 4db626b0d6..767b89df33 100644 --- a/src/main/java/com/ning/http/client/websocket/DefaultWebSocketListener.java +++ b/src/main/java/com/ning/http/client/websocket/DefaultWebSocketListener.java @@ -1,42 +1,16 @@ /* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * Copyright (c) 2012-2013 Sonatype, Inc. All rights reserved. * - * Copyright (c) 2012 Oracle and/or its affiliates. All rights reserved. + * This program is licensed to you under the Apache License Version 2.0, + * and you may not use this file except in compliance with the Apache License Version 2.0. + * You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0. * - * The contents of this file are subject to the terms of either the GNU - * General Public License Version 2 only ("GPL") or the Common Development - * and Distribution License("CDDL") (collectively, the "License"). You - * may not use this file except in compliance with the License. You can - * obtain a copy of the License at - * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html - * or packager/legal/LICENSE.txt. See the License for the specific - * language governing permissions and limitations under the License. - * - * When distributing the software, include this License Header Notice in each - * file and include the License file at packager/legal/LICENSE.txt. - * - * GPL Classpath Exception: - * Oracle designates this particular file as subject to the "Classpath" - * exception as provided by Oracle in the GPL Version 2 section of the License - * file that accompanied this code. - * - * Modifications: - * If applicable, add the following below the License Header, with the fields - * enclosed by brackets [] replaced by your own identifying information: - * "Portions Copyright [year] [name of copyright owner]" - * - * Contributor(s): - * If you wish your version of this file to be governed by only the CDDL or - * only the GPL Version 2, indicate your decision by adding "[Contributor] - * elects to include this software in this distribution under the [CDDL or GPL - * Version 2] license." If you don't indicate a single choice of license, a - * recipient has the option to distribute your version of this file under - * either the CDDL, the GPL Version 2 or to extend the choice of license to - * its licensees as provided above. However, if you add GPL Version 2 code - * and therefore, elected the GPL Version 2 license, then the option applies - * only if the new code is made subject to such option by the copyright - * holder. + * Unless required by applicable law or agreed to in writing, + * software distributed under the Apache License Version 2.0 is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under. */ + package com.ning.http.client.websocket; /** From 8bd3516c4c497416aa0cb6906cb79b8655f1125a Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 17 Jun 2013 18:32:38 +0200 Subject: [PATCH 169/264] NettyAsyncHttpProvider shouldn't use FluentCaseInsensitiveStringsMap.getKeys that uselessly creates a new Map, close #326 --- .../providers/netty/NettyAsyncHttpProvider.java | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java index d247bb82e5..44d3eeb20d 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java @@ -643,13 +643,11 @@ else if (uri.getRawQuery() != null) } if (!m.equals(HttpMethod.CONNECT)) { - FluentCaseInsensitiveStringsMap h = request.getHeaders(); - if (h != null) { - for (String name : h.keySet()) { - if (!"host".equalsIgnoreCase(name)) { - for (String value : h.get(name)) { - nettyRequest.addHeader(name, value); - } + for (Entry> header : request.getHeaders()) { + String name = header.getKey(); + if (!HttpHeaders.Names.HOST.equalsIgnoreCase(name)) { + for (String value : header.getValue()) { + nettyRequest.addHeader(name, value); } } } From c3ea902c078caf176a6970c2451111f7e16d6bb3 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 17 Jun 2013 18:32:46 +0200 Subject: [PATCH 170/264] Minor clean up --- .../java/com/ning/http/client/FluentStringsMap.java | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/ning/http/client/FluentStringsMap.java b/src/main/java/com/ning/http/client/FluentStringsMap.java index b540b70896..22a2ccb6bb 100644 --- a/src/main/java/com/ning/http/client/FluentStringsMap.java +++ b/src/main/java/com/ning/http/client/FluentStringsMap.java @@ -78,14 +78,12 @@ public FluentStringsMap add(String key, String... values) { * @return This object */ public FluentStringsMap add(String key, Collection values) { - if (key != null) { - if (isNonEmpty(values)) { - List curValues = this.values.get(key); + if (key != null && isNonEmpty(values)) { + List curValues = this.values.get(key); - if (curValues == null) { - curValues = new ArrayList(); - this.values.put(key, curValues); - } + if (curValues == null) { + this.values.put(key, new ArrayList(values)); + } else { curValues.addAll(values); } } From 18f5805a57a0ab9ff89c5c8e7e064ecadbc7bf8c Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 19 Jun 2013 18:23:18 +0200 Subject: [PATCH 171/264] typo --- .../http/client/providers/netty/NettyAsyncHttpProvider.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java index 44d3eeb20d..6acfa97ddc 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java @@ -2316,8 +2316,8 @@ public void handle(ChannelHandlerContext ctx, MessageEvent e) throws Exception { s = new ResponseStatus(future.getURI(), response, NettyAsyncHttpProvider.this); final boolean statusReceived = h.onStatusReceived(s) == STATE.UPGRADE; - final boolean headeOK = h.onHeadersReceived(responseHeaders) == STATE.CONTINUE; - if (!headeOK || !validStatus || !validUpgrade || !validConnection || !statusReceived) { + final boolean headerOK = h.onHeadersReceived(responseHeaders) == STATE.CONTINUE; + if (!headerOK || !validStatus || !validUpgrade || !validConnection || !statusReceived) { abort(future, new IOException("Invalid handshake response")); return; } From b65ef397d473acab8f9b050caddc919591990e36 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 19 Jun 2013 18:23:43 +0200 Subject: [PATCH 172/264] Scan headers efficiently --- .../client/providers/netty/ResponseHeaders.java | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/ResponseHeaders.java b/src/main/java/com/ning/http/client/providers/netty/ResponseHeaders.java index 0db2b32334..3e552c9da8 100644 --- a/src/main/java/com/ning/http/client/providers/netty/ResponseHeaders.java +++ b/src/main/java/com/ning/http/client/providers/netty/ResponseHeaders.java @@ -22,6 +22,7 @@ import org.jboss.netty.handler.codec.http.HttpResponse; import java.net.URI; +import java.util.Map; /** * A class that represent the HTTP headers. @@ -48,17 +49,13 @@ public ResponseHeaders(URI uri, HttpResponse response, AsyncHttpProvider provide private FluentCaseInsensitiveStringsMap computerHeaders() { FluentCaseInsensitiveStringsMap h = new FluentCaseInsensitiveStringsMap(); - for (String s : response.getHeaderNames()) { - for (String header : response.getHeaders(s)) { - h.add(s, header); - } + for (Map.Entry header: response.getHeaders()) { + h.add(header.getKey(), header.getValue()); } - if (trailingHeaders != null && trailingHeaders.getHeaderNames().size() > 0) { - for (final String s : trailingHeaders.getHeaderNames()) { - for (String header : response.getHeaders(s)) { - h.add(s, header); - } + if (trailingHeaders != null) { + for (Map.Entry header: trailingHeaders.getHeaders()) { + h.add(header.getKey(), header.getValue()); } } From 37bf6647ec56c521e0c543ca80c047e9db07fc70 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 20 Jun 2013 05:39:24 +0200 Subject: [PATCH 173/264] Normalize redirect URI, close #329 --- src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java index acb2317687..e4f555a419 100644 --- a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java +++ b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java @@ -273,7 +273,7 @@ public final static URI getRedirectUri(URI uri, String location) { + ", must be equal (ignoring case) to 'ws, 'wss', 'http', or 'https'"); } - return redirectUri; + return redirectUri.normalize(); } public final static int getPort(URI uri) { From 9d7e6c9d56e8ad86902cb639d1496a04fc086cd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Deleuze?= Date: Thu, 20 Jun 2013 10:11:14 +0200 Subject: [PATCH 174/264] Fix useRelativeURIsWithSSLProxies initialization in AsyncHttpClientConfig constructor --- src/main/java/com/ning/http/client/AsyncHttpClientConfig.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java b/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java index ef96371ad5..5227c7ca6c 100644 --- a/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java @@ -154,6 +154,7 @@ private AsyncHttpClientConfig(int maxTotalConnections, this.hostnameVerifier = hostnameVerifier; this.ioThreadMultiplier = ioThreadMultiplier; this.strict302Handling = strict302Handling; + this.useRelativeURIsWithSSLProxies = useRelativeURIsWithSSLProxies; this.rfc6265CookieEncoding = rfc6265CookieEncoding; if (applicationThreadPool == null) { From 1684c8db97d24e3fc0d6120bf121c0d1818324a8 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 21 Jun 2013 11:37:56 +0200 Subject: [PATCH 175/264] Don't compute regular host if there's a virtual one --- .../client/providers/netty/NettyAsyncHttpProvider.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java index 6acfa97ddc..8b3f201488 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java @@ -602,10 +602,12 @@ private static SpnegoEngine getSpnegoEngine() { private static HttpRequest construct(AsyncHttpClientConfig config, Request request, HttpMethod m, URI uri, ChannelBuffer buffer, ProxyServer proxyServer) throws IOException { - String host = AsyncHttpProviderUtils.getHost(uri); + String host = null; if (request.getVirtualHost() != null) { host = request.getVirtualHost(); + } else { + host = AsyncHttpProviderUtils.getHost(uri); } HttpRequest nettyRequest; @@ -631,9 +633,7 @@ else if (uri.getRawQuery() != null) } if (host != null) { - if (uri.getPort() == -1) { - nettyRequest.setHeader(HttpHeaders.Names.HOST, host); - } else if (request.getVirtualHost() != null) { + if (request.getVirtualHost() != null || uri.getPort() == -1) { nettyRequest.setHeader(HttpHeaders.Names.HOST, host); } else { nettyRequest.setHeader(HttpHeaders.Names.HOST, host + ":" + uri.getPort()); From a5515b50ee4b103842e01fcea2c8581f554a2e58 Mon Sep 17 00:00:00 2001 From: Ryan Lubke Date: Tue, 2 Jul 2013 11:53:27 -0700 Subject: [PATCH 176/264] Fix secure pool logic. --- .../http/client/providers/grizzly/GrizzlyConnectionsPool.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyConnectionsPool.java b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyConnectionsPool.java index 9f93fd364f..237fa9bd3e 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyConnectionsPool.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyConnectionsPool.java @@ -98,7 +98,7 @@ public void onClosed(Connection connection, Connection.CloseType closeType) thro */ public boolean offer(String uri, Connection connection) { - if (!cacheSSLConnections && isSecure(uri)) { + if (isSecure(uri) && !cacheSSLConnections) { return false; } From 48a65d49c117707030e3a7a11714a53b333cc06a Mon Sep 17 00:00:00 2001 From: Martin Korinth Date: Tue, 2 Jul 2013 16:07:16 +0200 Subject: [PATCH 177/264] Fixed a bug using proxies with the JDK API, found by DanielAdolfsson --- .../http/client/providers/jdk/JDKAsyncHttpProvider.java | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/jdk/JDKAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/jdk/JDKAsyncHttpProvider.java index 37b3cd7880..ccca62a363 100644 --- a/src/main/java/com/ning/http/client/providers/jdk/JDKAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/jdk/JDKAsyncHttpProvider.java @@ -175,12 +175,8 @@ private HttpURLConnection createUrlConnection(Request request) throws IOExceptio } } - HttpURLConnection urlConnection = null; - if (proxy == null) { - urlConnection = (HttpURLConnection) request.getURI().toURL().openConnection(Proxy.NO_PROXY); - } else { - urlConnection = (HttpURLConnection) proxyServer.getURI().toURL().openConnection(proxy); - } + HttpURLConnection urlConnection = (HttpURLConnection) + request.getURI().toURL().openConnection(proxy == null ? Proxy.NO_PROXY : proxy); if (request.getUrl().startsWith("https")) { HttpsURLConnection secure = (HttpsURLConnection) urlConnection; From 3ef7b83d9db65020c2d1bf62616178d3dbf07bbb Mon Sep 17 00:00:00 2001 From: jfarcand Date: Wed, 3 Jul 2013 09:12:07 -0400 Subject: [PATCH 178/264] [maven-release-plugin] prepare release async-http-client-1.7.18 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 1d5800f248..125b412aa8 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.7.18-SNAPSHOT + 1.7.18 jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From a8e57e5569633a57c2e2b193e190a11c8e98e196 Mon Sep 17 00:00:00 2001 From: jfarcand Date: Wed, 3 Jul 2013 09:12:11 -0400 Subject: [PATCH 179/264] [maven-release-plugin] prepare for next development iteration --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 125b412aa8..1f541c047a 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.7.18 + 1.7.19-SNAPSHOT jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From 91788b41f2f79a9f561e8d6dff911a3974c5440e Mon Sep 17 00:00:00 2001 From: Liu Kumai Date: Fri, 5 Jul 2013 13:06:20 +0900 Subject: [PATCH 180/264] GrizzlyResponse#getResponseBodyAsBytes doesn't return original content. --- .../http/client/providers/grizzly/GrizzlyResponse.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponse.java b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponse.java index 5984d03174..193718a333 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponse.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponse.java @@ -172,9 +172,11 @@ public String getResponseBody() throws IOException { * {@inheritDoc} */ public byte[] getResponseBodyAsBytes() throws IOException { - - return getResponseBody().getBytes(); - + final byte[] responseBodyBytes = new byte[responseBody.remaining()]; + final int origPos = responseBody.position(); + responseBody.get(responseBodyBytes); + responseBody.position(origPos); + return responseBodyBytes; } public ByteBuffer getResponseBodyAsByteBuffer() throws IOException { From 85d692bec16203fc82e0cdb4a566a55d47f2b8cc Mon Sep 17 00:00:00 2001 From: Ryan Lubke Date: Fri, 5 Jul 2013 11:03:31 -0700 Subject: [PATCH 181/264] Add constructor to allow decoupling of the AHC config. --- .../grizzly/GrizzlyConnectionsPool.java | 57 ++++++++++++++----- 1 file changed, 42 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyConnectionsPool.java b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyConnectionsPool.java index 237fa9bd3e..457dc58bcf 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyConnectionsPool.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyConnectionsPool.java @@ -59,12 +59,48 @@ public class GrizzlyConnectionsPool implements ConnectionsPool Date: Fri, 5 Jul 2013 11:04:46 -0700 Subject: [PATCH 182/264] Quick fix to secure check. --- .../http/client/providers/grizzly/GrizzlyConnectionsPool.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyConnectionsPool.java b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyConnectionsPool.java index 457dc58bcf..7db2841102 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyConnectionsPool.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyConnectionsPool.java @@ -261,7 +261,7 @@ public void destroy() { private boolean isSecure(String uri) { - return (uri.charAt(0) == 'h' && uri.charAt(4) == 's'); + return (uri.startsWith("https") || uri.startsWith("wss")); } From ec19cdb8719263c172139c068199bb850d73f778 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Sat, 6 Jul 2013 22:23:47 +0200 Subject: [PATCH 183/264] DelayedExecutor has to be public in order to use new GrizzlyConnectionsPool contructor --- .../client/providers/grizzly/GrizzlyConnectionsPool.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyConnectionsPool.java b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyConnectionsPool.java index 7db2841102..50e1a93969 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyConnectionsPool.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyConnectionsPool.java @@ -269,7 +269,7 @@ private boolean isSecure(String uri) { // ---------------------------------------------------------- Nested Classes - private static final class DelayedExecutor { + public static final class DelayedExecutor { public final static long UNSET_TIMEOUT = -1; private final ExecutorService threadPool; @@ -284,14 +284,14 @@ private static final class DelayedExecutor { // -------------------------------------------------------- Constructors - private DelayedExecutor(final ExecutorService threadPool) { + public DelayedExecutor(final ExecutorService threadPool) { this(threadPool, 1000, TimeUnit.MILLISECONDS); } // ----------------------------------------------------- Private Methods - private DelayedExecutor(final ExecutorService threadPool, + public DelayedExecutor(final ExecutorService threadPool, final long checkInterval, final TimeUnit timeunit) { this.threadPool = threadPool; From f4484b6f647943841c738555487c25b9c29520db Mon Sep 17 00:00:00 2001 From: Marc Arens Date: Thu, 18 Jul 2013 15:25:12 +0200 Subject: [PATCH 184/264] Prevent NPE when trying to access cookies --- .../java/com/ning/http/client/providers/jdk/JDKResponse.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/ning/http/client/providers/jdk/JDKResponse.java b/src/main/java/com/ning/http/client/providers/jdk/JDKResponse.java index 8dda720d8b..b4aa4fe84b 100644 --- a/src/main/java/com/ning/http/client/providers/jdk/JDKResponse.java +++ b/src/main/java/com/ning/http/client/providers/jdk/JDKResponse.java @@ -170,7 +170,7 @@ public List getCookies() { if (headers == null) { return Collections.emptyList(); } - if (cookies.isEmpty()) { + if (cookies == null || cookies.isEmpty()) { List localCookies = new ArrayList(); for (Map.Entry> header : headers.getHeaders().entrySet()) { if (header.getKey().equalsIgnoreCase("Set-Cookie")) { From 7ffe9863ecf3547f471b74eebd200aa08dfe73ae Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 22 Jul 2013 12:26:57 +0200 Subject: [PATCH 185/264] Minor clean up, use constants --- .../netty/NettyAsyncHttpProvider.java | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java index 8b3f201488..e44e4bb2bb 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java @@ -533,8 +533,8 @@ public void operationComplete(ChannelFuture cf) { * TODO: AHC-78: SSL + zero copy isn't supported by the MultiPart class and pretty complex to implements. */ if (future.getRequest().getParts() != null) { - String contentType = future.getNettyRequest().getHeader("Content-Type"); - String length = future.getNettyRequest().getHeader("Content-Length"); + String contentType = future.getNettyRequest().getHeader(HttpHeaders.Names.CONTENT_TYPE); + String length = future.getNettyRequest().getHeader(HttpHeaders.Names.CONTENT_LENGTH); body = new MultipartBody(future.getRequest().getParts(), contentType, length); } @@ -627,9 +627,9 @@ else if (uri.getRawQuery() != null) if (webSocket) { nettyRequest.addHeader(HttpHeaders.Names.UPGRADE, HttpHeaders.Values.WEBSOCKET); nettyRequest.addHeader(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.UPGRADE); - nettyRequest.addHeader("Origin", "http://" + uri.getHost() + ":" + uri.getPort()); + nettyRequest.addHeader(HttpHeaders.Names.ORIGIN, "http://" + uri.getHost() + ":" + uri.getPort()); nettyRequest.addHeader(WEBSOCKET_KEY, WebSocketUtil.getKey()); - nettyRequest.addHeader("Sec-WebSocket-Version", "13"); + nettyRequest.addHeader(HttpHeaders.Names.SEC_WEBSOCKET_VERSION, "13"); } if (host != null) { @@ -747,16 +747,16 @@ else if (uri.getRawQuery() != null) } // Add default accept headers. - if (request.getHeaders().getFirstValue("Accept") == null) { + if (request.getHeaders().getFirstValue(HttpHeaders.Names.ACCEPT) == null) { nettyRequest.setHeader(HttpHeaders.Names.ACCEPT, "*/*"); } - if (request.getHeaders().getFirstValue("User-Agent") != null) { - nettyRequest.setHeader("User-Agent", request.getHeaders().getFirstValue("User-Agent")); + if (request.getHeaders().getFirstValue(HttpHeaders.Names.USER_AGENT) != null) { + nettyRequest.setHeader(HttpHeaders.Names.USER_AGENT, request.getHeaders().getFirstValue(HttpHeaders.Names.USER_AGENT)); } else if (config.getUserAgent() != null) { - nettyRequest.setHeader("User-Agent", config.getUserAgent()); + nettyRequest.setHeader(HttpHeaders.Names.USER_AGENT, config.getUserAgent()); } else { - nettyRequest.setHeader("User-Agent", AsyncHttpProviderUtils.constructUserAgent(NettyAsyncHttpProvider.class)); + nettyRequest.setHeader(HttpHeaders.Names.USER_AGENT, AsyncHttpProviderUtils.constructUserAgent(NettyAsyncHttpProvider.class)); } if (!m.equals(HttpMethod.CONNECT)) { @@ -803,7 +803,7 @@ else if (uri.getRawQuery() != null) nettyRequest.setContent(ChannelBuffers.wrappedBuffer(sb.toString().getBytes(bodyCharset))); if (!request.getHeaders().containsKey(HttpHeaders.Names.CONTENT_TYPE)) { - nettyRequest.setHeader(HttpHeaders.Names.CONTENT_TYPE, "application/x-www-form-urlencoded"); + nettyRequest.setHeader(HttpHeaders.Names.CONTENT_TYPE, HttpHeaders.Values.APPLICATION_X_WWW_FORM_URLENCODED); } } else if (request.getParts() != null) { @@ -1640,7 +1640,7 @@ public static NettyResponseFuture newFuture(URI uri, Request request, Asy request.getConnectionPoolKeyStrategy(),// proxyServer); - if (request.getHeaders().getFirstValue("Expect") != null && request.getHeaders().getFirstValue("Expect").equalsIgnoreCase("100-Continue")) { + if (request.getHeaders().getFirstValue(HttpHeaders.Names.EXPECT) != null && request.getHeaders().getFirstValue(HttpHeaders.Names.EXPECT).equalsIgnoreCase(HttpHeaders.Values.CONTINUE)) { f.getAndSetWriteBody(false); } return f; @@ -2051,7 +2051,7 @@ public void handle(final ChannelHandlerContext ctx, final MessageEvent e) throws int statusCode = response.getStatus().getCode(); String ka = response.getHeader(HttpHeaders.Names.CONNECTION); - future.setKeepAlive(ka == null || ka.toLowerCase().equals("keep-alive")); + future.setKeepAlive(ka == null || ka.equalsIgnoreCase(HttpHeaders.Values.KEEP_ALIVE)); List wwwAuth = getAuthorizationToken(response.getHeaders(), HttpHeaders.Names.WWW_AUTHENTICATE); Realm realm = request.getRealm() != null ? request.getRealm() : config.getRealm(); From abfe8c7a137b25747058ba569e574fd8c387885c Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 22 Jul 2013 12:40:01 +0200 Subject: [PATCH 186/264] Remove useless multiple getFirstValue calls, close #341 --- .../client/providers/netty/NettyAsyncHttpProvider.java | 10 ++++++---- .../http/client/resumable/ResumableAsyncHandler.java | 5 +++-- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java index e44e4bb2bb..cb0bd72f9c 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java @@ -747,12 +747,13 @@ else if (uri.getRawQuery() != null) } // Add default accept headers. - if (request.getHeaders().getFirstValue(HttpHeaders.Names.ACCEPT) == null) { + if (!request.getHeaders().containsKey(HttpHeaders.Names.ACCEPT)) { nettyRequest.setHeader(HttpHeaders.Names.ACCEPT, "*/*"); } - if (request.getHeaders().getFirstValue(HttpHeaders.Names.USER_AGENT) != null) { - nettyRequest.setHeader(HttpHeaders.Names.USER_AGENT, request.getHeaders().getFirstValue(HttpHeaders.Names.USER_AGENT)); + String userAgentHeader = request.getHeaders().getFirstValue(HttpHeaders.Names.USER_AGENT); + if (userAgentHeader != null) { + nettyRequest.setHeader(HttpHeaders.Names.USER_AGENT, userAgentHeader); } else if (config.getUserAgent() != null) { nettyRequest.setHeader(HttpHeaders.Names.USER_AGENT, config.getUserAgent()); } else { @@ -1640,7 +1641,8 @@ public static NettyResponseFuture newFuture(URI uri, Request request, Asy request.getConnectionPoolKeyStrategy(),// proxyServer); - if (request.getHeaders().getFirstValue(HttpHeaders.Names.EXPECT) != null && request.getHeaders().getFirstValue(HttpHeaders.Names.EXPECT).equalsIgnoreCase(HttpHeaders.Values.CONTINUE)) { + String expectHeader = request.getHeaders().getFirstValue(HttpHeaders.Names.EXPECT); + if (expectHeader != null && expectHeader.equalsIgnoreCase(HttpHeaders.Values.CONTINUE)) { f.getAndSetWriteBody(false); } return f; diff --git a/src/main/java/com/ning/http/client/resumable/ResumableAsyncHandler.java b/src/main/java/com/ning/http/client/resumable/ResumableAsyncHandler.java index 51d60ccf99..53ebec5cdb 100644 --- a/src/main/java/com/ning/http/client/resumable/ResumableAsyncHandler.java +++ b/src/main/java/com/ning/http/client/resumable/ResumableAsyncHandler.java @@ -177,8 +177,9 @@ public T onCompleted() throws Exception { /* @Override */ public AsyncHandler.STATE onHeadersReceived(HttpResponseHeaders headers) throws Exception { responseBuilder.accumulate(headers); - if (headers.getHeaders().getFirstValue("Content-Length") != null) { - contentLength = Integer.valueOf(headers.getHeaders().getFirstValue("Content-Length")); + String contentLengthHeader = headers.getHeaders().getFirstValue("Content-Length"); + if (contentLengthHeader != null) { + contentLength = Integer.valueOf(contentLengthHeader); if (contentLength == null || contentLength == -1) { return AsyncHandler.STATE.ABORT; } From 03e31ef7ba1a098039f9f72b26d617d39fa84ad8 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 22 Jul 2013 14:12:21 +0200 Subject: [PATCH 187/264] Fix Netty provider NTLM type 2 message handling, close #339 --- .../netty/NettyAsyncHttpProvider.java | 52 +++++++++++-------- 1 file changed, 31 insertions(+), 21 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java index cb0bd72f9c..f8a3320123 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java @@ -198,6 +198,10 @@ public boolean remove(Object o) { private final Protocol httpProtocol = new HttpProtocol(); private final Protocol webSocketProtocol = new WebSocketProtocol(); + private static boolean isNTLM(List auth) { + return isNonEmpty(auth) && auth.get(0).startsWith("NTLM"); + } + public NettyAsyncHttpProvider(AsyncHttpClientConfig config) { if (config.getAsyncHttpProviderConfig() != null && NettyAsyncHttpProviderConfig.class.isAssignableFrom(config.getAsyncHttpProviderConfig().getClass())) { @@ -657,7 +661,7 @@ else if (uri.getRawQuery() != null) } } else { List auth = request.getHeaders().get(HttpHeaders.Names.PROXY_AUTHORIZATION); - if (auth != null && auth.size() > 0 && auth.get(0).startsWith("NTLM")) { + if (isNTLM(auth)) { nettyRequest.addHeader(HttpHeaders.Names.PROXY_AUTHORIZATION, auth.get(0)); } } @@ -727,10 +731,10 @@ else if (uri.getRawQuery() != null) } if (proxyServer.getPrincipal() != null) { - if (proxyServer.getNtlmDomain() != null && proxyServer.getNtlmDomain().length() > 0) { + if (isNonEmpty(proxyServer.getNtlmDomain())) { List auth = request.getHeaders().get(HttpHeaders.Names.PROXY_AUTHORIZATION); - if (!(auth != null && auth.size() > 0 && auth.get(0).startsWith("NTLM"))) { + if (!isNTLM(auth)) { try { String msg = ntlmEngine.generateType1Msg(proxyServer.getNtlmDomain(), proxyServer.getHost()); nettyRequest.setHeader(HttpHeaders.Names.PROXY_AUTHORIZATION, "NTLM " + msg); @@ -1173,7 +1177,7 @@ private Realm kerberosChallenge(List proxyAuth, Request request, ProxySe } return realmBuilder.setUri(uri.getRawPath()).setMethodName(request.getMethod()).setScheme(Realm.AuthScheme.KERBEROS).build(); } catch (Throwable throwable) { - if (proxyAuth.contains("NTLM")) { + if (isNTLM(proxyAuth)) { return ntlmChallenge(proxyAuth, request, proxyServer, headers, realm, future); } abort(future, throwable); @@ -1181,6 +1185,23 @@ private Realm kerberosChallenge(List proxyAuth, Request request, ProxySe } } + private void addType3NTLMAuthorizationHeader( + List auth, + FluentCaseInsensitiveStringsMap headers, + String username, + String password, + String domain, + String workstation) throws NTLMEngineException { + headers.remove(HttpHeaders.Names.AUTHORIZATION); + + if (isNTLM(auth)) { + String serverChallenge = auth.get(0).trim().substring("NTLM ".length()); + String challengeHeader = ntlmEngine.generateType3Msg(username, password, domain, workstation, serverChallenge); + + headers.add(HttpHeaders.Names.AUTHORIZATION, "NTLM " + challengeHeader); + } + } + private Realm ntlmChallenge(List wwwAuth, Request request, ProxyServer proxyServer, FluentCaseInsensitiveStringsMap headers, Realm realm, NettyResponseFuture future) throws NTLMEngineException { boolean useRealm = (proxyServer == null && realm != null); @@ -1199,14 +1220,7 @@ private Realm ntlmChallenge(List wwwAuth, Request request, ProxyServer p newRealm = new Realm.RealmBuilder().clone(realm).setScheme(realm.getAuthScheme()).setUri(uri.getRawPath()).setMethodName(request.getMethod()).setNtlmMessageType2Received(true).build(); future.getAndSetAuth(false); } else { - headers.remove(HttpHeaders.Names.AUTHORIZATION); - - if (wwwAuth.get(0).startsWith("NTLM ")) { - String serverChallenge = wwwAuth.get(0).trim().substring("NTLM ".length()); - String challengeHeader = ntlmEngine.generateType3Msg(principal, password, ntlmDomain, ntlmHost, serverChallenge); - - headers.add(HttpHeaders.Names.AUTHORIZATION, "NTLM " + challengeHeader); - } + addType3NTLMAuthorizationHeader(wwwAuth, headers, principal, password, ntlmDomain, ntlmHost); Realm.RealmBuilder realmBuilder; Realm.AuthScheme authScheme; @@ -1225,14 +1239,10 @@ private Realm ntlmChallenge(List wwwAuth, Request request, ProxyServer p private Realm ntlmProxyChallenge(List wwwAuth, Request request, ProxyServer proxyServer, FluentCaseInsensitiveStringsMap headers, Realm realm, NettyResponseFuture future) throws NTLMEngineException { future.getAndSetAuth(false); - headers.remove(HttpHeaders.Names.PROXY_AUTHORIZATION); - - if (wwwAuth.get(0).startsWith("NTLM ")) { - String serverChallenge = wwwAuth.get(0).trim().substring("NTLM ".length()); - String challengeHeader = ntlmEngine.generateType3Msg(proxyServer.getPrincipal(), proxyServer.getPassword(), proxyServer.getNtlmDomain(), proxyServer.getHost(), serverChallenge); - headers.add(HttpHeaders.Names.PROXY_AUTHORIZATION, "NTLM " + challengeHeader); - } + + addType3NTLMAuthorizationHeader(wwwAuth, headers, proxyServer.getPrincipal(), proxyServer.getPassword(), proxyServer.getNtlmDomain(), proxyServer.getHost()); Realm newRealm; + Realm.RealmBuilder realmBuilder; if (realm != null) { realmBuilder = new Realm.RealmBuilder().clone(realm); @@ -2095,7 +2105,7 @@ public void handle(final ChannelHandlerContext ctx, final MessageEvent e) throws future.setState(NettyResponseFuture.STATE.NEW); // NTLM - if (!wwwAuth.contains("Kerberos") && (wwwAuth.contains("NTLM") || (wwwAuth.contains("Negotiate")))) { + if (!wwwAuth.contains("Kerberos") && (isNTLM(wwwAuth) || (wwwAuth.contains("Negotiate")))) { newRealm = ntlmChallenge(wwwAuth, request, proxyServer, headers, realm, future); // SPNEGO KERBEROS } else if (wwwAuth.contains("Negotiate")) { @@ -2146,7 +2156,7 @@ public Object call() throws Exception { future.setState(NettyResponseFuture.STATE.NEW); - if (!proxyAuth.contains("Kerberos") && (proxyAuth.get(0).contains("NTLM") || (proxyAuth.contains("Negotiate")))) { + if (!proxyAuth.contains("Kerberos") && (isNTLM(proxyAuth) || (proxyAuth.contains("Negotiate")))) { newRealm = ntlmProxyChallenge(proxyAuth, request, proxyServer, headers, realm, future); // SPNEGO KERBEROS } else if (proxyAuth.contains("Negotiate")) { From 10d6c6a0abf4859245eefc64618c09013a224ab3 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 22 Jul 2013 14:25:21 +0200 Subject: [PATCH 188/264] Use isEmpty instead of comparing size/length, close #343 --- .../client/FluentCaseInsensitiveStringsMap.java | 4 +++- .../client/listener/TransferCompletionHandler.java | 4 +++- .../providers/apache/ApacheAsyncHttpProvider.java | 2 +- .../grizzly/GrizzlyAsyncHttpProvider.java | 6 +++--- .../client/providers/jdk/JDKAsyncHttpProvider.java | 2 +- .../providers/netty/NettyAsyncHttpProvider.java | 14 +++++++------- .../providers/netty/NettyConnectionsPool.java | 2 +- .../com/ning/http/util/AsyncHttpProviderUtils.java | 4 ++-- src/main/java/com/ning/http/util/MiscUtil.java | 4 ++++ src/main/java/com/ning/http/util/ProxyUtils.java | 4 +++- 10 files changed, 28 insertions(+), 18 deletions(-) diff --git a/src/main/java/com/ning/http/client/FluentCaseInsensitiveStringsMap.java b/src/main/java/com/ning/http/client/FluentCaseInsensitiveStringsMap.java index 009af7e43f..35f200bc66 100644 --- a/src/main/java/com/ning/http/client/FluentCaseInsensitiveStringsMap.java +++ b/src/main/java/com/ning/http/client/FluentCaseInsensitiveStringsMap.java @@ -16,6 +16,8 @@ */ package com.ning.http.client; +import static com.ning.http.util.MiscUtil.isNonEmpty; + import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -66,7 +68,7 @@ public FluentCaseInsensitiveStringsMap(Map> src) { * @return This object */ public FluentCaseInsensitiveStringsMap add(String key, String... values) { - if ((values != null) && (values.length > 0)) { + if (isNonEmpty(values)) { add(key, Arrays.asList(values)); } return this; diff --git a/src/main/java/com/ning/http/client/listener/TransferCompletionHandler.java b/src/main/java/com/ning/http/client/listener/TransferCompletionHandler.java index 6d71cbd238..5088f12577 100644 --- a/src/main/java/com/ning/http/client/listener/TransferCompletionHandler.java +++ b/src/main/java/com/ning/http/client/listener/TransferCompletionHandler.java @@ -26,6 +26,8 @@ import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.atomic.AtomicLong; +import static com.ning.http.util.MiscUtil.isNonEmpty; + /** * A {@link com.ning.http.client.AsyncHandler} that can be used to notify a set of {@link com.ning.http.client.listener.TransferListener} *

@@ -144,7 +146,7 @@ public Response onCompleted(Response response) throws Exception { */ public STATE onHeaderWriteCompleted() { List list = transferAdapter.getHeaders().get("Content-Length"); - if (list != null && list.size() > 0 && list.get(0) != "") { + if (isNonEmpty(list) && list.get(0) != "") { totalBytesToTransfer.set(Long.valueOf(list.get(0))); } diff --git a/src/main/java/com/ning/http/client/providers/apache/ApacheAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/apache/ApacheAsyncHttpProvider.java index e572101cbb..da81b19bd6 100644 --- a/src/main/java/com/ning/http/client/providers/apache/ApacheAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/apache/ApacheAsyncHttpProvider.java @@ -592,7 +592,7 @@ public T call() { } } catch (Throwable t) { - if (IOException.class.isAssignableFrom(t.getClass()) && config.getIOExceptionFilters().size() > 0) { + if (IOException.class.isAssignableFrom(t.getClass()) && !config.getIOExceptionFilters().isEmpty()) { FilterContext fc = new FilterContext.FilterContextBuilder().asyncHandler(asyncHandler) .request(future.getRequest()).ioException(IOException.class.cast(t)).build(); diff --git a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java index 80313f05c9..711f964f95 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java @@ -1019,7 +1019,7 @@ private void addQueryString(final Request request, try { for (int i = 0, len = values.size(); i < len; i++) { final String value = values.get(i); - if (value != null && value.length() > 0) { + if (isNonEmpty(value)) { sb.append(URLEncoder.encode(name, "UTF-8")).append('=') .append(URLEncoder.encode(values.get(i), "UTF-8")).append('&'); } else { @@ -2606,7 +2606,7 @@ public WebSocket sendMessage(byte[] message) { @Override public WebSocket stream(byte[] fragment, boolean last) { - if (fragment != null && fragment.length > 0) { + if (isNonEmpty(fragment)) { gWebSocket.stream(last, fragment, 0, fragment.length); } return this; @@ -2614,7 +2614,7 @@ public WebSocket stream(byte[] fragment, boolean last) { @Override public WebSocket stream(byte[] fragment, int offset, int len, boolean last) { - if (fragment != null && fragment.length > 0) { + if (isNonEmpty(fragment)) { gWebSocket.stream(last, fragment, offset, len); } return this; diff --git a/src/main/java/com/ning/http/client/providers/jdk/JDKAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/jdk/JDKAsyncHttpProvider.java index ccca62a363..8d3739927a 100644 --- a/src/main/java/com/ning/http/client/providers/jdk/JDKAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/jdk/JDKAsyncHttpProvider.java @@ -370,7 +370,7 @@ public T call() throws Exception { } catch (Throwable t) { logger.debug(t.getMessage(), t); - if (IOException.class.isAssignableFrom(t.getClass()) && config.getIOExceptionFilters().size() > 0) { + if (IOException.class.isAssignableFrom(t.getClass()) && !config.getIOExceptionFilters().isEmpty()) { FilterContext fc = new FilterContext.FilterContextBuilder().asyncHandler(asyncHandler) .request(request).ioException(IOException.class.cast(t)).build(); diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java index f8a3320123..ab0e36c65e 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java @@ -1381,7 +1381,7 @@ public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws NettyResponseFuture future = (NettyResponseFuture) ctx.getAttachment(); future.touch(); - if (config.getIOExceptionFilters().size() > 0) { + if (!config.getIOExceptionFilters().isEmpty()) { FilterContext fc = new FilterContext.FilterContextBuilder().asyncHandler(future.getAsyncHandler()).request(future.getRequest()).ioException(new IOException("Channel Closed")).build(); fc = handleIoException(fc, future); @@ -1517,7 +1517,7 @@ public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws if (IOException.class.isAssignableFrom(cause.getClass())) { - if (config.getIOExceptionFilters().size() > 0) { + if (!config.getIOExceptionFilters().isEmpty()) { FilterContext fc = new FilterContext.FilterContextBuilder().asyncHandler(future.getAsyncHandler()).request(future.getRequest()).ioException(new IOException("Channel Closed")).build(); fc = handleIoException(fc, future); @@ -2101,7 +2101,7 @@ public void handle(final ChannelHandlerContext ctx, final MessageEvent e) throws // builder.setUrl(future.getURI().toString()); // } - if (statusCode == 401 && realm != null && wwwAuth.size() > 0 && !future.getAndSetAuth(true)) { + if (statusCode == 401 && realm != null && !wwwAuth.isEmpty() && !future.getAndSetAuth(true)) { future.setState(NettyResponseFuture.STATE.NEW); // NTLM @@ -2150,7 +2150,7 @@ public Object call() throws Exception { } List proxyAuth = getAuthorizationToken(response.getHeaders(), HttpHeaders.Names.PROXY_AUTHENTICATE); - if (statusCode == 407 && realm != null && proxyAuth.size() > 0 && !future.getAndSetAuth(true)) { + if (statusCode == 407 && realm != null && !proxyAuth.isEmpty() && !future.getAndSetAuth(true)) { log.debug("Sending proxy authentication to {}", request.getUrl()); @@ -2201,7 +2201,7 @@ public Object call() throws Exception { if (!future.getAndSetStatusReceived(true) && updateStatusAndInterrupt(handler, status)) { finishUpdate(future, ctx, response.isChunked()); return; - } else if (response.getHeaders().size() > 0 && updateHeadersAndInterrupt(handler, responseHeaders)) { + } else if (!response.getHeaders().isEmpty() && updateHeadersAndInterrupt(handler, responseHeaders)) { finishUpdate(future, ctx, response.isChunked()); return; } else if (!response.isChunked()) { @@ -2231,7 +2231,7 @@ public Object call() throws Exception { } } } catch (Exception t) { - if (IOException.class.isAssignableFrom(t.getClass()) && config.getIOExceptionFilters().size() > 0) { + if (IOException.class.isAssignableFrom(t.getClass()) && !config.getIOExceptionFilters().isEmpty()) { FilterContext fc = new FilterContext.FilterContextBuilder().asyncHandler(future.getAsyncHandler()).request(future.getRequest()).ioException(IOException.class.cast(t)).build(); fc = handleIoException(fc, future); @@ -2334,7 +2334,7 @@ public void handle(ChannelHandlerContext ctx, MessageEvent e) throws Exception { return; } - String accept = response.getHeader("Sec-WebSocket-Accept"); + String accept = response.getHeader(HttpHeaders.Names.SEC_WEBSOCKET_ACCEPT); String key = WebSocketUtil.getAcceptKey(future.getNettyRequest().getHeader(WEBSOCKET_KEY)); if (accept == null || !accept.equals(key)) { throw new IOException(String.format("Invalid challenge. Actual: %s. Expected: %s", accept, key)); diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyConnectionsPool.java b/src/main/java/com/ning/http/client/providers/netty/NettyConnectionsPool.java index fc467fecce..b3868228a1 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyConnectionsPool.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyConnectionsPool.java @@ -209,7 +209,7 @@ public Channel poll(String uri) { if (idleConnectionForHost != null) { boolean poolEmpty = false; while (!poolEmpty && idleChannel == null) { - if (idleConnectionForHost.size() > 0) { + if (!idleConnectionForHost.isEmpty()) { synchronized (idleConnectionForHost) { idleChannel = idleConnectionForHost.poll(); if (idleChannel != null) { diff --git a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java index e4f555a419..6007a2c05a 100644 --- a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java +++ b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java @@ -158,10 +158,10 @@ public final static URI createUri(String u) { if (path == null) { throw new IllegalArgumentException("The URI path, of the URI " + uri + ", must be non-null"); - } else if (path.length() > 0 && path.charAt(0) != '/') { + } else if (!path.isEmpty() && path.charAt(0) != '/') { throw new IllegalArgumentException("The URI path, of the URI " + uri + ". must start with a '/'"); - } else if (path.length() == 0) { + } else if (path.isEmpty()) { return URI.create(u + "/"); } diff --git a/src/main/java/com/ning/http/util/MiscUtil.java b/src/main/java/com/ning/http/util/MiscUtil.java index 54e472cf9e..26e1859685 100644 --- a/src/main/java/com/ning/http/util/MiscUtil.java +++ b/src/main/java/com/ning/http/util/MiscUtil.java @@ -28,6 +28,10 @@ public static boolean isNonEmpty(Object[] array) { return array != null && array.length != 0; } + public static boolean isNonEmpty(byte[] array) { + return array != null && array.length != 0; + } + public static boolean isNonEmpty(Collection collection) { return collection != null && !collection.isEmpty(); } diff --git a/src/main/java/com/ning/http/util/ProxyUtils.java b/src/main/java/com/ning/http/util/ProxyUtils.java index cf03ab78a5..4f9b3c4240 100644 --- a/src/main/java/com/ning/http/util/ProxyUtils.java +++ b/src/main/java/com/ning/http/util/ProxyUtils.java @@ -12,6 +12,8 @@ */ package com.ning.http.util; +import static com.ning.http.util.MiscUtil.isNonEmpty; + import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.ProxyServer; import com.ning.http.client.ProxyServer.Protocol; @@ -102,7 +104,7 @@ public static boolean avoidProxy(final ProxyServer proxyServer, final String tar List nonProxyHosts = proxyServer.getNonProxyHosts(); - if (nonProxyHosts != null && nonProxyHosts.size() > 0) { + if (nonProxyHosts != null) { for (String nonProxyHost : nonProxyHosts) { if (nonProxyHost.startsWith("*") && nonProxyHost.length() > 1 && targetHost.endsWith(nonProxyHost.substring(1).toLowerCase())) { From 8cb9c4be723b237159d9c18c849e747d5c0e55d2 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 22 Jul 2013 15:00:21 +0200 Subject: [PATCH 189/264] Fix build --- src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java index 6007a2c05a..f5a7ac9845 100644 --- a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java +++ b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java @@ -41,6 +41,8 @@ import com.ning.http.multipart.PartSource; import com.ning.org.jboss.netty.handler.codec.http.CookieDecoder; +import static com.ning.http.util.MiscUtil.isNonEmpty; + /** * {@link com.ning.http.client.AsyncHttpProvider} common utilities. *

@@ -158,7 +160,7 @@ public final static URI createUri(String u) { if (path == null) { throw new IllegalArgumentException("The URI path, of the URI " + uri + ", must be non-null"); - } else if (!path.isEmpty() && path.charAt(0) != '/') { + } else if (isNonEmpty(path) && path.charAt(0) != '/') { throw new IllegalArgumentException("The URI path, of the URI " + uri + ". must start with a '/'"); } else if (path.isEmpty()) { From ec6a83933815b74c83f13b9ef8acf8f1f7f7ecfc Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 22 Jul 2013 15:23:13 +0200 Subject: [PATCH 190/264] Use instanceof instead of isAssignableFrom where possible, close #342 --- .../com/ning/http/client/AsyncHttpClient.java | 2 +- .../consumers/AppendableBodyConsumer.java | 2 +- .../apache/ApacheAsyncHttpProvider.java | 23 ++++--- .../grizzly/GrizzlyAsyncHttpProvider.java | 66 ++++++++----------- .../providers/jdk/JDKAsyncHttpProvider.java | 21 +++--- .../netty/NettyAsyncHttpProvider.java | 44 ++++++------- .../providers/netty/NettyConnectListener.java | 4 +- .../providers/netty/NettyConnectionsPool.java | 14 ++-- .../providers/netty/NettyWebSocket.java | 6 +- .../resumable/ResumableIOExceptionFilter.java | 2 +- .../websocket/WebSocketUpgradeHandler.java | 2 +- .../ning/http/multipart/MultipartBody.java | 4 +- .../client/async/AsyncProvidersBasicTest.java | 2 +- .../ning/http/client/async/EmptyBodyTest.java | 2 +- 14 files changed, 90 insertions(+), 104 deletions(-) diff --git a/src/main/java/com/ning/http/client/AsyncHttpClient.java b/src/main/java/com/ning/http/client/AsyncHttpClient.java index b507e9defe..f8a3d9d5cc 100755 --- a/src/main/java/com/ning/http/client/AsyncHttpClient.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClient.java @@ -554,7 +554,7 @@ private FilterContext preProcessRequest(FilterContext fc) throws IOException { } Request request = fc.getRequest(); - if (ResumableAsyncHandler.class.isAssignableFrom(fc.getAsyncHandler().getClass())) { + if (fc.getAsyncHandler() instanceof ResumableAsyncHandler) { request = ResumableAsyncHandler.class.cast(fc.getAsyncHandler()).adjustRequestRange(request); } diff --git a/src/main/java/com/ning/http/client/consumers/AppendableBodyConsumer.java b/src/main/java/com/ning/http/client/consumers/AppendableBodyConsumer.java index e2976facb5..a1e9dc5ade 100644 --- a/src/main/java/com/ning/http/client/consumers/AppendableBodyConsumer.java +++ b/src/main/java/com/ning/http/client/consumers/AppendableBodyConsumer.java @@ -52,7 +52,7 @@ public void consume(ByteBuffer byteBuffer) throws IOException { */ /* @Override */ public void close() throws IOException { - if (Closeable.class.isAssignableFrom(appendable.getClass())) { + if (appendable instanceof Closeable) { Closeable.class.cast(appendable).close(); } } diff --git a/src/main/java/com/ning/http/client/providers/apache/ApacheAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/apache/ApacheAsyncHttpProvider.java index da81b19bd6..fd041a8f18 100644 --- a/src/main/java/com/ning/http/client/providers/apache/ApacheAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/apache/ApacheAsyncHttpProvider.java @@ -158,7 +158,7 @@ public ApacheAsyncHttpProvider(AsyncHttpClientConfig config) { params.setParameter(HttpMethodParams.RETRY_HANDLER, new DefaultHttpMethodRetryHandler()); AsyncHttpProviderConfig providerConfig = config.getAsyncHttpProviderConfig(); - if (providerConfig != null && ApacheAsyncHttpProvider.class.isAssignableFrom(providerConfig.getClass())) { + if (providerConfig instanceof ApacheAsyncHttpProvider) { configure(ApacheAsyncHttpProviderConfig.class.cast(providerConfig)); } } @@ -171,7 +171,7 @@ public ListenableFuture execute(Request request, AsyncHandler handler) throw new IOException("Closed"); } - if (ResumableAsyncHandler.class.isAssignableFrom(handler.getClass())) { + if (handler instanceof ResumableAsyncHandler) { request = ResumableAsyncHandler.class.cast(handler).adjustRequestRange(request); } @@ -460,7 +460,7 @@ public T call() { future.setReaperFuture(reaperFuture); } - if (TransferCompletionHandler.class.isAssignableFrom(asyncHandler.getClass())) { + if (asyncHandler instanceof TransferCompletionHandler) { throw new IllegalStateException(TransferCompletionHandler.class.getName() + "not supported by this provider"); } @@ -578,9 +578,10 @@ public T call() { } } - if (ProgressAsyncHandler.class.isAssignableFrom(asyncHandler.getClass())) { - ProgressAsyncHandler.class.cast(asyncHandler).onHeaderWriteCompleted(); - ProgressAsyncHandler.class.cast(asyncHandler).onContentWriteCompleted(); + if (asyncHandler instanceof ProgressAsyncHandler) { + ProgressAsyncHandler progressAsyncHandler = (ProgressAsyncHandler) asyncHandler; + progressAsyncHandler.onHeaderWriteCompleted(); + progressAsyncHandler.onContentWriteCompleted(); } try { @@ -592,7 +593,7 @@ public T call() { } } catch (Throwable t) { - if (IOException.class.isAssignableFrom(t.getClass()) && !config.getIOExceptionFilters().isEmpty()) { + if (t instanceof IOException && !config.getIOExceptionFilters().isEmpty()) { FilterContext fc = new FilterContext.FilterContextBuilder().asyncHandler(asyncHandler) .request(future.getRequest()).ioException(IOException.class.cast(t)).build(); @@ -643,20 +644,18 @@ public void run() { } private Throwable filterException(Throwable t) { - if (UnknownHostException.class.isAssignableFrom(t.getClass())) { + if (t instanceof UnknownHostException) { t = new ConnectException(t.getMessage()); - } - if (NoHttpResponseException.class.isAssignableFrom(t.getClass())) { + } else if (t instanceof NoHttpResponseException) { int responseTimeoutInMs = config.getRequestTimeoutInMs(); if (request.getPerRequestConfig() != null && request.getPerRequestConfig().getRequestTimeoutInMs() != -1) { responseTimeoutInMs = request.getPerRequestConfig().getRequestTimeoutInMs(); } t = new TimeoutException(String.format("No response received after %s", responseTimeoutInMs)); - } - if (SSLHandshakeException.class.isAssignableFrom(t.getClass())) { + } else if (t instanceof SSLHandshakeException) { Throwable t2 = new ConnectException(); t2.initCause(t); t = t2; diff --git a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java index 711f964f95..521551401d 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java @@ -904,12 +904,10 @@ private boolean sendAsGrizzlyRequest(final Request request, } } final AsyncHandler h = httpCtx.handler; - if (h != null) { - if (TransferCompletionHandler.class.isAssignableFrom(h.getClass())) { - final FluentCaseInsensitiveStringsMap map = - new FluentCaseInsensitiveStringsMap(request.getHeaders()); - TransferCompletionHandler.class.cast(h).transferAdapter(new GrizzlyTransferAdapter(map)); - } + if (h instanceof TransferCompletionHandler) { + final FluentCaseInsensitiveStringsMap map = + new FluentCaseInsensitiveStringsMap(request.getHeaders()); + TransferCompletionHandler.class.cast(h).transferAdapter(new GrizzlyTransferAdapter(map)); } return sendRequest(ctx, request, requestPacket); @@ -1102,10 +1100,8 @@ protected void onHttpContentParsed(HttpContent content, protected void onHttpHeadersEncoded(HttpHeader httpHeader, FilterChainContext ctx) { final HttpTransactionContext context = provider.getHttpTransactionContext(ctx.getConnection()); final AsyncHandler handler = context.handler; - if (handler != null) { - if (TransferCompletionHandler.class.isAssignableFrom(handler.getClass())) { - ((TransferCompletionHandler) handler).onHeaderWriteCompleted(); - } + if (handler instanceof TransferCompletionHandler) { + ((TransferCompletionHandler) handler).onHeaderWriteCompleted(); } } @@ -1113,15 +1109,13 @@ protected void onHttpHeadersEncoded(HttpHeader httpHeader, FilterChainContext ct protected void onHttpContentEncoded(HttpContent content, FilterChainContext ctx) { final HttpTransactionContext context = provider.getHttpTransactionContext(ctx.getConnection()); final AsyncHandler handler = context.handler; - if (handler != null) { - if (TransferCompletionHandler.class.isAssignableFrom(handler.getClass())) { - final int written = content.getContent().remaining(); - final long total = context.totalBodyWritten.addAndGet(written); - ((TransferCompletionHandler) handler).onContentWriteProgress( - written, - total, - content.getHttpHeader().getContentLength()); - } + if (handler instanceof TransferCompletionHandler) { + final int written = content.getContent().remaining(); + final long total = context.totalBodyWritten.addAndGet(written); + ((TransferCompletionHandler) handler).onContentWriteProgress( + written, + total, + content.getHttpHeader().getContentLength()); } } @@ -2148,15 +2142,13 @@ public boolean doHandle(final FilterChainContext ctx, @Override public void updated(WriteResult result) { final AsyncHandler handler = context.handler; - if (handler != null) { - if (TransferCompletionHandler.class.isAssignableFrom(handler.getClass())) { - final long written = result.getWrittenSize(); - final long total = context.totalBodyWritten.addAndGet(written); - ((TransferCompletionHandler) handler).onContentWriteProgress( - written, - total, - requestPacket.getContentLength()); - } + if (handler instanceof TransferCompletionHandler) { + final long written = result.getWrittenSize(); + final long total = context.totalBodyWritten.addAndGet(written); + ((TransferCompletionHandler) handler).onContentWriteProgress( + written, + total, + requestPacket.getContentLength()); } } }); @@ -2700,7 +2692,7 @@ private static final class AHCWebSocketListenerAdapter implements org.glassfish. @Override public void onClose(org.glassfish.grizzly.websockets.WebSocket gWebSocket, DataFrame dataFrame) { try { - if (WebSocketCloseCodeReasonListener.class.isAssignableFrom(ahcListener.getClass())) { + if (ahcListener instanceof WebSocketCloseCodeReasonListener) { ClosingFrame cf = ClosingFrame.class.cast(dataFrame); WebSocketCloseCodeReasonListener.class.cast(ahcListener).onClose(webSocket, cf.getCode(), cf.getReason()); } else { @@ -2723,7 +2715,7 @@ public void onConnect(org.glassfish.grizzly.websockets.WebSocket gWebSocket) { @Override public void onMessage(org.glassfish.grizzly.websockets.WebSocket webSocket, String s) { try { - if (WebSocketTextListener.class.isAssignableFrom(ahcListener.getClass())) { + if (ahcListener instanceof WebSocketTextListener) { WebSocketTextListener.class.cast(ahcListener).onMessage(s); } } catch (Throwable e) { @@ -2734,7 +2726,7 @@ public void onMessage(org.glassfish.grizzly.websockets.WebSocket webSocket, Stri @Override public void onMessage(org.glassfish.grizzly.websockets.WebSocket webSocket, byte[] bytes) { try { - if (WebSocketByteListener.class.isAssignableFrom(ahcListener.getClass())) { + if (ahcListener instanceof WebSocketByteListener) { WebSocketByteListener.class.cast(ahcListener).onMessage(bytes); } } catch (Throwable e) { @@ -2745,7 +2737,7 @@ public void onMessage(org.glassfish.grizzly.websockets.WebSocket webSocket, byte @Override public void onPing(org.glassfish.grizzly.websockets.WebSocket webSocket, byte[] bytes) { try { - if (WebSocketPingListener.class.isAssignableFrom(ahcListener.getClass())) { + if (ahcListener instanceof WebSocketPingListener) { WebSocketPingListener.class.cast(ahcListener).onPing(bytes); } } catch (Throwable e) { @@ -2756,7 +2748,7 @@ public void onPing(org.glassfish.grizzly.websockets.WebSocket webSocket, byte[] @Override public void onPong(org.glassfish.grizzly.websockets.WebSocket webSocket, byte[] bytes) { try { - if (WebSocketPongListener.class.isAssignableFrom(ahcListener.getClass())) { + if (ahcListener instanceof WebSocketPongListener) { WebSocketPongListener.class.cast(ahcListener).onPong(bytes); } } catch (Throwable e) { @@ -2771,7 +2763,7 @@ public void onFragment(org.glassfish.grizzly.websockets.WebSocket webSocket, Str synchronized (this.webSocket) { stringBuffer.append(s); if (last) { - if (WebSocketTextListener.class.isAssignableFrom(ahcListener.getClass())) { + if (ahcListener instanceof WebSocketTextListener) { final String message = stringBuffer.toString(); stringBuffer.setLength(0); WebSocketTextListener.class.cast(ahcListener).onMessage(message); @@ -2779,7 +2771,7 @@ public void onFragment(org.glassfish.grizzly.websockets.WebSocket webSocket, Str } } } else { - if (WebSocketTextListener.class.isAssignableFrom(ahcListener.getClass())) { + if (ahcListener instanceof WebSocketTextListener) { WebSocketTextListener.class.cast(ahcListener).onFragment(s, last); } } @@ -2795,7 +2787,7 @@ public void onFragment(org.glassfish.grizzly.websockets.WebSocket webSocket, byt synchronized (this.webSocket) { byteArrayOutputStream.write(bytes); if (last) { - if (WebSocketByteListener.class.isAssignableFrom(ahcListener.getClass())) { + if (ahcListener instanceof WebSocketByteListener) { final byte[] bytesLocal = byteArrayOutputStream.toByteArray(); byteArrayOutputStream.reset(); WebSocketByteListener.class.cast(ahcListener).onMessage(bytesLocal); @@ -2803,7 +2795,7 @@ public void onFragment(org.glassfish.grizzly.websockets.WebSocket webSocket, byt } } } else { - if (WebSocketByteListener.class.isAssignableFrom(ahcListener.getClass())) { + if (ahcListener instanceof WebSocketByteListener) { WebSocketByteListener.class.cast(ahcListener).onFragment(bytes, last); } } diff --git a/src/main/java/com/ning/http/client/providers/jdk/JDKAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/jdk/JDKAsyncHttpProvider.java index 8d3739927a..b9985a0aee 100644 --- a/src/main/java/com/ning/http/client/providers/jdk/JDKAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/jdk/JDKAsyncHttpProvider.java @@ -104,7 +104,7 @@ public JDKAsyncHttpProvider(AsyncHttpClientConfig config) { this.config = config; AsyncHttpProviderConfig providerConfig = config.getAsyncHttpProviderConfig(); - if (providerConfig != null && JDKAsyncHttpProviderConfig.class.isAssignableFrom(providerConfig.getClass())) { + if (providerConfig instanceof JDKAsyncHttpProviderConfig) { configure(JDKAsyncHttpProviderConfig.class.cast(providerConfig)); } } @@ -238,7 +238,7 @@ public T call() throws Exception { configure(uri, urlConnection, request); urlConnection.connect(); - if (TransferCompletionHandler.class.isAssignableFrom(asyncHandler.getClass())) { + if (asyncHandler instanceof TransferCompletionHandler) { throw new IllegalStateException(TransferCompletionHandler.class.getName() + "not supported by this provider"); } @@ -353,9 +353,10 @@ public T call() throws Exception { } } - if (ProgressAsyncHandler.class.isAssignableFrom(asyncHandler.getClass())) { - ProgressAsyncHandler.class.cast(asyncHandler).onHeaderWriteCompleted(); - ProgressAsyncHandler.class.cast(asyncHandler).onContentWriteCompleted(); + if (asyncHandler instanceof ProgressAsyncHandler) { + ProgressAsyncHandler progressAsyncHandler = (ProgressAsyncHandler) asyncHandler; + progressAsyncHandler.onHeaderWriteCompleted(); + progressAsyncHandler.onContentWriteCompleted(); } try { T t = asyncHandler.onCompleted(); @@ -370,7 +371,7 @@ public T call() throws Exception { } catch (Throwable t) { logger.debug(t.getMessage(), t); - if (IOException.class.isAssignableFrom(t.getClass()) && !config.getIOExceptionFilters().isEmpty()) { + if (t instanceof IOException && !config.getIOExceptionFilters().isEmpty()) { FilterContext fc = new FilterContext.FilterContextBuilder().asyncHandler(asyncHandler) .request(request).ioException(IOException.class.cast(t)).build(); @@ -421,20 +422,18 @@ private FilterContext handleIoException(FilterContext fc) throws FilterException } private Throwable filterException(Throwable t) { - if (UnknownHostException.class.isAssignableFrom(t.getClass())) { + if (t instanceof UnknownHostException) { t = new ConnectException(t.getMessage()); - } - if (SocketTimeoutException.class.isAssignableFrom(t.getClass())) { + } else if (t instanceof SocketTimeoutException) { int responseTimeoutInMs = config.getRequestTimeoutInMs(); if (request.getPerRequestConfig() != null && request.getPerRequestConfig().getRequestTimeoutInMs() != -1) { responseTimeoutInMs = request.getPerRequestConfig().getRequestTimeoutInMs(); } t = new TimeoutException(String.format("No response received after %s", responseTimeoutInMs)); - } - if (SSLHandshakeException.class.isAssignableFrom(t.getClass())) { + } else if (t instanceof SSLHandshakeException) { Throwable t2 = new ConnectException(); t2.initCause(t); t = t2; diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java index ab0e36c65e..b9f01d2afa 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java @@ -78,6 +78,7 @@ import org.jboss.netty.channel.socket.ClientSocketChannelFactory; import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory; import org.jboss.netty.channel.socket.oio.OioClientSocketChannelFactory; +import org.jboss.netty.handler.codec.PrematureChannelClosureException; import org.jboss.netty.handler.codec.http.DefaultHttpChunkTrailer; import org.jboss.netty.handler.codec.http.DefaultHttpRequest; import org.jboss.netty.handler.codec.http.HttpChunk; @@ -204,7 +205,7 @@ private static boolean isNTLM(List auth) { public NettyAsyncHttpProvider(AsyncHttpClientConfig config) { - if (config.getAsyncHttpProviderConfig() != null && NettyAsyncHttpProviderConfig.class.isAssignableFrom(config.getAsyncHttpProviderConfig().getClass())) { + if (config.getAsyncHttpProviderConfig() instanceof NettyAsyncHttpProviderConfig) { asyncHttpProviderConfig = NettyAsyncHttpProviderConfig.class.cast(config.getAsyncHttpProviderConfig()); } else { asyncHttpProviderConfig = new NettyAsyncHttpProviderConfig(); @@ -216,7 +217,7 @@ public NettyAsyncHttpProvider(AsyncHttpClientConfig config) { } else { // check if external NioClientSocketChannelFactory is defined Object oo = asyncHttpProviderConfig.getProperty(SOCKET_CHANNEL_FACTORY); - if (oo != null && NioClientSocketChannelFactory.class.isAssignableFrom(oo.getClass())) { + if (oo instanceof NioClientSocketChannelFactory) { this.socketChannelFactory = NioClientSocketChannelFactory.class.cast(oo); // cannot allow releasing shared channel factory @@ -224,7 +225,7 @@ public NettyAsyncHttpProvider(AsyncHttpClientConfig config) { } else { ExecutorService e; Object o = asyncHttpProviderConfig.getProperty(BOSS_EXECUTOR_SERVICE); - if (o != null && ExecutorService.class.isAssignableFrom(o.getClass())) { + if (o instanceof ExecutorService) { e = ExecutorService.class.cast(o); } else { e = Executors.newCachedThreadPool(); @@ -303,7 +304,7 @@ public ChannelPipeline getPipeline() throws Exception { if (asyncHttpProviderConfig != null) { Object value = asyncHttpProviderConfig.getProperty(EXECUTE_ASYNC_CONNECT); - if (value != null && Boolean.class.isAssignableFrom(value.getClass())) { + if (value instanceof Boolean) { executeConnectAsync = Boolean.class.cast(value); } else if (asyncHttpProviderConfig.getProperty(DISABLE_NESTED_REQUEST) != null) { DefaultChannelFuture.setUseDeadLockChecker(true); @@ -448,7 +449,7 @@ protected final void writeRequest(final Channel channel, final AsyncHttpClie BodyGenerator bg = future.getRequest().getBodyGenerator(); if (bg != null) { // Netty issue with chunking. - if (InputStreamBodyGenerator.class.isAssignableFrom(bg.getClass())) { + if (bg instanceof InputStreamBodyGenerator) { InputStreamBodyGenerator.class.cast(bg).patchNettyChunkingIssue(true); } @@ -468,7 +469,7 @@ protected final void writeRequest(final Channel channel, final AsyncHttpClie } } - if (TransferCompletionHandler.class.isAssignableFrom(future.getAsyncHandler().getClass())) { + if (future.getAsyncHandler() instanceof TransferCompletionHandler) { FluentCaseInsensitiveStringsMap h = new FluentCaseInsensitiveStringsMap(); for (String s : future.getNettyRequest().getHeaderNames()) { @@ -1412,7 +1413,7 @@ protected boolean remotelyClosed(Channel channel, NettyResponseFuture future) connectionsPool.removeAll(channel); - if (future == null && channel.getPipeline().getContext(NettyAsyncHttpProvider.class).getAttachment() != null && NettyResponseFuture.class.isAssignableFrom(channel.getPipeline().getContext(NettyAsyncHttpProvider.class).getAttachment().getClass())) { + if (future == null && channel.getPipeline().getContext(NettyAsyncHttpProvider.class).getAttachment() instanceof NettyResponseFuture) { future = (NettyResponseFuture) channel.getPipeline().getContext(NettyAsyncHttpProvider.class).getAttachment(); } @@ -1493,10 +1494,7 @@ public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Throwable cause = e.getCause(); NettyResponseFuture future = null; - /** - * Issue 81 if (e.getCause() != null && e.getCause().getClass().isAssignableFrom(PrematureChannelClosureException.class)) { return; } - */ - if (e.getCause() != null && e.getCause().getClass().getSimpleName().equals("PrematureChannelClosureException")) { + if (e.getCause() instanceof PrematureChannelClosureException) { return; } @@ -1506,7 +1504,7 @@ public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws try { - if (cause != null && ClosedChannelException.class.isAssignableFrom(cause.getClass())) { + if (cause instanceof ClosedChannelException) { return; } @@ -1515,7 +1513,7 @@ public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws future.attachChannel(null, false); future.touch(); - if (IOException.class.isAssignableFrom(cause.getClass())) { + if (cause instanceof IOException) { if (!config.getIOExceptionFilters().isEmpty()) { FilterContext fc = new FilterContext.FilterContextBuilder().asyncHandler(future.getAsyncHandler()).request(future.getRequest()).ioException(new IOException("Channel Closed")).build(); @@ -1676,7 +1674,7 @@ public void operationComplete(ChannelFuture cf) { Throwable cause = cf.getCause(); if (cause != null && future.getState() != NettyResponseFuture.STATE.NEW) { - if (IllegalStateException.class.isAssignableFrom(cause.getClass())) { + if (cause instanceof IllegalStateException) { log.debug(cause.getMessage(), cause); try { cf.getChannel().close(); @@ -1686,7 +1684,7 @@ public void operationComplete(ChannelFuture cf) { return; } - if (ClosedChannelException.class.isAssignableFrom(cause.getClass()) || abortOnReadCloseException(cause) || abortOnWriteCloseException(cause)) { + if (cause instanceof ClosedChannelException || abortOnReadCloseException(cause) || abortOnWriteCloseException(cause)) { if (log.isDebugEnabled()) { log.debug(cf.getCause() == null ? "" : cf.getCause().getMessage(), cf.getCause()); @@ -1711,7 +1709,7 @@ public void operationComplete(ChannelFuture cf) { Realm realm = future.getRequest().getRealm() != null ? future.getRequest().getRealm() : NettyAsyncHttpProvider.this.getConfig().getRealm(); boolean startPublishing = future.isInAuth() || realm == null || realm.getUsePreemptiveAuth() == true; - if (startPublishing && ProgressAsyncHandler.class.isAssignableFrom(asyncHandler.getClass())) { + if (startPublishing && asyncHandler instanceof ProgressAsyncHandler) { if (notifyHeaders) { ProgressAsyncHandler.class.cast(asyncHandler).onHeaderWriteCompleted(); } else { @@ -1722,7 +1720,7 @@ public void operationComplete(ChannelFuture cf) { public void operationProgressed(ChannelFuture cf, long amount, long current, long total) { future.touch(); - if (ProgressAsyncHandler.class.isAssignableFrom(asyncHandler.getClass())) { + if (asyncHandler instanceof ProgressAsyncHandler) { ProgressAsyncHandler.class.cast(asyncHandler).onContentWriteProgress(amount, current, total); } } @@ -1962,7 +1960,7 @@ public void destroy() { } private static final boolean validateWebSocketRequest(Request request, AsyncHandler asyncHandler) { - if (request.getMethod() != "GET" || !WebSocketUpgradeHandler.class.isAssignableFrom(asyncHandler.getClass())) { + if (request.getMethod() != "GET" || !(asyncHandler instanceof WebSocketUpgradeHandler)) { return false; } return true; @@ -2231,7 +2229,7 @@ public Object call() throws Exception { } } } catch (Exception t) { - if (IOException.class.isAssignableFrom(t.getClass()) && !config.getIOExceptionFilters().isEmpty()) { + if (t instanceof IOException && !config.getIOExceptionFilters().isEmpty()) { FilterContext fc = new FilterContext.FilterContextBuilder().asyncHandler(future.getAsyncHandler()).request(future.getRequest()).ioException(IOException.class.cast(t)).build(); fc = handleIoException(fc, future); @@ -2390,7 +2388,7 @@ public void setContent(ChannelBuffer content) { webSocket.onTextFragment(frame.getBinaryData().toString(UTF8), frame.isFinalFragment()); } - if (CloseWebSocketFrame.class.isAssignableFrom(frame.getClass())) { + if (frame instanceof CloseWebSocketFrame) { try { ctx.setAttachment(DiscardEvent.class); webSocket.onClose(CloseWebSocketFrame.class.cast(frame).getStatusCode(), CloseWebSocketFrame.class.cast(frame).getReasonText()); @@ -2414,7 +2412,7 @@ public void setContent(ChannelBuffer content) { public void onError(ChannelHandlerContext ctx, ExceptionEvent e) { try { log.warn("onError {}", e); - if (ctx.getAttachment() == null || !NettyResponseFuture.class.isAssignableFrom(ctx.getAttachment().getClass())) { + if (!(ctx.getAttachment() instanceof NettyResponseFuture)) { return; } @@ -2434,7 +2432,7 @@ public void onError(ChannelHandlerContext ctx, ExceptionEvent e) { // @Override public void onClose(ChannelHandlerContext ctx, ChannelStateEvent e) { log.trace("onClose {}", e); - if (ctx.getAttachment() == null || !NettyResponseFuture.class.isAssignableFrom(ctx.getAttachment().getClass())) { + if (!(ctx.getAttachment() instanceof NettyResponseFuture)) { return; } @@ -2444,7 +2442,7 @@ public void onClose(ChannelHandlerContext ctx, ChannelStateEvent e) { NettyWebSocket webSocket = NettyWebSocket.class.cast(h.onCompleted()); h.resetSuccess(); - if (ctx.getAttachment() == null || !DiscardEvent.class.isAssignableFrom(ctx.getAttachment().getClass())) + if (!(ctx.getAttachment() instanceof DiscardEvent)) webSocket.close(1006, "Connection was closed abnormally (that is, with no close frame being sent)."); } catch (Throwable t) { log.error("onError", t); diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyConnectListener.java b/src/main/java/com/ning/http/client/providers/netty/NettyConnectListener.java index 8625643cd7..3fd5ab573f 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyConnectListener.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyConnectListener.java @@ -74,7 +74,7 @@ public final void operationComplete(ChannelFuture f) throws Exception { } HostnameVerifier v = config.getHostnameVerifier(); - if (sslHandler != null && !AllowAllHostnameVerifier.class.isAssignableFrom(v.getClass())) { + if (sslHandler != null && !(v instanceof AllowAllHostnameVerifier)) { // TODO: channel.getRemoteAddress()).getHostName() is very expensive. Should cache the result. if (!v.verify(InetSocketAddress.class.cast(channel.getRemoteAddress()).getHostName(), sslHandler.getEngine().getSession())) { @@ -88,7 +88,7 @@ public final void operationComplete(ChannelFuture f) throws Exception { logger.debug("Trying to recover a dead cached channel {} with a retry value of {} ", f.getChannel(), future.canRetry()); if (future.canRetry() && cause != null && (NettyAsyncHttpProvider.abortOnDisconnectException(cause) - || ClosedChannelException.class.isAssignableFrom(cause.getClass()) + || cause instanceof ClosedChannelException || future.getState() != NettyResponseFuture.STATE.NEW)) { logger.debug("Retrying {} ", nettyRequest); diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyConnectionsPool.java b/src/main/java/com/ning/http/client/providers/netty/NettyConnectionsPool.java index b3868228a1..813f4c41fc 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyConnectionsPool.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyConnectionsPool.java @@ -118,14 +118,12 @@ public void run() { for (IdleChannel idleChannel : channelsInTimeout) { Object attachment = idleChannel.channel.getPipeline().getContext(NettyAsyncHttpProvider.class).getAttachment(); - if (attachment != null) { - if (NettyResponseFuture.class.isAssignableFrom(attachment.getClass())) { - NettyResponseFuture future = (NettyResponseFuture) attachment; - - if (!future.isDone() && !future.isCancelled()) { - log.debug("Future not in appropriate state %s\n", future); - continue; - } + if (attachment instanceof NettyResponseFuture) { + NettyResponseFuture future = (NettyResponseFuture) attachment; + + if (!future.isDone() && !future.isCancelled()) { + log.debug("Future not in appropriate state %s\n", future); + continue; } } diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyWebSocket.java b/src/main/java/com/ning/http/client/providers/netty/NettyWebSocket.java index bd8704f8e3..b9d96249d8 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyWebSocket.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyWebSocket.java @@ -130,7 +130,7 @@ public void close(int statusCode, String reason) { protected void onBinaryFragment(byte[] message, boolean last) { for (WebSocketListener l : listeners) { - if (WebSocketByteListener.class.isAssignableFrom(l.getClass())) { + if (l instanceof WebSocketByteListener) { try { WebSocketByteListener.class.cast(l).onFragment(message,last); @@ -162,7 +162,7 @@ protected void onBinaryFragment(byte[] message, boolean last) { protected void onTextFragment(String message, boolean last) { for (WebSocketListener l : listeners) { - if (WebSocketTextListener.class.isAssignableFrom(l.getClass())) { + if (l instanceof WebSocketTextListener) { try { WebSocketTextListener.class.cast(l).onFragment(message,last); @@ -209,7 +209,7 @@ protected void onClose() { protected void onClose(int code, String reason) { for (WebSocketListener l : listeners) { try { - if (WebSocketCloseCodeReasonListener.class.isAssignableFrom(l.getClass())) { + if (l instanceof WebSocketCloseCodeReasonListener) { WebSocketCloseCodeReasonListener.class.cast(l).onClose(this, code, reason); } l.onClose(this); diff --git a/src/main/java/com/ning/http/client/resumable/ResumableIOExceptionFilter.java b/src/main/java/com/ning/http/client/resumable/ResumableIOExceptionFilter.java index 7e2bd1d254..9422c0bd8d 100644 --- a/src/main/java/com/ning/http/client/resumable/ResumableIOExceptionFilter.java +++ b/src/main/java/com/ning/http/client/resumable/ResumableIOExceptionFilter.java @@ -23,7 +23,7 @@ */ public class ResumableIOExceptionFilter implements IOExceptionFilter { public FilterContext filter(FilterContext ctx) throws FilterException { - if (ctx.getIOException() != null && ResumableAsyncHandler.class.isAssignableFrom(ctx.getAsyncHandler().getClass())) { + if (ctx.getIOException() != null && ctx.getAsyncHandler() instanceof ResumableAsyncHandler) { Request request = ResumableAsyncHandler.class.cast(ctx.getAsyncHandler()).adjustRequestRange(ctx.getRequest()); diff --git a/src/main/java/com/ning/http/client/websocket/WebSocketUpgradeHandler.java b/src/main/java/com/ning/http/client/websocket/WebSocketUpgradeHandler.java index 16704bedef..6f7e20f472 100644 --- a/src/main/java/com/ning/http/client/websocket/WebSocketUpgradeHandler.java +++ b/src/main/java/com/ning/http/client/websocket/WebSocketUpgradeHandler.java @@ -131,7 +131,7 @@ public void onClose(WebSocket webSocket, int status, String reasonPhrase) { webSocket.addWebSocketListener(w); } w.onClose(webSocket); - if (WebSocketCloseCodeReasonListener.class.isAssignableFrom(w.getClass())) { + if (w instanceof WebSocketCloseCodeReasonListener) { WebSocketCloseCodeReasonListener.class.cast(w).onClose(webSocket, status, reasonPhrase); } } diff --git a/src/main/java/com/ning/http/multipart/MultipartBody.java b/src/main/java/com/ning/http/multipart/MultipartBody.java index 1f336c21aa..55799a3266 100644 --- a/src/main/java/com/ning/http/multipart/MultipartBody.java +++ b/src/main/java/com/ning/http/multipart/MultipartBody.java @@ -223,7 +223,7 @@ private void initializeFileEnd(FilePart currentPart) private void initializeFileBody(FilePart currentPart) throws IOException { - if (FilePartSource.class.isAssignableFrom(currentPart.getSource().getClass())) { + if (currentPart.getSource() instanceof FilePartSource) { FilePartSource source = (FilePartSource) currentPart.getSource(); @@ -442,7 +442,7 @@ private long handleFilePart(WritableByteChannel target, FilePart filePart) throw handler.start(); - if (FilePartSource.class.isAssignableFrom(filePart.getSource().getClass())) { + if (filePart.getSource() instanceof FilePartSource) { int length = 0; length += handleFileHeaders(target, filePart); diff --git a/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java b/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java index 52bd48bfe3..0f849674e5 100755 --- a/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java +++ b/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java @@ -967,7 +967,7 @@ public void onThrowable(Throwable t) { future.get(10, TimeUnit.SECONDS); } catch (ExecutionException ex) { - if (ex.getCause() != null && TimeoutException.class.isAssignableFrom(ex.getCause().getClass())) { + if (ex.getCause() instanceof TimeoutException) { Assert.assertTrue(true); } } catch (TimeoutException te) { diff --git a/src/test/java/com/ning/http/client/async/EmptyBodyTest.java b/src/test/java/com/ning/http/client/async/EmptyBodyTest.java index ccec37a180..ea0bbab5fa 100644 --- a/src/test/java/com/ning/http/client/async/EmptyBodyTest.java +++ b/src/test/java/com/ning/http/client/async/EmptyBodyTest.java @@ -133,7 +133,7 @@ public void testPutEmptyBody() throws Throwable { assertNotNull(response); assertEquals(response.getStatusCode(), 204); assertEquals(response.getResponseBody(), ""); - assertTrue(InputStream.class.isAssignableFrom(response.getResponseBodyAsStream().getClass())); + assertTrue(response.getResponseBodyAsStream() instanceof InputStream); assertEquals(response.getResponseBodyAsStream().read(), -1); } finally { From 44b3d054c452a7cc775326794e6d5fb4b6bf0bab Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 22 Jul 2013 17:46:38 +0200 Subject: [PATCH 191/264] Honor multipart boundary if specified in existing Content-Type header, close #345 --- .../multipart/MultipartRequestEntity.java | 47 ++++++++++--------- 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/src/main/java/com/ning/http/multipart/MultipartRequestEntity.java b/src/main/java/com/ning/http/multipart/MultipartRequestEntity.java index cad76f9a5a..545f3a68ef 100644 --- a/src/main/java/com/ning/http/multipart/MultipartRequestEntity.java +++ b/src/main/java/com/ning/http/multipart/MultipartRequestEntity.java @@ -64,7 +64,7 @@ public static byte[] generateMultipartBoundary() { */ protected Part[] parts; - private byte[] multipartBoundary; + private final byte[] multipartBoundary; private final String contentType; @@ -79,11 +79,28 @@ public MultipartRequestEntity(Part[] parts, FluentCaseInsensitiveStringsMap requ } this.parts = parts; String contentTypeHeader = requestHeaders.getFirstValue("Content-Type"); - if (isNonEmpty(contentTypeHeader)) - this.contentType = contentTypeHeader; - else - this.contentType = MULTIPART_FORM_CONTENT_TYPE; + if (isNonEmpty(contentTypeHeader)) { + int boundaryLocation = contentTypeHeader.indexOf("boundary="); + if (boundaryLocation != -1) { + // boundary defined in existing Content-Type + contentType = contentTypeHeader; + multipartBoundary = MultipartEncodingUtil.getAsciiBytes((contentTypeHeader.substring(boundaryLocation + "boundary=".length()).trim())); + } else { + // generate boundary and append it to existing Content-Type + multipartBoundary = generateMultipartBoundary(); + contentType = computeContentType(contentTypeHeader); + } + } else { + multipartBoundary = generateMultipartBoundary(); + contentType = computeContentType(MULTIPART_FORM_CONTENT_TYPE); + } + } + private String computeContentType(String base) { + StringBuilder buffer = new StringBuilder(base); + if (!base.endsWith(";")) + buffer.append(";"); + return buffer.append(" boundary=").append(MultipartEncodingUtil.getAsciiString(multipartBoundary)).toString(); } /** @@ -93,9 +110,6 @@ public MultipartRequestEntity(Part[] parts, FluentCaseInsensitiveStringsMap requ * @return The boundary string of this entity in ASCII encoding. */ protected byte[] getMultipartBoundary() { - if (multipartBoundary == null) { - multipartBoundary = generateMultipartBoundary(); - } return multipartBoundary; } @@ -117,7 +131,7 @@ public boolean isRepeatable() { * @see org.apache.commons.httpclient.methods.RequestEntity#writeRequest(java.io.OutputStream) */ public void writeRequest(OutputStream out) throws IOException { - Part.sendParts(out, parts, getMultipartBoundary()); + Part.sendParts(out, parts, multipartBoundary); } /* @@ -127,7 +141,7 @@ public void writeRequest(OutputStream out) throws IOException { */ public long getContentLength() { try { - return Part.getLengthOfParts(parts, getMultipartBoundary()); + return Part.getLengthOfParts(parts, multipartBoundary); } catch (Exception e) { log.error("An exception occurred while getting the length of the parts", e); return 0; @@ -140,16 +154,7 @@ public long getContentLength() { * @see org.apache.commons.httpclient.methods.RequestEntity#getContentType() */ public String getContentType() { - if (contentType.contains("boundary=")) - return contentType; - else { - StringBuilder buffer = new StringBuilder(contentType); - if (!contentType.endsWith(";")) - buffer.append(";"); - buffer.append(" boundary="); - buffer.append(MultipartEncodingUtil.getAsciiString(getMultipartBoundary())); - return buffer.toString(); - } + return contentType; } - } + From 4ac6e05aae095a0cfa768b4da199d054ef3569c9 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 22 Jul 2013 23:20:52 +0200 Subject: [PATCH 192/264] Remove ListenableFuture.done Callable argument, close #344 --- .../com/ning/http/client/ListenableFuture.java | 5 ++--- .../listenable/AbstractListenableFuture.java | 2 +- .../providers/apache/ApacheAsyncHttpProvider.java | 4 ++-- .../providers/apache/ApacheResponseFuture.java | 11 +++++------ .../grizzly/GrizzlyAsyncHttpProvider.java | 8 ++++---- .../providers/grizzly/GrizzlyResponseFuture.java | 12 ++++-------- .../providers/jdk/JDKAsyncHttpProvider.java | 4 ++-- .../client/providers/jdk/JDKDelegateFuture.java | 9 ++++----- .../ning/http/client/providers/jdk/JDKFuture.java | 11 +++++------ .../providers/netty/NettyAsyncHttpProvider.java | 4 ++-- .../providers/netty/NettyResponseFuture.java | 15 ++++----------- 11 files changed, 35 insertions(+), 50 deletions(-) diff --git a/src/main/java/com/ning/http/client/ListenableFuture.java b/src/main/java/com/ning/http/client/ListenableFuture.java index 74dfcb70f0..b119f26597 100755 --- a/src/main/java/com/ning/http/client/ListenableFuture.java +++ b/src/main/java/com/ning/http/client/ListenableFuture.java @@ -30,7 +30,6 @@ */ package com.ning.http.client; -import java.util.concurrent.Callable; import java.util.concurrent.Executor; import java.util.concurrent.Future; @@ -42,11 +41,11 @@ public interface ListenableFuture extends Future { /** - * Execute a {@link Callable} and if there is no exception, mark this Future as done and release the internal lock. + * Terminate and if there is no exception, mark this Future as done and release the internal lock. * * @param callable */ - void done(Callable callable); + void done(); /** * Abort the current processing, and propagate the {@link Throwable} to the {@link AsyncHandler} or {@link Future} diff --git a/src/main/java/com/ning/http/client/listenable/AbstractListenableFuture.java b/src/main/java/com/ning/http/client/listenable/AbstractListenableFuture.java index a0f9575e6a..16b2f94352 100644 --- a/src/main/java/com/ning/http/client/listenable/AbstractListenableFuture.java +++ b/src/main/java/com/ning/http/client/listenable/AbstractListenableFuture.java @@ -63,7 +63,7 @@ public ListenableFuture addListener(Runnable listener, Executor exec) { /* * Override the done method to execute the execution list. */ - protected void done() { + protected void runListeners() { executionList.run(); } } diff --git a/src/main/java/com/ning/http/client/providers/apache/ApacheAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/apache/ApacheAsyncHttpProvider.java index fd041a8f18..a125d1ba9d 100644 --- a/src/main/java/com/ning/http/client/providers/apache/ApacheAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/apache/ApacheAsyncHttpProvider.java @@ -603,7 +603,7 @@ public T call() { if (config.getMaxTotalConnections() != -1) { maxConnections.decrementAndGet(); } - future.done(null); + future.done(); method.releaseConnection(); } @@ -629,7 +629,7 @@ public T call() { if (config.getMaxTotalConnections() != -1) { maxConnections.decrementAndGet(); } - future.done(null); + future.done(); // Crappy Apache HttpClient who blocks forever here with large files. config.executorService().submit(new Runnable() { diff --git a/src/main/java/com/ning/http/client/providers/apache/ApacheResponseFuture.java b/src/main/java/com/ning/http/client/providers/apache/ApacheResponseFuture.java index 67706fbea6..cdbe106c92 100644 --- a/src/main/java/com/ning/http/client/providers/apache/ApacheResponseFuture.java +++ b/src/main/java/com/ning/http/client/providers/apache/ApacheResponseFuture.java @@ -21,7 +21,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.concurrent.Callable; import java.util.concurrent.CancellationException; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; @@ -64,12 +63,12 @@ protected void setInnerFuture(Future innerFuture) { this.innerFuture = innerFuture; } - public void done(Callable callable) { + public void done() { isDone.set(true); if (reaperFuture != null) { reaperFuture.cancel(true); } - super.done(); + runListeners(); } /** @@ -125,7 +124,7 @@ public void abort(Throwable t) { logger.debug("asyncHandler.onThrowable", t2); } } - super.done(); + runListeners(); } public boolean cancel(boolean mayInterruptIfRunning) { @@ -140,10 +139,10 @@ public boolean cancel(boolean mayInterruptIfRunning) { if (reaperFuture != null) { reaperFuture.cancel(true); } - super.done(); + runListeners(); return innerFuture.cancel(mayInterruptIfRunning); } else { - super.done(); + runListeners(); return false; } } diff --git a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java index 521551401d..4e367b1465 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java @@ -674,9 +674,9 @@ void abort(final Throwable t) { } } - void done(final Callable c) { + void done() { if (future != null) { - future.done(c); + future.done(); } } @@ -684,7 +684,7 @@ void done(final Callable c) { void result(Object result) { if (future != null) { future.delegate.result(result); - future.done(null); + future.done(); } } @@ -1371,7 +1371,7 @@ protected boolean onHttpPacketParsed(HttpHeader httpHeader, FilterChainContext c context.abort(e); } } else { - context.done(null); + context.done(); } return result; diff --git a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponseFuture.java b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponseFuture.java index d4116ad4c0..fb68580678 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponseFuture.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponseFuture.java @@ -21,8 +21,6 @@ import org.glassfish.grizzly.Connection; import org.glassfish.grizzly.impl.FutureImpl; -import java.io.IOException; -import java.util.concurrent.Callable; import java.util.concurrent.CancellationException; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; @@ -67,14 +65,12 @@ public class GrizzlyResponseFuture extends AbstractListenableFuture { // ----------------------------------- Methods from AbstractListenableFuture - public void done(Callable callable) { + public void done() { if (!done.compareAndSet(false, true) || cancelled.get()) { return; } - done(); - - + runListeners(); } @@ -93,7 +89,7 @@ public void abort(Throwable t) { } closeConnection(); - done(); + runListeners(); } @@ -144,7 +140,7 @@ public boolean cancel(boolean mayInterruptIfRunning) { } catch (Throwable ignore) { } } - done(); + runListeners(); return delegate.cancel(mayInterruptIfRunning); } diff --git a/src/main/java/com/ning/http/client/providers/jdk/JDKAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/jdk/JDKAsyncHttpProvider.java index b9985a0aee..011884c171 100644 --- a/src/main/java/com/ning/http/client/providers/jdk/JDKAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/jdk/JDKAsyncHttpProvider.java @@ -361,7 +361,7 @@ public T call() throws Exception { try { T t = asyncHandler.onCompleted(); future.content(t); - future.done(null); + future.done(); return t; } catch (Throwable t) { RuntimeException ex = new RuntimeException(); @@ -381,7 +381,7 @@ public T call() throws Exception { if (config.getMaxTotalConnections() != -1) { maxConnections.decrementAndGet(); } - future.done(null); + future.done(); } if (fc.replayRequest()) { diff --git a/src/main/java/com/ning/http/client/providers/jdk/JDKDelegateFuture.java b/src/main/java/com/ning/http/client/providers/jdk/JDKDelegateFuture.java index 0791a4a567..b1dbcc3a3a 100644 --- a/src/main/java/com/ning/http/client/providers/jdk/JDKDelegateFuture.java +++ b/src/main/java/com/ning/http/client/providers/jdk/JDKDelegateFuture.java @@ -18,7 +18,6 @@ import com.ning.http.client.ListenableFuture; import java.net.HttpURLConnection; -import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; @@ -32,9 +31,9 @@ public JDKDelegateFuture(AsyncHandler asyncHandler, int responseTimeoutInMs, this.delegateFuture = delegateFuture; } - public void done(Callable callable) { - delegateFuture.done(callable); - super.done(callable); + public void done() { + delegateFuture.done(); + super.done(); } public void abort(Throwable t) { @@ -79,7 +78,7 @@ public V get(long timeout, TimeUnit unit) throws InterruptedException, Execution delegateFuture.abort(new ExecutionException(exception.get())); } delegateFuture.content(content); - delegateFuture.done(null); + delegateFuture.done(); return content; } } diff --git a/src/main/java/com/ning/http/client/providers/jdk/JDKFuture.java b/src/main/java/com/ning/http/client/providers/jdk/JDKFuture.java index e029183f53..0ec695ae9f 100644 --- a/src/main/java/com/ning/http/client/providers/jdk/JDKFuture.java +++ b/src/main/java/com/ning/http/client/providers/jdk/JDKFuture.java @@ -20,7 +20,6 @@ import org.slf4j.LoggerFactory; import java.net.HttpURLConnection; -import java.util.concurrent.Callable; import java.util.concurrent.CancellationException; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; @@ -60,9 +59,9 @@ protected void setInnerFuture(Future innerFuture) { this.innerFuture = innerFuture; } - public void done(Callable callable) { + public void done() { isDone.set(true); - super.done(); + runListeners(); } public void abort(Throwable t) { @@ -77,7 +76,7 @@ public void abort(Throwable t) { logger.debug("asyncHandler.onThrowable", te); } } - super.done(); + runListeners(); } public void content(V v) { @@ -92,10 +91,10 @@ public boolean cancel(boolean mayInterruptIfRunning) { logger.debug("asyncHandler.onThrowable", te); } cancelled.set(true); - super.done(); + runListeners(); return innerFuture.cancel(mayInterruptIfRunning); } else { - super.done(); + runListeners(); return false; } } diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java index b9f01d2afa..ebb57caade 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java @@ -1440,7 +1440,7 @@ protected boolean remotelyClosed(Channel channel, NettyResponseFuture future) private void markAsDone(final NettyResponseFuture future, final ChannelHandlerContext ctx) throws MalformedURLException { // We need to make sure everything is OK before adding the connection back to the pool. try { - future.done(null); + future.done(); } catch (Throwable t) { // Never propagate exception once we know we are done. log.debug(t.getMessage(), t); @@ -2342,7 +2342,7 @@ public void handle(ChannelHandlerContext ctx, MessageEvent e) throws Exception { ctx.getPipeline().get(HttpResponseDecoder.class).replace("ws-decoder", new WebSocket08FrameDecoder(false, false)); invokeOnSucces(ctx, h); - future.done(null); + future.done(); } else if (e.getMessage() instanceof WebSocketFrame) { invokeOnSucces(ctx, h); diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyResponseFuture.java b/src/main/java/com/ning/http/client/providers/netty/NettyResponseFuture.java index 8cf16dc83e..29d22415c6 100755 --- a/src/main/java/com/ning/http/client/providers/netty/NettyResponseFuture.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyResponseFuture.java @@ -180,7 +180,7 @@ public boolean cancel(boolean force) { } latch.countDown(); isCancelled.set(true); - super.done(); + runListeners(); return true; } @@ -293,7 +293,7 @@ V getContent() throws ExecutionException { return update; } - public final void done(Callable callable) { + public final void done() { Throwable exception = null; @@ -305,13 +305,6 @@ public final void done(Callable callable) { } getContent(); isDone.set(true); - if (callable != null) { - try { - callable.call(); - } catch (Exception ex) { - exception = ex; - } - } } catch (ExecutionException t) { return; } catch (RuntimeException t) { @@ -324,7 +317,7 @@ public final void done(Callable callable) { if (exception != null) exEx.compareAndSet(null, new ExecutionException(exception)); - super.done(); + runListeners(); } public final void abort(final Throwable t) { @@ -344,7 +337,7 @@ public final void abort(final Throwable t) { } } latch.countDown(); - super.done(); + runListeners(); } public void content(V v) { From b588f716abfc37a600c7aa55daab769a31cf9699 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 22 Jul 2013 23:25:27 +0200 Subject: [PATCH 193/264] Fix race condition in NettyResponseFuture.done exception handling, close #337 --- .../http/client/providers/netty/NettyResponseFuture.java | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyResponseFuture.java b/src/main/java/com/ning/http/client/providers/netty/NettyResponseFuture.java index 29d22415c6..ab43dc91c2 100755 --- a/src/main/java/com/ning/http/client/providers/netty/NettyResponseFuture.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyResponseFuture.java @@ -19,7 +19,6 @@ import java.net.MalformedURLException; import java.net.URI; -import java.util.concurrent.Callable; import java.util.concurrent.CancellationException; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutionException; @@ -295,8 +294,6 @@ V getContent() throws ExecutionException { public final void done() { - Throwable exception = null; - try { cancelReaper(); @@ -308,15 +305,13 @@ public final void done() { } catch (ExecutionException t) { return; } catch (RuntimeException t) { - exception = t.getCause() != null ? t.getCause() : t; + Throwable exception = t.getCause() != null ? t.getCause() : t; + exEx.compareAndSet(null, new ExecutionException(exception)); } finally { latch.countDown(); } - if (exception != null) - exEx.compareAndSet(null, new ExecutionException(exception)); - runListeners(); } From d2cc2ec6beffcbda3276a353cb37b3ecb9142d63 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 22 Jul 2013 23:27:29 +0200 Subject: [PATCH 194/264] Minor clean up --- .../java/com/ning/http/client/providers/jdk/JDKResponse.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/ning/http/client/providers/jdk/JDKResponse.java b/src/main/java/com/ning/http/client/providers/jdk/JDKResponse.java index b4aa4fe84b..0981731bb0 100644 --- a/src/main/java/com/ning/http/client/providers/jdk/JDKResponse.java +++ b/src/main/java/com/ning/http/client/providers/jdk/JDKResponse.java @@ -170,7 +170,7 @@ public List getCookies() { if (headers == null) { return Collections.emptyList(); } - if (cookies == null || cookies.isEmpty()) { + if (!isNonEmpty(cookies)) { List localCookies = new ArrayList(); for (Map.Entry> header : headers.getHeaders().entrySet()) { if (header.getKey().equalsIgnoreCase("Set-Cookie")) { From c1d3ffdea3202cdecaa599c5f9c0bd1681334512 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 23 Jul 2013 09:36:52 +0200 Subject: [PATCH 195/264] Make NettyConnectionsPool's Timer externally configurable, close #346 --- .../client/providers/netty/NettyConnectionsPool.java | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyConnectionsPool.java b/src/main/java/com/ning/http/client/providers/netty/NettyConnectionsPool.java index 813f4c41fc..5639a59c54 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyConnectionsPool.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyConnectionsPool.java @@ -38,7 +38,7 @@ public class NettyConnectionsPool implements ConnectionsPool { private final ConcurrentHashMap channel2IdleChannel = new ConcurrentHashMap(); private final ConcurrentHashMap channel2CreationDate = new ConcurrentHashMap(); private final AtomicBoolean isClosed = new AtomicBoolean(false); - private final Timer idleConnectionDetector = new Timer(true); + private final Timer idleConnectionDetector; private final boolean sslConnectionPoolEnabled; private final int maxTotalConnections; private final int maxConnectionPerHost; @@ -46,16 +46,22 @@ public class NettyConnectionsPool implements ConnectionsPool { private final long maxIdleTime; public NettyConnectionsPool(NettyAsyncHttpProvider provider) { - this(provider.getConfig().getMaxTotalConnections(), provider.getConfig().getMaxConnectionPerHost(), provider.getConfig().getIdleConnectionInPoolTimeoutInMs(), provider.getConfig().getMaxConnectionLifeTimeInMs(), provider.getConfig().isSslConnectionPoolEnabled()); + this(provider.getConfig().getMaxTotalConnections(),// + provider.getConfig().getMaxConnectionPerHost(),// + provider.getConfig().getIdleConnectionInPoolTimeoutInMs(),// + provider.getConfig().getMaxConnectionLifeTimeInMs(),// + provider.getConfig().isSslConnectionPoolEnabled(),// + new Timer(true)); } - public NettyConnectionsPool(int maxTotalConnections, int maxConnectionPerHost, long maxIdleTime, int maxConnectionLifeTimeInMs, boolean sslConnectionPoolEnabled) { + public NettyConnectionsPool(int maxTotalConnections, int maxConnectionPerHost, long maxIdleTime, int maxConnectionLifeTimeInMs, boolean sslConnectionPoolEnabled, Timer idleConnectionDetector) { this.maxTotalConnections = maxTotalConnections; this.maxConnectionPerHost = maxConnectionPerHost; this.sslConnectionPoolEnabled = sslConnectionPoolEnabled; this.maxIdleTime = maxIdleTime; this.maxConnectionLifeTimeInMs = maxConnectionLifeTimeInMs; this.idleConnectionDetector.schedule(new IdleChannelDetector(), maxIdleTime, maxIdleTime); + this.idleConnectionDetector = idleConnectionDetector; } private static class IdleChannel { From c7ee3e7f73a7208af4adf603dda132f86dd7906e Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 23 Jul 2013 09:41:29 +0200 Subject: [PATCH 196/264] Fix build --- src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java index f5a7ac9845..e2e7631b18 100644 --- a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java +++ b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java @@ -163,7 +163,7 @@ public final static URI createUri(String u) { } else if (isNonEmpty(path) && path.charAt(0) != '/') { throw new IllegalArgumentException("The URI path, of the URI " + uri + ". must start with a '/'"); - } else if (path.isEmpty()) { + } else if (!isNonEmpty(path)) { return URI.create(u + "/"); } From a0a83a631d55925ef09404016605cf3141b3c055 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 23 Jul 2013 11:12:24 +0200 Subject: [PATCH 197/264] Google redirect has changed --- src/test/java/com/ning/http/client/async/Relative302Test.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/test/java/com/ning/http/client/async/Relative302Test.java b/src/test/java/com/ning/http/client/async/Relative302Test.java index 871b6a9ce2..0d189048da 100644 --- a/src/test/java/com/ning/http/client/async/Relative302Test.java +++ b/src/test/java/com/ning/http/client/async/Relative302Test.java @@ -97,10 +97,9 @@ public void redirected302Test() throws Throwable { assertNotNull(response); assertEquals(response.getStatusCode(), 200); - String anyGoogleSubdomain = "http://www//.google//.[a-z]+(//.[a-z]+)*:80"; String baseUrl = getBaseUrl(response.getUri()); - assertTrue(baseUrl.matches(anyGoogleSubdomain), "response does not show redirection to " + anyGoogleSubdomain); + assertTrue(baseUrl.startsWith("http://www.google./"), "response does not show redirection to a google subdomain, got " + baseUrl); } finally { c.close(); } From 3d79612ad17b2fe6236135922fd23164e62f6868 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 23 Jul 2013 22:32:13 +0200 Subject: [PATCH 198/264] Fix NPE --- .../ning/http/client/providers/netty/NettyConnectionsPool.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyConnectionsPool.java b/src/main/java/com/ning/http/client/providers/netty/NettyConnectionsPool.java index 5639a59c54..08acb0bf02 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyConnectionsPool.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyConnectionsPool.java @@ -60,8 +60,8 @@ public NettyConnectionsPool(int maxTotalConnections, int maxConnectionPerHost, l this.sslConnectionPoolEnabled = sslConnectionPoolEnabled; this.maxIdleTime = maxIdleTime; this.maxConnectionLifeTimeInMs = maxConnectionLifeTimeInMs; - this.idleConnectionDetector.schedule(new IdleChannelDetector(), maxIdleTime, maxIdleTime); this.idleConnectionDetector = idleConnectionDetector; + this.idleConnectionDetector.schedule(new IdleChannelDetector(), maxIdleTime, maxIdleTime); } private static class IdleChannel { From d670f590df157016ba36ae0088c6384cf3199399 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 24 Jul 2013 00:15:16 +0200 Subject: [PATCH 199/264] Don't build request twice when using a proxy, close #235 --- .../http/client/providers/netty/NettyAsyncHttpProvider.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java index ebb57caade..b03f0e8b0e 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java @@ -937,9 +937,10 @@ private ListenableFuture doConnect(final Request request, final AsyncHand boolean useSSl = isSecure(uri) && !useProxy; if (channel != null && channel.isOpen() && channel.isConnected()) { - HttpRequest nettyRequest = buildRequest(config, request, uri, f != null && f.isConnectAllowed(), bufferedBytes, proxyServer); + HttpRequest nettyRequest = null; if (f == null) { + nettyRequest = buildRequest(config, request, uri, false, bufferedBytes, proxyServer); f = newFuture(uri, request, asyncHandler, nettyRequest, config, this, proxyServer); } else { nettyRequest = buildRequest(config, request, uri, f.isConnectAllowed(), bufferedBytes, proxyServer); From e3d5db5e85fd38355a4905b6e9b3b99ecfa28939 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 25 Jul 2013 15:28:43 +0200 Subject: [PATCH 200/264] Don't pass nettyRequest to writeRequest: it's in the future --- .../netty/NettyAsyncHttpProvider.java | 21 +++++++++++-------- .../providers/netty/NettyConnectListener.java | 9 ++++---- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java index b03f0e8b0e..94e46626db 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java @@ -435,7 +435,10 @@ private Channel verifyChannelPipeline(Channel channel, String scheme) throws IOE return channel; } - protected final void writeRequest(final Channel channel, final AsyncHttpClientConfig config, final NettyResponseFuture future, final HttpRequest nettyRequest) { + protected final void writeRequest(final Channel channel, final AsyncHttpClientConfig config, final NettyResponseFuture future) { + + HttpRequest nettyRequest = future.getNettyRequest(); + try { /** * If the channel is dead because it was pooled and the remote server decided to close it, we just let it go and the closeChannel do it's work. @@ -445,7 +448,7 @@ protected final void writeRequest(final Channel channel, final AsyncHttpClie } Body body = null; - if (!future.getNettyRequest().getMethod().equals(HttpMethod.CONNECT)) { + if (!nettyRequest.getMethod().equals(HttpMethod.CONNECT)) { BodyGenerator bg = future.getRequest().getBodyGenerator(); if (bg != null) { // Netty issue with chunking. @@ -472,8 +475,8 @@ protected final void writeRequest(final Channel channel, final AsyncHttpClie if (future.getAsyncHandler() instanceof TransferCompletionHandler) { FluentCaseInsensitiveStringsMap h = new FluentCaseInsensitiveStringsMap(); - for (String s : future.getNettyRequest().getHeaderNames()) { - for (String header : future.getNettyRequest().getHeaders(s)) { + for (String s : nettyRequest.getHeaderNames()) { + for (String header : nettyRequest.getHeaders(s)) { h.add(s, header); } } @@ -497,7 +500,7 @@ protected final void writeRequest(final Channel channel, final AsyncHttpClie } if (future.getAndSetWriteBody(true)) { - if (!future.getNettyRequest().getMethod().equals(HttpMethod.CONNECT)) { + if (!nettyRequest.getMethod().equals(HttpMethod.CONNECT)) { if (future.getRequest().getFile() != null) { final File file = future.getRequest().getFile(); @@ -538,8 +541,8 @@ public void operationComplete(ChannelFuture cf) { * TODO: AHC-78: SSL + zero copy isn't supported by the MultiPart class and pretty complex to implements. */ if (future.getRequest().getParts() != null) { - String contentType = future.getNettyRequest().getHeader(HttpHeaders.Names.CONTENT_TYPE); - String length = future.getNettyRequest().getHeader(HttpHeaders.Names.CONTENT_LENGTH); + String contentType = nettyRequest.getHeader(HttpHeaders.Names.CONTENT_TYPE); + String length = nettyRequest.getHeader(HttpHeaders.Names.CONTENT_LENGTH); body = new MultipartBody(future.getRequest().getParts(), contentType, length); } @@ -953,7 +956,7 @@ private ListenableFuture doConnect(final Request request, final AsyncHand channel.getPipeline().getContext(NettyAsyncHttpProvider.class).setAttachment(f); try { - writeRequest(channel, config, f, nettyRequest); + writeRequest(channel, config, f); } catch (Exception ex) { log.debug("writeRequest failure", ex); if (useSSl && ex.getMessage() != null && ex.getMessage().contains("SSLEngine")) { @@ -2144,7 +2147,7 @@ public Object call() throws Exception { if (statusCode == 100) { future.getAndSetWriteHeaders(false); future.getAndSetWriteBody(true); - writeRequest(ctx.getChannel(), config, future, nettyRequest); + writeRequest(ctx.getChannel(), config, future); return; } diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyConnectListener.java b/src/main/java/com/ning/http/client/providers/netty/NettyConnectListener.java index 3fd5ab573f..0dbca7a339 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyConnectListener.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyConnectListener.java @@ -52,11 +52,10 @@ final class NettyConnectListener implements ChannelFutureListener { private final AtomicBoolean handshakeDone = new AtomicBoolean(false); private NettyConnectListener(AsyncHttpClientConfig config, - NettyResponseFuture future, - HttpRequest nettyRequest) { + NettyResponseFuture future) { this.config = config; this.future = future; - this.nettyRequest = nettyRequest; + this.nettyRequest = future.getNettyRequest(); } public NettyResponseFuture future() { @@ -82,7 +81,7 @@ public final void operationComplete(ChannelFuture f) throws Exception { } } - future.provider().writeRequest(f.getChannel(), config, future, nettyRequest); + future.provider().writeRequest(f.getChannel(), config, future); } else { Throwable cause = f.getCause(); @@ -148,7 +147,7 @@ public NettyConnectListener build(final URI uri) throws IOException { future.setNettyRequest(nettyRequest); future.setRequest(request); } - return new NettyConnectListener(config, future, nettyRequest); + return new NettyConnectListener(config, future); } } } From 6d2b7062d449926d22f150762065fffeb5942fd2 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 25 Jul 2013 15:30:38 +0200 Subject: [PATCH 201/264] Compute SSL check once --- .../http/client/providers/netty/NettyAsyncHttpProvider.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java index 94e46626db..04913840ee 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java @@ -438,6 +438,7 @@ private Channel verifyChannelPipeline(Channel channel, String scheme) throws IOE protected final void writeRequest(final Channel channel, final AsyncHttpClientConfig config, final NettyResponseFuture future) { HttpRequest nettyRequest = future.getNettyRequest(); + boolean ssl = channel.getPipeline().get(SslHandler.class) != null; try { /** @@ -511,7 +512,7 @@ protected final void writeRequest(final Channel channel, final AsyncHttpClie fileLength = raf.length(); ChannelFuture writeFuture; - if (channel.getPipeline().get(SslHandler.class) != null) { + if (ssl) { writeFuture = channel.write(new ChunkedFile(raf, 0, fileLength, 8192)); } else { final FileRegion region = new OptimizedFileRegion(raf, 0, fileLength); @@ -547,7 +548,7 @@ public void operationComplete(ChannelFuture cf) { } ChannelFuture writeFuture; - if (channel.getPipeline().get(SslHandler.class) == null && (body instanceof RandomAccessBody)) { + if (!ssl && body instanceof RandomAccessBody) { BodyFileRegion bodyFileRegion = new BodyFileRegion((RandomAccessBody) body); writeFuture = channel.write(bodyFileRegion); } else { From 6af397e4e5b622f834f982b0f17e7bba3f338a74 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 25 Jul 2013 15:30:52 +0200 Subject: [PATCH 202/264] typo --- .../ning/http/client/generators/InputStreamBodyGenerator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/ning/http/client/generators/InputStreamBodyGenerator.java b/src/main/java/com/ning/http/client/generators/InputStreamBodyGenerator.java index 5beba6e092..99ae7fe9d8 100644 --- a/src/main/java/com/ning/http/client/generators/InputStreamBodyGenerator.java +++ b/src/main/java/com/ning/http/client/generators/InputStreamBodyGenerator.java @@ -79,7 +79,7 @@ public long read(ByteBuffer buffer) throws IOException { if (patchNettyChunkingIssue) { if (read == -1) { - // Since we are chuncked, we must output extra bytes before considering the input stream closed. + // Since we are chunked, we must output extra bytes before considering the input stream closed. // chunking requires to end the chunking: // - A Terminating chunk of "0\r\n".getBytes(), // - Then a separate packet of "\r\n".getBytes() From 739c3a6491d80b47e9cd0abb81cbecf69dd23d49 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 25 Jul 2013 15:33:40 +0200 Subject: [PATCH 203/264] BodyChunkedInput clean up --- .../providers/netty/BodyChunkedInput.java | 65 +++++++++---------- 1 file changed, 29 insertions(+), 36 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/BodyChunkedInput.java b/src/main/java/com/ning/http/client/providers/netty/BodyChunkedInput.java index 9ea1de6609..8e155f8b5f 100644 --- a/src/main/java/com/ning/http/client/providers/netty/BodyChunkedInput.java +++ b/src/main/java/com/ning/http/client/providers/netty/BodyChunkedInput.java @@ -16,68 +16,61 @@ import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.handler.stream.ChunkedInput; -import java.io.IOException; import java.nio.ByteBuffer; /** * Adapts a {@link Body} to Netty's {@link ChunkedInput}. */ -class BodyChunkedInput - implements ChunkedInput { +class BodyChunkedInput implements ChunkedInput { - private final Body body; - - private final int chunkSize = 1024 * 8; + private static final int DEFAULT_CHUNK_SIZE = 8 * 1024; - private ByteBuffer nextChunk; + private final Body body; + private final int contentLength; + private final int chunkSize; - private static final ByteBuffer EOF = ByteBuffer.allocate(0); + private boolean endOfInput; public BodyChunkedInput(Body body) { if (body == null) { throw new IllegalArgumentException("no body specified"); } this.body = body; + contentLength = (int) body.getContentLength(); + if (contentLength <= 0) + chunkSize = DEFAULT_CHUNK_SIZE; + else + chunkSize = Math.min(contentLength, DEFAULT_CHUNK_SIZE); } - private ByteBuffer peekNextChuck() - throws IOException { + public boolean hasNextChunk() throws Exception { + // unused + throw new UnsupportedOperationException(); + } - if (nextChunk == null) { + public Object nextChunk() throws Exception { + if (endOfInput) { + return null; + } else { ByteBuffer buffer = ByteBuffer.allocate(chunkSize); - if (body.read(buffer) < 0) { - nextChunk = EOF; + long r = body.read(buffer); + if (r < 0L) { + endOfInput = true; + return null; } else { + endOfInput = r == contentLength || r < chunkSize; buffer.flip(); - nextChunk = buffer; + return ChannelBuffers.wrappedBuffer(buffer); } } - return nextChunk; - } - - public boolean hasNextChunk() - throws Exception { - return !isEndOfInput(); - } - - public Object nextChunk() - throws Exception { - ByteBuffer buffer = peekNextChuck(); - if (buffer == EOF) { - return null; - } - nextChunk = null; - return ChannelBuffers.wrappedBuffer(buffer); } - public boolean isEndOfInput() - throws Exception { - return peekNextChuck() == EOF; + public boolean isEndOfInput() throws Exception { + // called by ChunkedWriteHandler AFTER nextChunk + return endOfInput; } - public void close() - throws Exception { + public void close() throws Exception { body.close(); } - } From 1a551e3c360b8dda8b7eaf09ab336eb71d460642 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Sat, 27 Jul 2013 08:08:47 +0200 Subject: [PATCH 204/264] Backport c9331b0916e6a8764ae9b6e559a1ca11676965de --- .../java/com/ning/http/client/AsyncHttpClient.java | 11 +++++++++++ .../providers/netty/NettyAsyncHttpProvider.java | 4 ++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/ning/http/client/AsyncHttpClient.java b/src/main/java/com/ning/http/client/AsyncHttpClient.java index f8a3d9d5cc..ccc5285c17 100755 --- a/src/main/java/com/ning/http/client/AsyncHttpClient.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClient.java @@ -28,6 +28,7 @@ import java.io.Closeable; import java.io.IOException; import java.io.InputStream; +import java.lang.reflect.InvocationTargetException; import java.util.Collection; import java.util.Map; import java.util.concurrent.ExecutorService; @@ -576,6 +577,16 @@ private final static AsyncHttpProvider loadDefaultProvider(String className, Asy new Class[]{AsyncHttpClientConfig.class}).newInstance(new Object[]{config}); } catch (Throwable t) { + if (t instanceof InvocationTargetException) { + final InvocationTargetException ite = (InvocationTargetException) t; + if (logger.isErrorEnabled()) { + logger.error( + "Unable to instantiate provider {}. Trying other providers.", + className); + logger.error(ite.getCause().toString(), ite.getCause()); + } + } + // Let's try with another classloader try { Class providerClass = (Class) diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java index 04913840ee..8fcc822522 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java @@ -240,10 +240,10 @@ public NettyAsyncHttpProvider(AsyncHttpClientConfig config) { secureBootstrap = new ClientBootstrap(socketChannelFactory); webSocketBootstrap = new ClientBootstrap(socketChannelFactory); secureWebSocketBootstrap = new ClientBootstrap(socketChannelFactory); - configureNetty(); - this.config = config; + configureNetty(); + // This is dangerous as we can't catch a wrong typed ConnectionsPool ConnectionsPool cp = (ConnectionsPool) config.getConnectionsPool(); if (cp == null && config.getAllowPoolingConnection()) { From 466acd6ca4e6a1af8c1009138c868d5b22a46011 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Sat, 27 Jul 2013 08:08:58 +0200 Subject: [PATCH 205/264] Fix typos --- .../java/com/ning/http/client/async/BasicAuthTest.java | 2 +- .../ning/http/client/async/SimpleAsyncHttpClientTest.java | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/test/java/com/ning/http/client/async/BasicAuthTest.java b/src/test/java/com/ning/http/client/async/BasicAuthTest.java index 0886b887c3..00ac83840c 100644 --- a/src/test/java/com/ning/http/client/async/BasicAuthTest.java +++ b/src/test/java/com/ning/http/client/async/BasicAuthTest.java @@ -474,7 +474,7 @@ public AbstractHandler configureHandler() throws Exception { } @Test(groups = { "standalone", "default_provider" }) - public void StringBuilderBodyConsumerTest() throws Throwable { + public void stringBuilderBodyConsumerTest() throws Throwable { SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setRealmPrincipal(user).setRealmPassword(admin).setUrl(getTargetUrl()).setHeader("Content-Type", "text/html").build(); try { StringBuilder s = new StringBuilder(); diff --git a/src/test/java/com/ning/http/client/async/SimpleAsyncHttpClientTest.java b/src/test/java/com/ning/http/client/async/SimpleAsyncHttpClientTest.java index 27d1248c8a..cde839a971 100644 --- a/src/test/java/com/ning/http/client/async/SimpleAsyncHttpClientTest.java +++ b/src/test/java/com/ning/http/client/async/SimpleAsyncHttpClientTest.java @@ -40,7 +40,7 @@ public abstract class SimpleAsyncHttpClientTest extends AbstractBasicTest { private final static String MY_MESSAGE = "my message"; @Test(groups = { "standalone", "default_provider" }) - public void inpuStreamBodyConsumerTest() throws Throwable { + public void inputStreamBodyConsumerTest() throws Throwable { SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setIdleConnectionInPoolTimeoutInMs(100).setMaximumConnectionsTotal(50).setRequestTimeoutInMs(5 * 60 * 1000).setUrl(getTargetUrl()).setHeader("Content-Type", "text/html").build(); try { @@ -56,7 +56,7 @@ public void inpuStreamBodyConsumerTest() throws Throwable { } @Test(groups = { "standalone", "default_provider" }) - public void StringBuilderBodyConsumerTest() throws Throwable { + public void stringBuilderBodyConsumerTest() throws Throwable { SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setIdleConnectionInPoolTimeoutInMs(100).setMaximumConnectionsTotal(50).setRequestTimeoutInMs(5 * 60 * 1000).setUrl(getTargetUrl()).setHeader("Content-Type", "text/html").build(); try { @@ -73,7 +73,7 @@ public void StringBuilderBodyConsumerTest() throws Throwable { } @Test(groups = { "standalone", "default_provider" }) - public void ByteArrayOutputStreamBodyConsumerTest() throws Throwable { + public void byteArrayOutputStreamBodyConsumerTest() throws Throwable { SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setIdleConnectionInPoolTimeoutInMs(100).setMaximumConnectionsTotal(50).setRequestTimeoutInMs(5 * 60 * 1000).setUrl(getTargetUrl()).setHeader("Content-Type", "text/html").build(); try { @@ -90,7 +90,7 @@ public void ByteArrayOutputStreamBodyConsumerTest() throws Throwable { } @Test(groups = { "standalone", "default_provider" }) - public void RequestByteArrayOutputStreamBodyConsumerTest() throws Throwable { + public void requestByteArrayOutputStreamBodyConsumerTest() throws Throwable { SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setUrl(getTargetUrl()).build(); try { From b34094d35ee07b7da52627272de4031ff720d230 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Sat, 27 Jul 2013 23:16:04 +0200 Subject: [PATCH 206/264] Add providerClass to SimpleAsyncHttpClient.Builder, close #349 --- .../ning/http/client/SimpleAsyncHttpClient.java | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/ning/http/client/SimpleAsyncHttpClient.java b/src/main/java/com/ning/http/client/SimpleAsyncHttpClient.java index ea03362bad..45eb19794f 100644 --- a/src/main/java/com/ning/http/client/SimpleAsyncHttpClient.java +++ b/src/main/java/com/ning/http/client/SimpleAsyncHttpClient.java @@ -68,8 +68,9 @@ public class SimpleAsyncHttpClient { private final ErrorDocumentBehaviour errorDocumentBehaviour; private final SimpleAHCTransferListener listener; private final boolean derived; + private String providerClass; - private SimpleAsyncHttpClient(AsyncHttpClientConfig config, RequestBuilder requestBuilder, ThrowableHandler defaultThrowableHandler, ErrorDocumentBehaviour errorDocumentBehaviour, boolean resumeEnabled, AsyncHttpClient ahc, SimpleAHCTransferListener listener) { + private SimpleAsyncHttpClient(AsyncHttpClientConfig config, RequestBuilder requestBuilder, ThrowableHandler defaultThrowableHandler, ErrorDocumentBehaviour errorDocumentBehaviour, boolean resumeEnabled, AsyncHttpClient ahc, SimpleAHCTransferListener listener, String providerClass) { this.config = config; this.requestBuilder = requestBuilder; this.defaultThrowableHandler = defaultThrowableHandler; @@ -77,6 +78,7 @@ private SimpleAsyncHttpClient(AsyncHttpClientConfig config, RequestBuilder reque this.errorDocumentBehaviour = errorDocumentBehaviour; this.asyncHttpClient = ahc; this.listener = listener; + this.providerClass = providerClass; this.derived = ahc != null; } @@ -287,7 +289,10 @@ private Future execute(RequestBuilder rb, BodyConsumer bodyConsumer, T private AsyncHttpClient asyncHttpClient() { synchronized (config) { if (asyncHttpClient == null) { - asyncHttpClient = new AsyncHttpClient(config); + if (providerClass == null) + asyncHttpClient = new AsyncHttpClient(config); + else + asyncHttpClient = new AsyncHttpClient(providerClass, config); } } return asyncHttpClient; @@ -400,6 +405,7 @@ public final static class Builder implements DerivedBuilder { private ErrorDocumentBehaviour errorDocumentBehaviour = ErrorDocumentBehaviour.WRITE; private AsyncHttpClient ahc = null; private SimpleAHCTransferListener listener = null; + private String providerClass = null; public Builder() { requestBuilder = new RequestBuilder("GET", false); @@ -659,6 +665,11 @@ public Builder setMaxRequestRetry(int maxRequestRetry) { return this; } + public Builder setProviderClass(String providerClass) { + this.providerClass = providerClass; + return this; + } + public SimpleAsyncHttpClient build() { if (realmBuilder != null) { @@ -671,7 +682,7 @@ public SimpleAsyncHttpClient build() { configBuilder.addIOExceptionFilter(new ResumableIOExceptionFilter()); - SimpleAsyncHttpClient sc = new SimpleAsyncHttpClient(configBuilder.build(), requestBuilder, defaultThrowableHandler, errorDocumentBehaviour, enableResumableDownload, ahc, listener); + SimpleAsyncHttpClient sc = new SimpleAsyncHttpClient(configBuilder.build(), requestBuilder, defaultThrowableHandler, errorDocumentBehaviour, enableResumableDownload, ahc, listener, providerClass); return sc; } From 499b9f5dd837bf9066f3aee29b7bc715ac9cd622 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Sat, 27 Jul 2013 23:16:48 +0200 Subject: [PATCH 207/264] Fix BodyChunkedInput when Transfer-Encoding is chunked (unknown Content-Length) --- .../com/ning/http/client/providers/netty/BodyChunkedInput.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/BodyChunkedInput.java b/src/main/java/com/ning/http/client/providers/netty/BodyChunkedInput.java index 8e155f8b5f..1cf8282b2c 100644 --- a/src/main/java/com/ning/http/client/providers/netty/BodyChunkedInput.java +++ b/src/main/java/com/ning/http/client/providers/netty/BodyChunkedInput.java @@ -58,7 +58,7 @@ public Object nextChunk() throws Exception { endOfInput = true; return null; } else { - endOfInput = r == contentLength || r < chunkSize; + endOfInput = r == contentLength || r < chunkSize && contentLength > 0; buffer.flip(); return ChannelBuffers.wrappedBuffer(buffer); } From d6a907bfc037e90e5853fdf72f0bc0a2da81308f Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Sat, 27 Jul 2013 23:17:43 +0200 Subject: [PATCH 208/264] Properly set up providerClass on SimpleAsyncHttpClient based tests --- .../ning/http/client/async/BasicAuthTest.java | 6 ++++- .../async/SimpleAsyncHttpClientTest.java | 27 ++++++++++--------- .../async/grizzly/GrizzlyBasicAuthTest.java | 4 +++ .../GrizzlySimpleAsyncHttpClientTest.java | 4 +++ .../async/netty/NettyBasicAuthTest.java | 13 +++------ .../netty/NettySimpleAsyncHttpClientTest.java | 4 +++ 6 files changed, 36 insertions(+), 22 deletions(-) diff --git a/src/test/java/com/ning/http/client/async/BasicAuthTest.java b/src/test/java/com/ning/http/client/async/BasicAuthTest.java index 00ac83840c..2899074272 100644 --- a/src/test/java/com/ning/http/client/async/BasicAuthTest.java +++ b/src/test/java/com/ning/http/client/async/BasicAuthTest.java @@ -26,6 +26,7 @@ import com.ning.http.client.SimpleAsyncHttpClient; import com.ning.http.client.consumers.AppendableBodyConsumer; import com.ning.http.client.generators.InputStreamBodyGenerator; + import org.apache.log4j.ConsoleAppender; import org.apache.log4j.Level; import org.apache.log4j.Logger; @@ -48,6 +49,7 @@ import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; + import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; @@ -72,6 +74,8 @@ public abstract class BasicAuthTest extends AbstractBasicTest { protected final static String admin = "admin"; private Server server2; + + public abstract String getProviderClass(); @BeforeClass(alwaysRun = true) @Override @@ -475,7 +479,7 @@ public AbstractHandler configureHandler() throws Exception { @Test(groups = { "standalone", "default_provider" }) public void stringBuilderBodyConsumerTest() throws Throwable { - SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setRealmPrincipal(user).setRealmPassword(admin).setUrl(getTargetUrl()).setHeader("Content-Type", "text/html").build(); + SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setProviderClass(getProviderClass()).setRealmPrincipal(user).setRealmPassword(admin).setUrl(getTargetUrl()).setHeader("Content-Type", "text/html").build(); try { StringBuilder s = new StringBuilder(); Future future = client.post(new InputStreamBodyGenerator(new ByteArrayInputStream(MY_MESSAGE.getBytes())), new AppendableBodyConsumer(s)); diff --git a/src/test/java/com/ning/http/client/async/SimpleAsyncHttpClientTest.java b/src/test/java/com/ning/http/client/async/SimpleAsyncHttpClientTest.java index cde839a971..c7a0e28c25 100644 --- a/src/test/java/com/ning/http/client/async/SimpleAsyncHttpClientTest.java +++ b/src/test/java/com/ning/http/client/async/SimpleAsyncHttpClientTest.java @@ -21,6 +21,7 @@ import com.ning.http.client.generators.InputStreamBodyGenerator; import com.ning.http.client.simple.HeaderMap; import com.ning.http.client.simple.SimpleAHCTransferListener; + import org.testng.annotations.Test; import java.io.ByteArrayInputStream; @@ -38,11 +39,13 @@ public abstract class SimpleAsyncHttpClientTest extends AbstractBasicTest { private final static String MY_MESSAGE = "my message"; + + public abstract String getProviderClass(); @Test(groups = { "standalone", "default_provider" }) public void inputStreamBodyConsumerTest() throws Throwable { - SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setIdleConnectionInPoolTimeoutInMs(100).setMaximumConnectionsTotal(50).setRequestTimeoutInMs(5 * 60 * 1000).setUrl(getTargetUrl()).setHeader("Content-Type", "text/html").build(); + SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setProviderClass(getProviderClass()).setIdleConnectionInPoolTimeoutInMs(100).setMaximumConnectionsTotal(50).setRequestTimeoutInMs(5 * 60 * 1000).setUrl(getTargetUrl()).setHeader("Content-Type", "text/html").build(); try { Future future = client.post(new InputStreamBodyGenerator(new ByteArrayInputStream(MY_MESSAGE.getBytes()))); @@ -58,7 +61,7 @@ public void inputStreamBodyConsumerTest() throws Throwable { @Test(groups = { "standalone", "default_provider" }) public void stringBuilderBodyConsumerTest() throws Throwable { - SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setIdleConnectionInPoolTimeoutInMs(100).setMaximumConnectionsTotal(50).setRequestTimeoutInMs(5 * 60 * 1000).setUrl(getTargetUrl()).setHeader("Content-Type", "text/html").build(); + SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setProviderClass(getProviderClass()).setIdleConnectionInPoolTimeoutInMs(100).setMaximumConnectionsTotal(50).setRequestTimeoutInMs(5 * 60 * 1000).setUrl(getTargetUrl()).setHeader("Content-Type", "text/html").build(); try { StringBuilder s = new StringBuilder(); Future future = client.post(new InputStreamBodyGenerator(new ByteArrayInputStream(MY_MESSAGE.getBytes())), new AppendableBodyConsumer(s)); @@ -75,7 +78,7 @@ public void stringBuilderBodyConsumerTest() throws Throwable { @Test(groups = { "standalone", "default_provider" }) public void byteArrayOutputStreamBodyConsumerTest() throws Throwable { - SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setIdleConnectionInPoolTimeoutInMs(100).setMaximumConnectionsTotal(50).setRequestTimeoutInMs(5 * 60 * 1000).setUrl(getTargetUrl()).setHeader("Content-Type", "text/html").build(); + SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setProviderClass(getProviderClass()).setIdleConnectionInPoolTimeoutInMs(100).setMaximumConnectionsTotal(50).setRequestTimeoutInMs(5 * 60 * 1000).setUrl(getTargetUrl()).setHeader("Content-Type", "text/html").build(); try { ByteArrayOutputStream o = new ByteArrayOutputStream(10); Future future = client.post(new InputStreamBodyGenerator(new ByteArrayInputStream(MY_MESSAGE.getBytes())), new OutputStreamBodyConsumer(o)); @@ -92,7 +95,7 @@ public void byteArrayOutputStreamBodyConsumerTest() throws Throwable { @Test(groups = { "standalone", "default_provider" }) public void requestByteArrayOutputStreamBodyConsumerTest() throws Throwable { - SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setUrl(getTargetUrl()).build(); + SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setProviderClass(getProviderClass()).setUrl(getTargetUrl()).build(); try { ByteArrayOutputStream o = new ByteArrayOutputStream(10); Future future = client.post(new InputStreamBodyGenerator(new ByteArrayInputStream(MY_MESSAGE.getBytes())), new OutputStreamBodyConsumer(o)); @@ -111,7 +114,7 @@ public void requestByteArrayOutputStreamBodyConsumerTest() throws Throwable { */ @Test(groups = { "standalone", "default_provider" }, enabled = true) public void testPutZeroBytesFileTest() throws Throwable { - SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setIdleConnectionInPoolTimeoutInMs(100).setMaximumConnectionsTotal(50).setRequestTimeoutInMs(5 * 1000).setUrl(getTargetUrl() + "/testPutZeroBytesFileTest.txt").setHeader("Content-Type", "text/plain") + SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setProviderClass(getProviderClass()).setIdleConnectionInPoolTimeoutInMs(100).setMaximumConnectionsTotal(50).setRequestTimeoutInMs(5 * 1000).setUrl(getTargetUrl() + "/testPutZeroBytesFileTest.txt").setHeader("Content-Type", "text/plain") .build(); try { File tmpfile = File.createTempFile("testPutZeroBytesFile", ".tmp"); @@ -131,7 +134,7 @@ public void testPutZeroBytesFileTest() throws Throwable { @Test(groups = { "standalone", "default_provider" }) public void testDerive() throws Exception { - SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().build(); + SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setProviderClass(getProviderClass()).build(); SimpleAsyncHttpClient derived = client.derive().build(); try { assertNotSame(derived, client); @@ -143,7 +146,7 @@ public void testDerive() throws Exception { @Test(groups = { "standalone", "default_provider" }) public void testDeriveOverrideURL() throws Exception { - SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setUrl("http://invalid.url/").build(); + SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setProviderClass(getProviderClass()).setUrl("http://invalid.url/").build(); SimpleAsyncHttpClient derived = client.derive().setUrl(getTargetUrl()).build(); try { ByteArrayOutputStream o = new ByteArrayOutputStream(10); @@ -214,7 +217,7 @@ public void onBytesReceived(String url, long amount, long current, long total) { @Test(groups = { "standalone", "default_provider" }) public void testNullUrl() throws Exception { - SimpleAsyncHttpClient c = new SimpleAsyncHttpClient.Builder().build().derive().build(); + SimpleAsyncHttpClient c = new SimpleAsyncHttpClient.Builder().setProviderClass(getProviderClass()).build().derive().build(); try { assertTrue(true); } finally { @@ -224,7 +227,7 @@ public void testNullUrl() throws Exception { @Test(groups = { "standalone", "default_provider" }) public void testCloseDerivedValidMaster() throws Exception { - SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setUrl(getTargetUrl()).build(); + SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setProviderClass(getProviderClass()).setUrl(getTargetUrl()).build(); try { SimpleAsyncHttpClient derived = client.derive().build(); derived.get().get(); @@ -241,7 +244,7 @@ public void testCloseDerivedValidMaster() throws Exception { @Test(groups = { "standalone", "default_provider" }) public void testCloseMasterInvalidDerived() throws Exception { - SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setUrl(getTargetUrl()).build(); + SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setProviderClass(getProviderClass()).setUrl(getTargetUrl()).build(); SimpleAsyncHttpClient derived = client.derive().build(); client.close(); @@ -256,7 +259,7 @@ public void testCloseMasterInvalidDerived() throws Exception { @Test(groups = { "standalone", "default_provider" }) public void testMultiPartPut() throws Exception { - SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setUrl(getTargetUrl() + "/multipart").build(); + SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setProviderClass(getProviderClass()).setUrl(getTargetUrl() + "/multipart").build(); try { Response response = client.put(new ByteArrayPart("baPart", "fileName", "testMultiPart".getBytes("utf-8"), "application/test", "utf-8")).get(); @@ -280,7 +283,7 @@ public void testMultiPartPut() throws Exception { @Test(groups = { "standalone", "default_provider" }) public void testMultiPartPost() throws Exception { - SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setUrl(getTargetUrl() + "/multipart").build(); + SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setProviderClass(getProviderClass()).setUrl(getTargetUrl() + "/multipart").build(); try { Response response = client.post(new ByteArrayPart("baPart", "fileName", "testMultiPart".getBytes("utf-8"), "application/test", "utf-8")).get(); diff --git a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyBasicAuthTest.java b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyBasicAuthTest.java index 98323e7b28..abea45483e 100644 --- a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyBasicAuthTest.java +++ b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyBasicAuthTest.java @@ -17,6 +17,7 @@ import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.async.BasicAuthTest; import com.ning.http.client.async.ProviderUtil; +import com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProvider; public class GrizzlyBasicAuthTest extends BasicAuthTest { @@ -25,4 +26,7 @@ public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { return ProviderUtil.grizzlyProvider(config); } + public String getProviderClass() { + return GrizzlyAsyncHttpProvider.class.getName(); + } } diff --git a/src/test/java/com/ning/http/client/async/grizzly/GrizzlySimpleAsyncHttpClientTest.java b/src/test/java/com/ning/http/client/async/grizzly/GrizzlySimpleAsyncHttpClientTest.java index ccbcfbd077..291c40844c 100644 --- a/src/test/java/com/ning/http/client/async/grizzly/GrizzlySimpleAsyncHttpClientTest.java +++ b/src/test/java/com/ning/http/client/async/grizzly/GrizzlySimpleAsyncHttpClientTest.java @@ -17,6 +17,7 @@ import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.async.ProviderUtil; import com.ning.http.client.async.SimpleAsyncHttpClientTest; +import com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProvider; public class GrizzlySimpleAsyncHttpClientTest extends SimpleAsyncHttpClientTest { @@ -25,4 +26,7 @@ public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { return ProviderUtil.grizzlyProvider(config); } + public String getProviderClass() { + return GrizzlyAsyncHttpProvider.class.getName(); + } } diff --git a/src/test/java/com/ning/http/client/async/netty/NettyBasicAuthTest.java b/src/test/java/com/ning/http/client/async/netty/NettyBasicAuthTest.java index 0dc441b15d..0257412469 100644 --- a/src/test/java/com/ning/http/client/async/netty/NettyBasicAuthTest.java +++ b/src/test/java/com/ning/http/client/async/netty/NettyBasicAuthTest.java @@ -16,10 +16,7 @@ import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.async.BasicAuthTest; import com.ning.http.client.async.ProviderUtil; -import org.testng.annotations.Test; - -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeoutException; +import com.ning.http.client.providers.netty.NettyAsyncHttpProvider; public class NettyBasicAuthTest extends BasicAuthTest { @@ -27,10 +24,8 @@ public class NettyBasicAuthTest extends BasicAuthTest { public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { return ProviderUtil.nettyProvider(config); } - - @Override - @Test - public void redirectAndBasicAuthTest() throws Exception, ExecutionException, TimeoutException, InterruptedException { - super.redirectAndBasicAuthTest(); //To change body of overridden methods use File | Settings | File Templates. + + public String getProviderClass() { + return NettyAsyncHttpProvider.class.getName(); } } diff --git a/src/test/java/com/ning/http/client/async/netty/NettySimpleAsyncHttpClientTest.java b/src/test/java/com/ning/http/client/async/netty/NettySimpleAsyncHttpClientTest.java index 249e0ebbdf..c470500643 100644 --- a/src/test/java/com/ning/http/client/async/netty/NettySimpleAsyncHttpClientTest.java +++ b/src/test/java/com/ning/http/client/async/netty/NettySimpleAsyncHttpClientTest.java @@ -15,6 +15,7 @@ import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.async.SimpleAsyncHttpClientTest; +import com.ning.http.client.providers.netty.NettyAsyncHttpProvider; public class NettySimpleAsyncHttpClientTest extends SimpleAsyncHttpClientTest { @@ -28,4 +29,7 @@ public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { return null; } + public String getProviderClass() { + return NettyAsyncHttpProvider.class.getName(); + } } From 7c5fe21b7805a32fbbf8ba97bcffd467015d7d21 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Sun, 28 Jul 2013 09:39:54 +0200 Subject: [PATCH 209/264] Don't implement stringBuilderBodyConsumerTest on top of SimpleAsyncHttpClient --- .../ning/http/client/async/BasicAuthTest.java | 18 +++++++++--------- .../async/grizzly/GrizzlyBasicAuthTest.java | 5 ----- .../client/async/netty/NettyBasicAuthTest.java | 5 ----- 3 files changed, 9 insertions(+), 19 deletions(-) diff --git a/src/test/java/com/ning/http/client/async/BasicAuthTest.java b/src/test/java/com/ning/http/client/async/BasicAuthTest.java index 2899074272..9a2d0a2d29 100644 --- a/src/test/java/com/ning/http/client/async/BasicAuthTest.java +++ b/src/test/java/com/ning/http/client/async/BasicAuthTest.java @@ -23,8 +23,6 @@ import com.ning.http.client.HttpResponseStatus; import com.ning.http.client.Realm; import com.ning.http.client.Response; -import com.ning.http.client.SimpleAsyncHttpClient; -import com.ning.http.client.consumers.AppendableBodyConsumer; import com.ning.http.client.generators.InputStreamBodyGenerator; import org.apache.log4j.ConsoleAppender; @@ -75,8 +73,6 @@ public abstract class BasicAuthTest extends AbstractBasicTest { private Server server2; - public abstract String getProviderClass(); - @BeforeClass(alwaysRun = true) @Override public void setUpGlobal() throws Exception { @@ -479,15 +475,19 @@ public AbstractHandler configureHandler() throws Exception { @Test(groups = { "standalone", "default_provider" }) public void stringBuilderBodyConsumerTest() throws Throwable { - SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setProviderClass(getProviderClass()).setRealmPrincipal(user).setRealmPassword(admin).setUrl(getTargetUrl()).setHeader("Content-Type", "text/html").build(); + AsyncHttpClient client = getAsyncHttpClient(null); + try { - StringBuilder s = new StringBuilder(); - Future future = client.post(new InputStreamBodyGenerator(new ByteArrayInputStream(MY_MESSAGE.getBytes())), new AppendableBodyConsumer(s)); + AsyncHttpClient.BoundRequestBuilder r = client.preparePost(getTargetUrl()) + .setHeader("Content-Type", "text/html") + .setBody(new InputStreamBodyGenerator(new ByteArrayInputStream(MY_MESSAGE.getBytes()))) + .setRealm((new Realm.RealmBuilder()).setPrincipal(user).setPassword(admin).build()); + Future f = r.execute(); System.out.println("waiting for response"); - Response response = future.get(); + Response response = f.get(); assertEquals(response.getStatusCode(), 200); - assertEquals(s.toString(), MY_MESSAGE); + assertEquals(response.getResponseBody(), MY_MESSAGE); assertEquals(response.getStatusCode(), HttpServletResponse.SC_OK); assertNotNull(response.getHeader("X-Auth")); } finally { diff --git a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyBasicAuthTest.java b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyBasicAuthTest.java index abea45483e..7cca1aa82c 100644 --- a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyBasicAuthTest.java +++ b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyBasicAuthTest.java @@ -17,7 +17,6 @@ import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.async.BasicAuthTest; import com.ning.http.client.async.ProviderUtil; -import com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProvider; public class GrizzlyBasicAuthTest extends BasicAuthTest { @@ -25,8 +24,4 @@ public class GrizzlyBasicAuthTest extends BasicAuthTest { public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { return ProviderUtil.grizzlyProvider(config); } - - public String getProviderClass() { - return GrizzlyAsyncHttpProvider.class.getName(); - } } diff --git a/src/test/java/com/ning/http/client/async/netty/NettyBasicAuthTest.java b/src/test/java/com/ning/http/client/async/netty/NettyBasicAuthTest.java index 0257412469..feb1f6115c 100644 --- a/src/test/java/com/ning/http/client/async/netty/NettyBasicAuthTest.java +++ b/src/test/java/com/ning/http/client/async/netty/NettyBasicAuthTest.java @@ -16,7 +16,6 @@ import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.async.BasicAuthTest; import com.ning.http.client.async.ProviderUtil; -import com.ning.http.client.providers.netty.NettyAsyncHttpProvider; public class NettyBasicAuthTest extends BasicAuthTest { @@ -24,8 +23,4 @@ public class NettyBasicAuthTest extends BasicAuthTest { public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { return ProviderUtil.nettyProvider(config); } - - public String getProviderClass() { - return NettyAsyncHttpProvider.class.getName(); - } } From 3cff8f8d4a47c21476a44b6d632bd60e585baf78 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Sun, 28 Jul 2013 15:45:09 +0200 Subject: [PATCH 210/264] Set up missiing providerClass --- .../com/ning/http/client/async/SimpleAsyncHttpClientTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/ning/http/client/async/SimpleAsyncHttpClientTest.java b/src/test/java/com/ning/http/client/async/SimpleAsyncHttpClientTest.java index c7a0e28c25..f98d88eea4 100644 --- a/src/test/java/com/ning/http/client/async/SimpleAsyncHttpClientTest.java +++ b/src/test/java/com/ning/http/client/async/SimpleAsyncHttpClientTest.java @@ -198,7 +198,7 @@ public void onBytesReceived(String url, long amount, long current, long total) { } }; - SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setUrl(getTargetUrl()).setHeader("Custom", "custom").setListener(listener).build(); + SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setProviderClass(getProviderClass()).setUrl(getTargetUrl()).setHeader("Custom", "custom").setListener(listener).build(); try { ByteArrayOutputStream o = new ByteArrayOutputStream(10); From 35c04ac774c94732f39b9cfc5c984b6825df267e Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 29 Jul 2013 10:06:19 +0200 Subject: [PATCH 211/264] Make Remotely Closed exception more generic --- .../http/client/providers/netty/NettyAsyncHttpProvider.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java index 8fcc822522..b5502d4cc1 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java @@ -1402,7 +1402,7 @@ public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws if (future != null && !future.isDone() && !future.isCancelled()) { if (!remotelyClosed(ctx.getChannel(), future)) { - abort(future, new IOException("Remotely Closed " + ctx.getChannel())); + abort(future, new IOException("Remotely Closed")); } } else { closeChannel(ctx); From 223641fb5e03c5deb3de768647c229b73f5a3bec Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 29 Jul 2013 12:45:17 +0200 Subject: [PATCH 212/264] Minor clean up --- .../netty/NettyAsyncHttpProvider.java | 30 ++++++++----------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java index b5502d4cc1..db94f02313 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java @@ -152,7 +152,6 @@ import static org.jboss.netty.channel.Channels.pipeline; public class NettyAsyncHttpProvider extends SimpleChannelUpstreamHandler implements AsyncHttpProvider { - private final static String WEBSOCKET_KEY = "Sec-WebSocket-Key"; private final static String HTTP_HANDLER = "httpHandler"; protected final static String SSL_HANDLER = "sslHandler"; private final static String HTTPS = "https"; @@ -397,7 +396,7 @@ private Channel lookupInCache(URI uri, ConnectionPoolKeyStrategy connectionPoolK try { // Always make sure the channel who got cached support the proper protocol. It could - // only occurs when a HttpMethod.CONNECT is used agains a proxy that require upgrading from http to + // only occurs when a HttpMethod.CONNECT is used against a proxy that require upgrading from http to // https. return verifyChannelPipeline(channel, uri.getScheme()); } catch (Exception ex) { @@ -637,7 +636,7 @@ else if (uri.getRawQuery() != null) nettyRequest.addHeader(HttpHeaders.Names.UPGRADE, HttpHeaders.Values.WEBSOCKET); nettyRequest.addHeader(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.UPGRADE); nettyRequest.addHeader(HttpHeaders.Names.ORIGIN, "http://" + uri.getHost() + ":" + uri.getPort()); - nettyRequest.addHeader(WEBSOCKET_KEY, WebSocketUtil.getKey()); + nettyRequest.addHeader(HttpHeaders.Names.SEC_WEBSOCKET_KEY, WebSocketUtil.getKey()); nettyRequest.addHeader(HttpHeaders.Names.SEC_WEBSOCKET_VERSION, "13"); } @@ -817,10 +816,10 @@ else if (uri.getRawQuery() != null) } } else if (request.getParts() != null) { - int lenght = computeAndSetContentLength(request, nettyRequest); + int length = computeAndSetContentLength(request, nettyRequest); - if (lenght == -1) { - lenght = MAX_BUFFERED_BYTES; + if (length == -1) { + length = MAX_BUFFERED_BYTES; } MultipartRequestEntity mre = AsyncHttpProviderUtils.createMultipartRequestEntity(request.getParts(), request.getHeaders()); @@ -833,18 +832,18 @@ else if (uri.getRawQuery() != null) */ if (isSecure(uri)) { - ChannelBuffer b = ChannelBuffers.dynamicBuffer(lenght); + ChannelBuffer b = ChannelBuffers.dynamicBuffer(length); mre.writeRequest(new ChannelBufferOutputStream(b)); nettyRequest.setContent(b); } } else if (request.getEntityWriter() != null) { - int lenght = computeAndSetContentLength(request, nettyRequest); + int length = computeAndSetContentLength(request, nettyRequest); - if (lenght == -1) { - lenght = MAX_BUFFERED_BYTES; + if (length == -1) { + length = MAX_BUFFERED_BYTES; } - ChannelBuffer b = ChannelBuffers.dynamicBuffer(lenght); + ChannelBuffer b = ChannelBuffers.dynamicBuffer(length); request.getEntityWriter().writeEntity(new ChannelBufferOutputStream(b)); nettyRequest.setHeader(HttpHeaders.Names.CONTENT_LENGTH, b.writerIndex()); nettyRequest.setContent(b); @@ -1017,7 +1016,7 @@ private ListenableFuture doConnect(final Request request, final AsyncHand bootstrap.setOption("connectTimeoutMillis", config.getConnectionTimeoutInMs()); // Do no enable this with win. - if (System.getProperty("os.name").toLowerCase().indexOf("win") == -1) { + if (!System.getProperty("os.name").toLowerCase().contains("win")) { bootstrap.setOption("reuseAddress", asyncHttpProviderConfig.getProperty(REUSE_ADDRESS)); } @@ -1045,10 +1044,7 @@ private ListenableFuture doConnect(final Request request, final AsyncHand return c.future(); } - boolean directInvokation = true; - if (IN_IO_THREAD.get() && DefaultChannelFuture.isUseDeadLockChecker()) { - directInvokation = false; - } + boolean directInvokation = !(IN_IO_THREAD.get() && DefaultChannelFuture.isUseDeadLockChecker()); if (directInvokation && !asyncConnect && request.getFile() == null) { int timeOut = config.getConnectionTimeoutInMs() > 0 ? config.getConnectionTimeoutInMs() : Integer.MAX_VALUE; @@ -2338,7 +2334,7 @@ public void handle(ChannelHandlerContext ctx, MessageEvent e) throws Exception { } String accept = response.getHeader(HttpHeaders.Names.SEC_WEBSOCKET_ACCEPT); - String key = WebSocketUtil.getAcceptKey(future.getNettyRequest().getHeader(WEBSOCKET_KEY)); + String key = WebSocketUtil.getAcceptKey(future.getNettyRequest().getHeader(HttpHeaders.Names.SEC_WEBSOCKET_KEY)); if (accept == null || !accept.equals(key)) { throw new IOException(String.format("Invalid challenge. Actual: %s. Expected: %s", accept, key)); } From a29f682024b220438c55c4091010e1009e6936a3 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 29 Jul 2013 15:46:33 +0200 Subject: [PATCH 213/264] Netty provider sends parts twice over https --- .../netty/NettyAsyncHttpProvider.java | 41 ++++--------------- .../multipart/MultipartRequestEntity.java | 16 -------- 2 files changed, 9 insertions(+), 48 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java index db94f02313..9261b43e06 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java @@ -467,8 +467,11 @@ protected final void writeRequest(final Channel channel, final AsyncHttpClie } else { nettyRequest.setHeader(HttpHeaders.Names.TRANSFER_ENCODING, HttpHeaders.Values.CHUNKED); } - } else { - body = null; + + } else if (future.getRequest().getParts() != null) { + String contentType = nettyRequest.getHeader(HttpHeaders.Names.CONTENT_TYPE); + String length = nettyRequest.getHeader(HttpHeaders.Names.CONTENT_LENGTH); + body = new MultipartBody(future.getRequest().getParts(), contentType, length); } } @@ -512,7 +515,7 @@ protected final void writeRequest(final Channel channel, final AsyncHttpClie ChannelFuture writeFuture; if (ssl) { - writeFuture = channel.write(new ChunkedFile(raf, 0, fileLength, 8192)); + writeFuture = channel.write(new ChunkedFile(raf, 0, fileLength, MAX_BUFFERED_BYTES)); } else { final FileRegion region = new OptimizedFileRegion(raf, 0, fileLength); writeFuture = channel.write(region); @@ -536,15 +539,7 @@ public void operationComplete(ChannelFuture cf) { } throw ex; } - } else if (body != null || future.getRequest().getParts() != null) { - /** - * TODO: AHC-78: SSL + zero copy isn't supported by the MultiPart class and pretty complex to implements. - */ - if (future.getRequest().getParts() != null) { - String contentType = nettyRequest.getHeader(HttpHeaders.Names.CONTENT_TYPE); - String length = nettyRequest.getHeader(HttpHeaders.Names.CONTENT_LENGTH); - body = new MultipartBody(future.getRequest().getParts(), contentType, length); - } + } else if (body != null) { ChannelFuture writeFuture; if (!ssl && body instanceof RandomAccessBody) { @@ -816,28 +811,13 @@ else if (uri.getRawQuery() != null) } } else if (request.getParts() != null) { - int length = computeAndSetContentLength(request, nettyRequest); - - if (length == -1) { - length = MAX_BUFFERED_BYTES; - } - MultipartRequestEntity mre = AsyncHttpProviderUtils.createMultipartRequestEntity(request.getParts(), request.getHeaders()); nettyRequest.setHeader(HttpHeaders.Names.CONTENT_TYPE, mre.getContentType()); nettyRequest.setHeader(HttpHeaders.Names.CONTENT_LENGTH, String.valueOf(mre.getContentLength())); - /** - * TODO: AHC-78: SSL + zero copy isn't supported by the MultiPart class and pretty complex to implements. - */ - - if (isSecure(uri)) { - ChannelBuffer b = ChannelBuffers.dynamicBuffer(length); - mre.writeRequest(new ChannelBufferOutputStream(b)); - nettyRequest.setContent(b); - } } else if (request.getEntityWriter() != null) { - int length = computeAndSetContentLength(request, nettyRequest); + int length = getPredefinedContentLength(request, nettyRequest); if (length == -1) { length = MAX_BUFFERED_BYTES; @@ -1626,15 +1606,12 @@ protected static boolean abortOnWriteCloseException(Throwable cause) { return false; } - private final static int computeAndSetContentLength(Request request, HttpRequest r) { + private final static int getPredefinedContentLength(Request request, HttpRequest r) { int length = (int) request.getContentLength(); if (length == -1 && r.getHeader(HttpHeaders.Names.CONTENT_LENGTH) != null) { length = Integer.valueOf(r.getHeader(HttpHeaders.Names.CONTENT_LENGTH)); } - if (length >= 0) { - r.setHeader(HttpHeaders.Names.CONTENT_LENGTH, String.valueOf(length)); - } return length; } diff --git a/src/main/java/com/ning/http/multipart/MultipartRequestEntity.java b/src/main/java/com/ning/http/multipart/MultipartRequestEntity.java index 545f3a68ef..673a58c017 100644 --- a/src/main/java/com/ning/http/multipart/MultipartRequestEntity.java +++ b/src/main/java/com/ning/http/multipart/MultipartRequestEntity.java @@ -125,20 +125,10 @@ public boolean isRepeatable() { return true; } - /* - * (non-Javadoc) - * - * @see org.apache.commons.httpclient.methods.RequestEntity#writeRequest(java.io.OutputStream) - */ public void writeRequest(OutputStream out) throws IOException { Part.sendParts(out, parts, multipartBoundary); } - /* - * (non-Javadoc) - * - * @see org.apache.commons.httpclient.methods.RequestEntity#getContentLength() - */ public long getContentLength() { try { return Part.getLengthOfParts(parts, multipartBoundary); @@ -148,13 +138,7 @@ public long getContentLength() { } } - /* - * (non-Javadoc) - * - * @see org.apache.commons.httpclient.methods.RequestEntity#getContentType() - */ public String getContentType() { return contentType; } } - From e8d76624d3bf022e3601d0ed65c427afc338b0d8 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 29 Jul 2013 16:29:29 +0200 Subject: [PATCH 214/264] Don't compute SSLContext over and over again --- src/main/java/com/ning/http/util/SslUtils.java | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/ning/http/util/SslUtils.java b/src/main/java/com/ning/http/util/SslUtils.java index dc5f2643e8..9fc62cf926 100644 --- a/src/main/java/com/ning/http/util/SslUtils.java +++ b/src/main/java/com/ning/http/util/SslUtils.java @@ -35,6 +35,8 @@ */ public class SslUtils { + private static SSLContext context = null; + public static SSLEngine getSSLEngine() throws GeneralSecurityException, IOException { SSLEngine engine = null; @@ -50,12 +52,16 @@ public static SSLEngine getSSLEngine() public static SSLContext getSSLContext() throws GeneralSecurityException, IOException { - SSLConfig config = new SSLConfig(); - if (config.keyStoreLocation == null || config.trustStoreLocation == null) { - return getLooseSSLContext(); - } else { - return getStrictSSLContext(config); + if (context == null) { + SSLConfig config = new SSLConfig(); + if (config.keyStoreLocation == null + || config.trustStoreLocation == null) { + context = getLooseSSLContext(); + } else { + context = getStrictSSLContext(config); + } } + return context; } static SSLContext getStrictSSLContext(SSLConfig config) From 07835c4ac26d3facd2621faccabc26aa04636d63 Mon Sep 17 00:00:00 2001 From: Ryan Lubke Date: Mon, 29 Jul 2013 11:11:25 -0700 Subject: [PATCH 215/264] Fix some recent test failures. --- .../http/client/async/SimpleAsyncHttpClientTest.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/test/java/com/ning/http/client/async/SimpleAsyncHttpClientTest.java b/src/test/java/com/ning/http/client/async/SimpleAsyncHttpClientTest.java index f98d88eea4..1f8a279252 100644 --- a/src/test/java/com/ning/http/client/async/SimpleAsyncHttpClientTest.java +++ b/src/test/java/com/ning/http/client/async/SimpleAsyncHttpClientTest.java @@ -28,6 +28,7 @@ import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; +import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import static junit.framework.Assert.assertTrue; @@ -253,7 +254,14 @@ public void testCloseMasterInvalidDerived() throws Exception { derived.get().get(); fail("Expected closed AHC"); } catch (IOException e) { - // expected + // expected -- Seems to me that this behavior conflicts with the requirements of Future.get() + } catch (ExecutionException ee) { + if (!(ee.getCause() instanceof IOException)) { + fail("ExecutionException thrown, but the cause was not an instance of IOException."); + } + } catch (Throwable t) { + fail("Unexpected Exception thrown: " + t.toString()); + t.printStackTrace(); } } From dbd4cbfef168f01b050f7ba66c89b744b84656e2 Mon Sep 17 00:00:00 2001 From: Ryan Lubke Date: Mon, 29 Jul 2013 11:33:13 -0700 Subject: [PATCH 216/264] Fix final "Grizzly" failure. Problem was the stream was only being reset when working around a Netty issue. --- .../http/client/generators/InputStreamBodyGenerator.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/ning/http/client/generators/InputStreamBodyGenerator.java b/src/main/java/com/ning/http/client/generators/InputStreamBodyGenerator.java index 99ae7fe9d8..799a74615a 100644 --- a/src/main/java/com/ning/http/client/generators/InputStreamBodyGenerator.java +++ b/src/main/java/com/ning/http/client/generators/InputStreamBodyGenerator.java @@ -43,7 +43,7 @@ public InputStreamBodyGenerator(InputStream inputStream) { if (inputStream.markSupported()) { inputStream.mark(0); } else { - logger.info("inputStream.markSupported() not supported. Some features will not works"); + logger.info("inputStream.markSupported() not supported. Some features will not work."); } } @@ -117,6 +117,10 @@ public long read(ByteBuffer buffer) throws IOException { } else { if (read > 0) { buffer.put(chunk, 0, read); + } else { + if (inputStream.markSupported()) { + inputStream.reset(); + } } } return read; From e8cce5fa15f6fc07604940c794db5feee4739548 Mon Sep 17 00:00:00 2001 From: Ryan Lubke Date: Mon, 29 Jul 2013 11:42:13 -0700 Subject: [PATCH 217/264] Update to Grizzly 2.3.4. --- pom.xml | 2 +- .../com/ning/http/client/providers/grizzly/GrizzlyResponse.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 1f541c047a..982fd0e3ae 100644 --- a/pom.xml +++ b/pom.xml @@ -489,7 +489,7 @@ org.glassfish.grizzly grizzly-websockets - 2.3.3 + 2.3.4 true diff --git a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponse.java b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponse.java index 193718a333..93c434e960 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponse.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponse.java @@ -267,7 +267,7 @@ public List getCookies() { List values = headers.getHeaders().get("set-cookie"); if (isNonEmpty(values)) { CookiesBuilder.ServerCookiesBuilder builder = - new CookiesBuilder.ServerCookiesBuilder(false); + new CookiesBuilder.ServerCookiesBuilder(false, true); for (String header : values) { builder.parse(header); } From 1f88f28771e6b372718da6a5b5365ea1ae04df7d Mon Sep 17 00:00:00 2001 From: Ryan Lubke Date: Tue, 30 Jul 2013 11:11:34 -0700 Subject: [PATCH 218/264] Fix test case and Grizzly impl. --- .../client/providers/grizzly/GrizzlyAsyncHttpProvider.java | 3 +++ .../ning/http/client/async/SimpleAsyncHttpClientTest.java | 7 ------- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java index 4e367b1465..85b0438bd2 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java @@ -200,6 +200,9 @@ public GrizzlyAsyncHttpProvider(final AsyncHttpClientConfig clientConfig) { public ListenableFuture execute(final Request request, final AsyncHandler handler) throws IOException { + if (clientTransport.isStopped()) { + throw new IOException("AsyncHttpClient has been closed."); + } final ProxyServer proxy = ProxyUtils.getProxyServer(clientConfig, request); final GrizzlyResponseFuture future = new GrizzlyResponseFuture(this, request, handler, proxy); future.setDelegate(SafeFutureImpl.create()); diff --git a/src/test/java/com/ning/http/client/async/SimpleAsyncHttpClientTest.java b/src/test/java/com/ning/http/client/async/SimpleAsyncHttpClientTest.java index 1f8a279252..f2874cf73c 100644 --- a/src/test/java/com/ning/http/client/async/SimpleAsyncHttpClientTest.java +++ b/src/test/java/com/ning/http/client/async/SimpleAsyncHttpClientTest.java @@ -255,13 +255,6 @@ public void testCloseMasterInvalidDerived() throws Exception { fail("Expected closed AHC"); } catch (IOException e) { // expected -- Seems to me that this behavior conflicts with the requirements of Future.get() - } catch (ExecutionException ee) { - if (!(ee.getCause() instanceof IOException)) { - fail("ExecutionException thrown, but the cause was not an instance of IOException."); - } - } catch (Throwable t) { - fail("Unexpected Exception thrown: " + t.toString()); - t.printStackTrace(); } } From f2be57b3c2a85f021ca0b5a1b1bee69ac94d89aa Mon Sep 17 00:00:00 2001 From: jfarcand Date: Tue, 30 Jul 2013 18:00:28 -0400 Subject: [PATCH 219/264] [maven-release-plugin] prepare release async-http-client-1.7.19 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 982fd0e3ae..678721e211 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.7.19-SNAPSHOT + 1.7.19 jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From baa150b5cb73f03c1be1ad1d42a9552c477d79ff Mon Sep 17 00:00:00 2001 From: jfarcand Date: Tue, 30 Jul 2013 18:00:56 -0400 Subject: [PATCH 220/264] [maven-release-plugin] prepare for next development iteration --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 678721e211..a87b9401de 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.7.19 + 1.7.20-SNAPSHOT jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From 1d965d7565ad8de0cd18ffb918243d0687cc21b3 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 2 Aug 2013 09:46:50 +0200 Subject: [PATCH 221/264] Minor clean up --- .../netty/NettyAsyncHttpProvider.java | 30 ++++++++++--------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java index 9261b43e06..ccf0c8b2fa 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java @@ -199,8 +199,8 @@ public boolean remove(Object o) { private final Protocol webSocketProtocol = new WebSocketProtocol(); private static boolean isNTLM(List auth) { - return isNonEmpty(auth) && auth.get(0).startsWith("NTLM"); - } + return isNonEmpty(auth) && auth.get(0).startsWith("NTLM"); + } public NettyAsyncHttpProvider(AsyncHttpClientConfig config) { @@ -923,7 +923,7 @@ private ListenableFuture doConnect(final Request request, final AsyncHand HttpRequest nettyRequest = null; if (f == null) { - nettyRequest = buildRequest(config, request, uri, false, bufferedBytes, proxyServer); + nettyRequest = buildRequest(config, request, uri, false, bufferedBytes, proxyServer); f = newFuture(uri, request, asyncHandler, nettyRequest, config, this, proxyServer); } else { nettyRequest = buildRequest(config, request, uri, f.isConnectAllowed(), bufferedBytes, proxyServer); @@ -1168,9 +1168,9 @@ private Realm kerberosChallenge(List proxyAuth, Request request, ProxySe } private void addType3NTLMAuthorizationHeader( - List auth, - FluentCaseInsensitiveStringsMap headers, - String username, + List auth, + FluentCaseInsensitiveStringsMap headers, + String username, String password, String domain, String workstation) throws NTLMEngineException { @@ -1202,7 +1202,7 @@ private Realm ntlmChallenge(List wwwAuth, Request request, ProxyServer p newRealm = new Realm.RealmBuilder().clone(realm).setScheme(realm.getAuthScheme()).setUri(uri.getRawPath()).setMethodName(request.getMethod()).setNtlmMessageType2Received(true).build(); future.getAndSetAuth(false); } else { - addType3NTLMAuthorizationHeader(wwwAuth, headers, principal, password, ntlmDomain, ntlmHost); + addType3NTLMAuthorizationHeader(wwwAuth, headers, principal, password, ntlmDomain, ntlmHost); Realm.RealmBuilder realmBuilder; Realm.AuthScheme authScheme; @@ -1377,7 +1377,7 @@ public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws p.onClose(ctx, e); if (future != null && !future.isDone() && !future.isCancelled()) { - if (!remotelyClosed(ctx.getChannel(), future)) { + if (remotelyClosed(ctx.getChannel(), future)) { abort(future, new IOException("Remotely Closed")); } } else { @@ -1389,18 +1389,20 @@ public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws protected boolean remotelyClosed(Channel channel, NettyResponseFuture future) { if (isClose.get()) { - return false; + return true; } connectionsPool.removeAll(channel); - if (future == null && channel.getPipeline().getContext(NettyAsyncHttpProvider.class).getAttachment() instanceof NettyResponseFuture) { - future = (NettyResponseFuture) channel.getPipeline().getContext(NettyAsyncHttpProvider.class).getAttachment(); + if (future == null) { + Object attachment = channel.getPipeline().getContext(NettyAsyncHttpProvider.class).getAttachment(); + if (attachment instanceof NettyResponseFuture) + future = (NettyResponseFuture) attachment; } if (future == null || future.cannotBeReplay()) { log.debug("Unable to recover future {}\n", future); - return false; + return true; } future.setState(NettyResponseFuture.STATE.RECONNECTED); @@ -1409,13 +1411,13 @@ protected boolean remotelyClosed(Channel channel, NettyResponseFuture future) try { nextRequest(future.getRequest(), future); - return true; + return false; } catch (IOException iox) { future.setState(NettyResponseFuture.STATE.CLOSED); future.abort(iox); log.error("Remotely Closed, unable to recover", iox); + return true; } - return false; } private void markAsDone(final NettyResponseFuture future, final ChannelHandlerContext ctx) throws MalformedURLException { From 95877bd32e500559d17c070d88ab5ccb35b098c1 Mon Sep 17 00:00:00 2001 From: Chad Selph Date: Mon, 12 Aug 2013 02:44:54 -0700 Subject: [PATCH 222/264] fix 4 byte characters in UTF8UrlEncoder --- .../java/com/ning/http/util/UTF8UrlEncoder.java | 16 ++++++++++------ .../com/ning/http/util/TestUTF8UrlCodec.java | 11 +++++++++++ 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/ning/http/util/UTF8UrlEncoder.java b/src/main/java/com/ning/http/util/UTF8UrlEncoder.java index a7d463f4fc..3e24f1c2d7 100644 --- a/src/main/java/com/ning/http/util/UTF8UrlEncoder.java +++ b/src/main/java/com/ning/http/util/UTF8UrlEncoder.java @@ -24,7 +24,7 @@ public class UTF8UrlEncoder { /** * Encoding table used for figuring out ascii characters that must be escaped - * (all non-Ascii characers need to be encoded anyway) + * (all non-Ascii characters need to be encoded anyway) */ private final static int[] SAFE_ASCII = new int[128]; @@ -58,11 +58,11 @@ public static String encode(String input) { public static StringBuilder appendEncoded(StringBuilder sb, String input) { final int[] safe = SAFE_ASCII; - for (int i = 0, len = input.length(); i < len; ++i) { - char c = input.charAt(i); + for (int c, i = 0, len = input.length(); i < len; i+= Character.charCount(c)) { + c = input.codePointAt(i); if (c <= 127) { if (safe[c] != 0) { - sb.append(c); + sb.append((char) c); } else { appendSingleByteEncoded(sb, c); } @@ -86,14 +86,18 @@ private final static void appendSingleByteEncoded(StringBuilder sb, int value) { } private final static void appendMultiByteEncoded(StringBuilder sb, int value) { - // two or three bytes? (ignoring surrogate pairs for now, which would yield 4 bytes) if (value < 0x800) { appendSingleByteEncoded(sb, (0xc0 | (value >> 6))); appendSingleByteEncoded(sb, (0x80 | (value & 0x3f))); - } else { + } else if (value < 0x10000) { appendSingleByteEncoded(sb, (0xe0 | (value >> 12))); appendSingleByteEncoded(sb, (0x80 | ((value >> 6) & 0x3f))); appendSingleByteEncoded(sb, (0x80 | (value & 0x3f))); + } else { + appendSingleByteEncoded(sb, (0xf0 | (value >> 18))); + appendSingleByteEncoded(sb, (0x80 | (value >> 12) & 0x3f)); + appendSingleByteEncoded(sb, (0x80 | (value >> 6) & 0x3f)); + appendSingleByteEncoded(sb, (0x80 | (value & 0x3f))); } } diff --git a/src/test/java/com/ning/http/util/TestUTF8UrlCodec.java b/src/test/java/com/ning/http/util/TestUTF8UrlCodec.java index e675a1a611..a0cd0f3c34 100644 --- a/src/test/java/com/ning/http/util/TestUTF8UrlCodec.java +++ b/src/test/java/com/ning/http/util/TestUTF8UrlCodec.java @@ -27,4 +27,15 @@ public void testBasics() Assert.assertEquals(UTF8UrlEncoder.encode("a&b"), "a%26b"); Assert.assertEquals(UTF8UrlEncoder.encode("a+b"), "a%2Bb"); } + + @Test(groups="fast") + public void testNonBmp() + { + // Plane 1 + Assert.assertEquals(UTF8UrlEncoder.encode("\uD83D\uDCA9"), "%F0%9F%92%A9"); + // Plane 2 + Assert.assertEquals(UTF8UrlEncoder.encode("\ud84c\uddc8 \ud84f\udfef"), "%F0%A3%87%88%20%F0%A3%BF%AF"); + // Plane 15 + Assert.assertEquals(UTF8UrlEncoder.encode("\udb80\udc01"), "%F3%B0%80%81"); + } } From e61a9c09096dad69fa5f8479e7e59ff284e25cd4 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Sun, 25 Aug 2013 10:06:01 +0200 Subject: [PATCH 223/264] Force encoding when using String.toLower/UpperCase, close #361 --- .../client/FluentCaseInsensitiveStringsMap.java | 11 ++++++----- .../grizzly/GrizzlyAsyncHttpProvider.java | 8 +++++--- .../providers/netty/NettyAsyncHttpProvider.java | 3 ++- src/main/java/com/ning/http/util/ProxyUtils.java | 5 +++-- .../http/client/async/AsyncStreamHandlerTest.java | 15 ++++++++------- 5 files changed, 24 insertions(+), 18 deletions(-) diff --git a/src/main/java/com/ning/http/client/FluentCaseInsensitiveStringsMap.java b/src/main/java/com/ning/http/client/FluentCaseInsensitiveStringsMap.java index 35f200bc66..16ad85572a 100644 --- a/src/main/java/com/ning/http/client/FluentCaseInsensitiveStringsMap.java +++ b/src/main/java/com/ning/http/client/FluentCaseInsensitiveStringsMap.java @@ -26,6 +26,7 @@ import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Set; @@ -105,7 +106,7 @@ public FluentCaseInsensitiveStringsMap add(String key, Collection values List nonNullValues = fetchValues(values); if (nonNullValues != null) { - String lcKey = key.toLowerCase(); + String lcKey = key.toLowerCase(Locale.ENGLISH); String realKey = keyLookup.get(lcKey); List curValues = null; @@ -177,7 +178,7 @@ public FluentCaseInsensitiveStringsMap replace(final String key, final String... public FluentCaseInsensitiveStringsMap replace(final String key, final Collection values) { if (key != null) { List nonNullValues = fetchValues(values); - String lcKkey = key.toLowerCase(); + String lcKkey = key.toLowerCase(Locale.ENGLISH); String realKey = keyLookup.get(lcKkey); if (nonNullValues == null) { @@ -259,7 +260,7 @@ public void putAll(Map> values) { */ public FluentCaseInsensitiveStringsMap delete(String key) { if (key != null) { - String lcKey = key.toLowerCase(); + String lcKey = key.toLowerCase(Locale.ENGLISH); String realKey = keyLookup.remove(lcKey); if (realKey != null) { @@ -368,7 +369,7 @@ public boolean isEmpty() { */ /* @Override */ public boolean containsKey(Object key) { - return key == null ? false : keyLookup.containsKey(key.toString().toLowerCase()); + return key == null ? false : keyLookup.containsKey(key.toString().toLowerCase(Locale.ENGLISH)); } /** @@ -433,7 +434,7 @@ public List get(Object key) { return null; } - String lcKey = key.toString().toLowerCase(); + String lcKey = key.toString().toLowerCase(Locale.ENGLISH); String realKey = keyLookup.get(lcKey); if (realKey == null) { diff --git a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java index 85b0438bd2..3a7a440d3e 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java @@ -129,6 +129,7 @@ import java.util.Collection; import java.util.HashMap; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; @@ -534,7 +535,7 @@ void timeout(final Connection c) { static int getPort(final URI uri, final int p) { int port = p; if (port == -1) { - final String protocol = uri.getScheme().toLowerCase(); + final String protocol = uri.getScheme().toLowerCase(Locale.ENGLISH); if ("http".equals(protocol) || "ws".equals(protocol)) { port = 80; } else if ("https".equals(protocol) || "wss".equals(protocol)) { @@ -1486,14 +1487,15 @@ public boolean handleStatus(final HttpResponsePacket responsePacket, .setUsePreemptiveAuth(true) .parseWWWAuthenticateHeader(auth) .build(); - if (auth.toLowerCase().startsWith("basic")) { + String lowerCaseAuth = auth.toLowerCase(Locale.ENGLISH); + if (lowerCaseAuth.startsWith("basic")) { req.getHeaders().remove(Header.Authorization.toString()); try { req.getHeaders().add(Header.Authorization.toString(), AuthenticatorUtils.computeBasicAuthentication(realm)); } catch (UnsupportedEncodingException ignored) { } - } else if (auth.toLowerCase().startsWith("digest")) { + } else if (lowerCaseAuth.startsWith("digest")) { req.getHeaders().remove(Header.Authorization.toString()); try { req.getHeaders().add(Header.Authorization.toString(), diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java index ccf0c8b2fa..4a0e4ac4d2 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java @@ -122,6 +122,7 @@ import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.List; +import java.util.Locale; import java.util.Map.Entry; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; @@ -996,7 +997,7 @@ private ListenableFuture doConnect(final Request request, final AsyncHand bootstrap.setOption("connectTimeoutMillis", config.getConnectionTimeoutInMs()); // Do no enable this with win. - if (!System.getProperty("os.name").toLowerCase().contains("win")) { + if (!System.getProperty("os.name").toLowerCase(Locale.ENGLISH).contains("win")) { bootstrap.setOption("reuseAddress", asyncHttpProviderConfig.getProperty(REUSE_ADDRESS)); } diff --git a/src/main/java/com/ning/http/util/ProxyUtils.java b/src/main/java/com/ning/http/util/ProxyUtils.java index 4f9b3c4240..8e859b12ba 100644 --- a/src/main/java/com/ning/http/util/ProxyUtils.java +++ b/src/main/java/com/ning/http/util/ProxyUtils.java @@ -20,6 +20,7 @@ import com.ning.http.client.Request; import java.util.List; +import java.util.Locale; import java.util.Properties; /** @@ -100,14 +101,14 @@ public static boolean avoidProxy(final ProxyServer proxyServer, final Request re */ public static boolean avoidProxy(final ProxyServer proxyServer, final String target) { if (proxyServer != null) { - final String targetHost = target.toLowerCase(); + final String targetHost = target.toLowerCase(Locale.ENGLISH); List nonProxyHosts = proxyServer.getNonProxyHosts(); if (nonProxyHosts != null) { for (String nonProxyHost : nonProxyHosts) { if (nonProxyHost.startsWith("*") && nonProxyHost.length() > 1 - && targetHost.endsWith(nonProxyHost.substring(1).toLowerCase())) { + && targetHost.endsWith(nonProxyHost.substring(1).toLowerCase(Locale.ENGLISH))) { return true; } else if (nonProxyHost.equalsIgnoreCase(targetHost)) { return true; diff --git a/src/test/java/com/ning/http/client/async/AsyncStreamHandlerTest.java b/src/test/java/com/ning/http/client/async/AsyncStreamHandlerTest.java index 00c1f00726..ad78d7b664 100644 --- a/src/test/java/com/ning/http/client/async/AsyncStreamHandlerTest.java +++ b/src/test/java/com/ning/http/client/async/AsyncStreamHandlerTest.java @@ -29,6 +29,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.HashMap; +import java.util.Locale; import java.util.Map; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Future; @@ -53,7 +54,7 @@ public STATE onHeadersReceived(HttpResponseHeaders content) throws Exception { try { FluentCaseInsensitiveStringsMap h = content.getHeaders(); Assert.assertNotNull(h); - Assert.assertEquals(h.getJoinedValue("content-type", ", ").toLowerCase(), UTF8); + Assert.assertEquals(h.getJoinedValue("content-type", ", ").toLowerCase(Locale.ENGLISH), UTF8); return STATE.ABORT; } finally { l.countDown(); @@ -95,7 +96,7 @@ public void asyncStreamPOSTTest() throws Throwable { public STATE onHeadersReceived(HttpResponseHeaders content) throws Exception { FluentCaseInsensitiveStringsMap h = content.getHeaders(); Assert.assertNotNull(h); - Assert.assertEquals(h.getJoinedValue("content-type", ", ").toLowerCase(), UTF8); + Assert.assertEquals(h.getJoinedValue("content-type", ", ").toLowerCase(Locale.ENGLISH), UTF8); return STATE.CONTINUE; } @@ -144,7 +145,7 @@ public void asyncStreamInterruptTest() throws Throwable { public STATE onHeadersReceived(HttpResponseHeaders content) throws Exception { FluentCaseInsensitiveStringsMap h = content.getHeaders(); Assert.assertNotNull(h); - Assert.assertEquals(h.getJoinedValue("content-type", ", ").toLowerCase(), UTF8); + Assert.assertEquals(h.getJoinedValue("content-type", ", ").toLowerCase(Locale.ENGLISH), UTF8); return STATE.ABORT; } @@ -186,7 +187,7 @@ public void asyncStreamFutureTest() throws Throwable { public STATE onHeadersReceived(HttpResponseHeaders content) throws Exception { FluentCaseInsensitiveStringsMap h = content.getHeaders(); Assert.assertNotNull(h); - Assert.assertEquals(h.getJoinedValue("content-type", ", ").toLowerCase(), UTF8); + Assert.assertEquals(h.getJoinedValue("content-type", ", ").toLowerCase(Locale.ENGLISH), UTF8); return STATE.CONTINUE; } @@ -272,7 +273,7 @@ public void asyncStreamReusePOSTTest() throws Throwable { public STATE onHeadersReceived(HttpResponseHeaders content) throws Exception { FluentCaseInsensitiveStringsMap h = content.getHeaders(); Assert.assertNotNull(h); - Assert.assertEquals(h.getJoinedValue("content-type", ", ").toLowerCase(), UTF8); + Assert.assertEquals(h.getJoinedValue("content-type", ", ").toLowerCase(Locale.ENGLISH), UTF8); return STATE.CONTINUE; } @@ -307,7 +308,7 @@ public String onCompleted() throws Exception { public STATE onHeadersReceived(HttpResponseHeaders content) throws Exception { FluentCaseInsensitiveStringsMap h = content.getHeaders(); Assert.assertNotNull(h); - Assert.assertEquals(h.getJoinedValue("content-type", ", ").toLowerCase(), UTF8); + Assert.assertEquals(h.getJoinedValue("content-type", ", ").toLowerCase(Locale.ENGLISH), UTF8); return STATE.CONTINUE; } @@ -349,7 +350,7 @@ public void asyncStream301WithBody() throws Throwable { public STATE onHeadersReceived(HttpResponseHeaders content) throws Exception { FluentCaseInsensitiveStringsMap h = content.getHeaders(); Assert.assertNotNull(h); - Assert.assertEquals(h.getJoinedValue("content-type", ", ").toLowerCase(), "text/html; charset=utf-8"); + Assert.assertEquals(h.getJoinedValue("content-type", ", ").toLowerCase(Locale.ENGLISH), "text/html; charset=utf-8"); return STATE.CONTINUE; } From 78ab0b0393876433eb8721095da12b18dd2f661e Mon Sep 17 00:00:00 2001 From: James Roper Date: Mon, 19 Aug 2013 14:42:49 +1000 Subject: [PATCH 224/264] Provided ability to use JDK ProxySelector Fixes #360. * Adds a useProxySelector option that tells async-http-client to use the JDK default ProxySelector. * Adds a ProxyServerSelector interface that AsyncHttpClientConfig and ProxyUtils now use. --- .../http/client/AsyncHttpClientConfig.java | 65 ++++++++++--- .../client/AsyncHttpClientConfigBean.java | 14 ++- .../ning/http/client/ProxyServerSelector.java | 26 ++++++ .../java/com/ning/http/util/ProxyUtils.java | 93 +++++++++++++++++-- src/site/apt/proxy.apt | 23 +++++ .../com/ning/http/client/async/ProxyTest.java | 81 +++++++++++++++- 6 files changed, 273 insertions(+), 29 deletions(-) create mode 100644 src/main/java/com/ning/http/client/ProxyServerSelector.java diff --git a/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java b/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java index 5227c7ca6c..a147bbe48b 100644 --- a/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java @@ -67,7 +67,7 @@ public class AsyncHttpClientConfig { protected boolean allowPoolingConnection; protected ScheduledExecutorService reaper; protected ExecutorService applicationThreadPool; - protected ProxyServer proxyServer; + protected ProxyServerSelector proxyServerSelector; protected SSLContext sslContext; protected SSLEngineFactory sslEngineFactory; protected AsyncHttpProviderConfig providerConfig; @@ -106,7 +106,7 @@ private AsyncHttpClientConfig(int maxTotalConnections, boolean keepAlive, ScheduledExecutorService reaper, ExecutorService applicationThreadPool, - ProxyServer proxyServer, + ProxyServerSelector proxyServerSelector, SSLContext sslContext, SSLEngineFactory sslEngineFactory, AsyncHttpProviderConfig providerConfig, @@ -162,7 +162,7 @@ private AsyncHttpClientConfig(int maxTotalConnections, } else { this.applicationThreadPool = applicationThreadPool; } - this.proxyServer = proxyServer; + this.proxyServerSelector = proxyServerSelector; this.useRawUrl = useRawUrl; } @@ -310,8 +310,8 @@ public ExecutorService executorService() { * * @return instance of {@link com.ning.http.client.ProxyServer} */ - public ProxyServer getProxyServer() { - return proxyServer; + public ProxyServerSelector getProxyServerSelector() { + return proxyServerSelector; } /** @@ -531,11 +531,12 @@ public static class Builder { private boolean compressionEnabled = Boolean.getBoolean(ASYNC_CLIENT + "compressionEnabled"); private String userAgent = System.getProperty(ASYNC_CLIENT + "userAgent", "NING/1.0"); private boolean useProxyProperties = Boolean.getBoolean(ASYNC_CLIENT + "useProxyProperties"); + private boolean useProxySelector = Boolean.getBoolean(ASYNC_CLIENT + "useProxySelector"); private boolean allowPoolingConnection = true; private boolean useRelativeURIsWithSSLProxies = Boolean.getBoolean(ASYNC_CLIENT + "useRelativeURIsWithSSLProxies"); private ScheduledExecutorService reaper; private ExecutorService applicationThreadPool; - private ProxyServer proxyServer = null; + private ProxyServerSelector proxyServerSelector = null; private SSLContext sslContext; private SSLEngineFactory sslEngineFactory; private AsyncHttpProviderConfig providerConfig; @@ -731,13 +732,24 @@ public Builder setExecutorService(ExecutorService applicationThreadPool) { } /** - * Set an instance of {@link com.ning.http.client.ProxyServer} used by an {@link AsyncHttpClient} + * Set an instance of {@link ProxyServerSelector} used by an {@link AsyncHttpClient} + * + * @param proxyServerSelector instance of {@link ProxyServerSelector} + * @return a {@link Builder} + */ + public Builder setProxyServerSelector(ProxyServerSelector proxyServerSelector) { + this.proxyServerSelector = proxyServerSelector; + return this; + } + + /** + * Set an instance of {@link ProxyServer} used by an {@link AsyncHttpClient} * * @param proxyServer instance of {@link com.ning.http.client.ProxyServer} * @return a {@link Builder} */ public Builder setProxyServer(ProxyServer proxyServer) { - this.proxyServer = proxyServer; + this.proxyServerSelector = ProxyUtils.createProxyServerSelector(proxyServer); return this; } @@ -938,12 +950,27 @@ public Builder setRemoveQueryParamsOnRedirect(boolean removeQueryParamOnRedirect return this; } + /** + * Sets whether AHC should use the default JDK ProxySelector to select a proxy server. + *

+ * If useProxySelector is set to true but {@link #setProxyServer(ProxyServer)} + * was used to explicitly set a proxy server, the latter is preferred. + *

+ * See http://docs.oracle.com/javase/7/docs/api/java/net/ProxySelector.html + */ + public Builder setUseProxySelector(boolean useProxySelector) { + this.useProxySelector = useProxySelector; + return this; + } + /** * Sets whether AHC should use the default http.proxy* system properties - * to obtain proxy information. + * to obtain proxy information. This differs from {@link #setUseProxySelector(boolean)} + * in that AsyncHttpClient will use its own logic to handle the system properties, + * potentially supporting other protocols that the the JDK ProxySelector doesn't. *

- * If useProxyProperties is set to true but {@link #setProxyServer(ProxyServer)} was used - * to explicitly set a proxy server, the latter is preferred. + * If useProxyProperties is set to true but {@link #setUseProxySelector(boolean)} + * was also set to true, the latter is preferred. *

* See http://download.oracle.com/javase/1.4.2/docs/guide/net/properties.html */ @@ -1036,7 +1063,7 @@ public Builder(AsyncHttpClientConfig prototype) { defaultMaxConnectionLifeTimeInMs = prototype.getMaxConnectionLifeTimeInMs(); maxDefaultRedirects = prototype.getMaxRedirects(); defaultMaxTotalConnections = prototype.getMaxTotalConnections(); - proxyServer = prototype.getProxyServer(); + proxyServerSelector = prototype.getProxyServerSelector(); realm = prototype.getRealm(); defaultRequestTimeoutInMs = prototype.getRequestTimeoutInMs(); sslContext = prototype.getSSLContext(); @@ -1100,8 +1127,16 @@ public Thread newThread(Runnable r) { throw new IllegalStateException("ExecutorServices closed"); } - if (proxyServer == null && useProxyProperties) { - proxyServer = ProxyUtils.createProxy(System.getProperties()); + if (proxyServerSelector == null && useProxySelector) { + proxyServerSelector = ProxyUtils.getJdkDefaultProxyServerSelector(); + } + + if (proxyServerSelector == null && useProxyProperties) { + proxyServerSelector = ProxyUtils.createProxyServerSelector(System.getProperties()); + } + + if (proxyServerSelector == null) { + proxyServerSelector = ProxyServerSelector.NO_PROXY_SELECTOR; } return new AsyncHttpClientConfig(defaultMaxTotalConnections, @@ -1119,7 +1154,7 @@ public Thread newThread(Runnable r) { allowPoolingConnection, reaper, applicationThreadPool, - proxyServer, + proxyServerSelector, sslContext, sslEngineFactory, providerConfig, diff --git a/src/main/java/com/ning/http/client/AsyncHttpClientConfigBean.java b/src/main/java/com/ning/http/client/AsyncHttpClientConfigBean.java index 0924d4d760..aa78c69260 100644 --- a/src/main/java/com/ning/http/client/AsyncHttpClientConfigBean.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClientConfigBean.java @@ -55,9 +55,12 @@ void configureDefaults() { compressionEnabled = Boolean.getBoolean(ASYNC_CLIENT + "compressionEnabled"); userAgent = System.getProperty(ASYNC_CLIENT + "userAgent", "NING/1.0"); + boolean useProxySelector = Boolean.getBoolean(ASYNC_CLIENT + "useProxySelector"); boolean useProxyProperties = Boolean.getBoolean(ASYNC_CLIENT + "useProxyProperties"); - if (useProxyProperties) { - proxyServer = ProxyUtils.createProxy(System.getProperties()); + if (useProxySelector) { + proxyServerSelector = ProxyUtils.getJdkDefaultProxyServerSelector(); + } else if (useProxyProperties) { + proxyServerSelector = ProxyUtils.createProxyServerSelector(System.getProperties()); } allowPoolingConnection = true; @@ -163,7 +166,12 @@ public AsyncHttpClientConfigBean setApplicationThreadPool(ExecutorService applic } public AsyncHttpClientConfigBean setProxyServer(ProxyServer proxyServer) { - this.proxyServer = proxyServer; + this.proxyServerSelector = ProxyUtils.createProxyServerSelector(proxyServer); + return this; + } + + public AsyncHttpClientConfigBean setProxyServerSelector(ProxyServerSelector proxyServerSelector) { + this.proxyServerSelector = proxyServerSelector; return this; } diff --git a/src/main/java/com/ning/http/client/ProxyServerSelector.java b/src/main/java/com/ning/http/client/ProxyServerSelector.java new file mode 100644 index 0000000000..8544e7e617 --- /dev/null +++ b/src/main/java/com/ning/http/client/ProxyServerSelector.java @@ -0,0 +1,26 @@ +package com.ning.http.client; + +import java.net.URI; + +/** + * Selector for a proxy server + */ +public interface ProxyServerSelector { + + /** + * Select a proxy server to use for the given URI. + * + * @param uri The URI to select a proxy server for. + * @return The proxy server to use, if any. May return null. + */ + ProxyServer select(URI uri); + + /** + * A selector that always selects no proxy. + */ + static final ProxyServerSelector NO_PROXY_SELECTOR = new ProxyServerSelector() { + public ProxyServer select(URI uri) { + return null; + } + }; +} diff --git a/src/main/java/com/ning/http/util/ProxyUtils.java b/src/main/java/com/ning/http/util/ProxyUtils.java index 8e859b12ba..a78cd2c0fa 100644 --- a/src/main/java/com/ning/http/util/ProxyUtils.java +++ b/src/main/java/com/ning/http/util/ProxyUtils.java @@ -12,17 +12,24 @@ */ package com.ning.http.util; -import static com.ning.http.util.MiscUtil.isNonEmpty; import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.ProxyServer; import com.ning.http.client.ProxyServer.Protocol; +import com.ning.http.client.ProxyServerSelector; import com.ning.http.client.Request; +import java.net.InetSocketAddress; +import java.net.Proxy; +import java.net.ProxySelector; +import java.net.URI; import java.util.List; import java.util.Locale; import java.util.Properties; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * Utilities for Proxy handling. * @@ -30,6 +37,8 @@ */ public class ProxyUtils { + private final static Logger log = LoggerFactory.getLogger(ProxyUtils.class); + private static final String PROPERTY_PREFIX = "com.ning.http.client.AsyncHttpClientConfig.proxy."; /** @@ -70,7 +79,10 @@ public class ProxyUtils { public static ProxyServer getProxyServer(AsyncHttpClientConfig config, Request request) { ProxyServer proxyServer = request.getProxyServer(); if (proxyServer == null) { - proxyServer = config.getProxyServer(); + ProxyServerSelector selector = config.getProxyServerSelector(); + if (selector != null) { + proxyServer = selector.select(request.getOriginalURI()); + } } return ProxyUtils.avoidProxy(proxyServer, request) ? null : proxyServer; } @@ -110,6 +122,9 @@ public static boolean avoidProxy(final ProxyServer proxyServer, final String tar if (nonProxyHost.startsWith("*") && nonProxyHost.length() > 1 && targetHost.endsWith(nonProxyHost.substring(1).toLowerCase(Locale.ENGLISH))) { return true; + } else if (nonProxyHost.endsWith("*") && nonProxyHost.length() > 1 + && targetHost.startsWith(nonProxyHost.substring(0, nonProxyHost.length() - 1).toLowerCase(Locale.ENGLISH))) { + return true; } else if (nonProxyHost.equalsIgnoreCase(targetHost)) { return true; } @@ -135,31 +150,89 @@ public static boolean avoidProxy(final ProxyServer proxyServer, final String tar * @see #PROXY_PROTOCOL * @see #PROXY_NONPROXYHOSTS */ - public static ProxyServer createProxy(Properties properties) { - String host = System.getProperty(PROXY_HOST); + public static ProxyServerSelector createProxyServerSelector(Properties properties) { + String host = properties.getProperty(PROXY_HOST); if (host != null) { - int port = Integer.valueOf(System.getProperty(PROXY_PORT, "80")); + int port = Integer.valueOf(properties.getProperty(PROXY_PORT, "80")); Protocol protocol; try { - protocol = Protocol.valueOf(System.getProperty(PROXY_PROTOCOL, "HTTP")); + protocol = Protocol.valueOf(properties.getProperty(PROXY_PROTOCOL, "HTTP")); } catch (IllegalArgumentException e) { protocol = Protocol.HTTP; } - ProxyServer proxyServer = new ProxyServer(protocol, host, port, System.getProperty(PROXY_USER), System.getProperty(PROXY_PASSWORD)); + ProxyServer proxyServer = new ProxyServer(protocol, host, port, properties.getProperty(PROXY_USER), + properties.getProperty(PROXY_PASSWORD)); - String nonProxyHosts = System.getProperties().getProperty(PROXY_NONPROXYHOSTS); + String nonProxyHosts = properties.getProperty(PROXY_NONPROXYHOSTS); if (nonProxyHosts != null) { for (String spec : nonProxyHosts.split("\\|")) { proxyServer.addNonProxyHost(spec); } } - return proxyServer; + return createProxyServerSelector(proxyServer); } - return null; + return ProxyServerSelector.NO_PROXY_SELECTOR; + } + + /** + * Get a proxy server selector based on the JDK default proxy selector. + * + * @return The proxy server selector. + */ + public static ProxyServerSelector getJdkDefaultProxyServerSelector() { + return createProxyServerSelector(ProxySelector.getDefault()); + } + + /** + * Create a proxy server selector based on the passed in JDK proxy selector. + * + * @param proxySelector The proxy selector to use. Must not be null. + * @return The proxy server selector. + */ + public static ProxyServerSelector createProxyServerSelector(final ProxySelector proxySelector) { + return new ProxyServerSelector() { + public ProxyServer select(URI uri) { + List proxies = proxySelector.select(uri); + if (proxies != null) { + // Loop through them until we find one that we know how to use + for (Proxy proxy : proxies) { + switch (proxy.type()) { + case HTTP: + if (!(proxy.address() instanceof InetSocketAddress)) { + log.warn("Don't know how to connect to address " + proxy.address()); + } else { + InetSocketAddress address = (InetSocketAddress) proxy.address(); + return new ProxyServer(Protocol.HTTP, address.getHostString(), address.getPort()); + } + case DIRECT: + return null; + default: + log.warn("ProxySelector returned proxy type that we don't know how to use: " + proxy.type()); + break; + } + } + } + return null; + } + }; + } + + /** + * Create a proxy server selector that always selects a single proxy server. + * + * @param proxyServer The proxy server to select. + * @return The proxy server selector. + */ + public static ProxyServerSelector createProxyServerSelector(final ProxyServer proxyServer) { + return new ProxyServerSelector() { + public ProxyServer select(URI uri) { + return proxyServer; + } + }; } } diff --git a/src/site/apt/proxy.apt b/src/site/apt/proxy.apt index d62a0ebb48..5424eefd75 100644 --- a/src/site/apt/proxy.apt +++ b/src/site/apt/proxy.apt @@ -61,3 +61,26 @@ Response r = responseFuture.get(); You can also set the <<>> at the <<>> level. In that case, all request will share the same proxy information. + +Using Java System Properties + + The AsyncHttpClient library supports the standard + {{{http://docs.oracle.com/javase/7/docs/api/java/net/doc-files/net-properties.html#Proxies}Java Proxy System Properties}}. + You can configure this at a global level using the <<>> method on the + <<>>, or by setting the <<>> + system property to true. + +Using JDK ProxySelectors + + The AsyncHttpClient library also supports using the default + {{{http://docs.oracle.com/javase/7/docs/api/java/net/ProxySelector.html}JDK ProxySelector}}. This allows for more + fine grained control over which proxies to use, for example, it can be used in combination with + {{{https://code.google.com/p/proxy-vole/}Proxy Vole}} to use OS configured proxies or to use a proxy.pac file. + + You configure this at a global level using the <<>> method on the + <<>>, or by setting the + <<>> system property to true. + + If you don't change the default JDK <<>>, this setting is very similar to the <<>> + setting, though the <<>> setting does allow more flexibility, such as the ability to use an + HTTPS proxy. diff --git a/src/test/java/com/ning/http/client/async/ProxyTest.java b/src/test/java/com/ning/http/client/async/ProxyTest.java index 385bee937f..e827ec41fe 100644 --- a/src/test/java/com/ning/http/client/async/ProxyTest.java +++ b/src/test/java/com/ning/http/client/async/ProxyTest.java @@ -16,6 +16,7 @@ package com.ning.http.client.async; import static org.testng.Assert.*; +import static org.testng.Assert.assertEquals; import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClientConfig; @@ -23,7 +24,9 @@ import com.ning.http.client.Response; import java.io.IOException; -import java.net.ConnectException; +import java.net.*; +import java.util.Arrays; +import java.util.List; import java.util.Properties; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; @@ -251,4 +254,80 @@ public void testProxyActivationProperty() throws IOException, ExecutionException System.setProperties(originalProps); } } + + @Test(groups = { "standalone", "default_provider" }) + public void testWildcardNonProxyHosts() throws IOException, ExecutionException, TimeoutException, InterruptedException { + Properties originalProps = System.getProperties(); + try { + Properties props = new Properties(); + props.putAll(originalProps); + + System.setProperties(props); + + System.setProperty("http.proxyHost", "127.0.0.1"); + System.setProperty("http.proxyPort", String.valueOf(port1)); + System.setProperty("http.nonProxyHosts", "127.*"); + + AsyncHttpClientConfig cfg = new AsyncHttpClientConfig.Builder().setUseProxyProperties(true).build(); + AsyncHttpClient client = getAsyncHttpClient(cfg); + try { + String target = "http://127.0.0.1:1234/"; + Future f = client.prepareGet(target).execute(); + try { + f.get(3, TimeUnit.SECONDS); + fail("should not be able to connect"); + } catch (ExecutionException e) { + // ok, no proxy used + } + } finally { + client.close(); + } + } finally { + System.setProperties(originalProps); + } + } + + @Test(groups = { "standalone", "default_provider" }) + public void testUseProxySelector() throws IOException, ExecutionException, TimeoutException, InterruptedException { + ProxySelector originalProxySelector = ProxySelector.getDefault(); + try { + ProxySelector.setDefault(new ProxySelector() { + public List select(URI uri) { + if (uri.getHost().equals("127.0.0.1")) { + return Arrays.asList(new Proxy(Proxy.Type.HTTP, new InetSocketAddress("127.0.0.1", port1))); + } else { + return Arrays.asList(Proxy.NO_PROXY); + } + } + + public void connectFailed(URI uri, SocketAddress sa, IOException ioe) { + } + }); + + AsyncHttpClientConfig cfg = new AsyncHttpClientConfig.Builder().setUseProxySelector(true).build(); + AsyncHttpClient client = getAsyncHttpClient(cfg); + try { + String target = "http://127.0.0.1:1234/"; + Future f = client.prepareGet(target).execute(); + Response resp = f.get(3, TimeUnit.SECONDS); + assertNotNull(resp); + assertEquals(resp.getStatusCode(), HttpServletResponse.SC_OK); + assertEquals(resp.getHeader("target"), "/"); + + target = "http://localhost:1234/"; + f = client.prepareGet(target).execute(); + try { + f.get(3, TimeUnit.SECONDS); + fail("should not be able to connect"); + } catch (ExecutionException e) { + // ok, no proxy used + } + } finally { + client.close(); + } + } finally { + ProxySelector.setDefault(originalProxySelector); + } + } + } From 4983685170be31cef08fc0ee6a8e96c78237882e Mon Sep 17 00:00:00 2001 From: Ryan Lubke Date: Thu, 29 Aug 2013 14:26:43 -0700 Subject: [PATCH 225/264] - Changes for #368. - Bump to Grizzly 2.3.5. --- pom.xml | 6 +- .../grizzly/FeedableBodyGenerator.java | 155 +++++++++++++++--- .../grizzly/GrizzlyAsyncHttpProvider.java | 13 +- 3 files changed, 145 insertions(+), 29 deletions(-) diff --git a/pom.xml b/pom.xml index a87b9401de..25246398ae 100644 --- a/pom.xml +++ b/pom.xml @@ -489,7 +489,7 @@ org.glassfish.grizzly grizzly-websockets - 2.3.4 + 2.3.5 true @@ -585,8 +585,8 @@ com/ning/http/client/providers/grizzly/*.java com/ning/http/client/async/grizzly/*.java com.ning.http.client.providers.grizzly - 1.5 - 1.5 + 1.6 + 1.6 2.12 diff --git a/src/main/java/com/ning/http/client/providers/grizzly/FeedableBodyGenerator.java b/src/main/java/com/ning/http/client/providers/grizzly/FeedableBodyGenerator.java index 4e509964db..509188552b 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/FeedableBodyGenerator.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/FeedableBodyGenerator.java @@ -18,11 +18,21 @@ import java.nio.ByteBuffer; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.ExecutionException; import java.util.concurrent.atomic.AtomicInteger; import org.glassfish.grizzly.Buffer; +import org.glassfish.grizzly.Connection; +import org.glassfish.grizzly.WriteHandler; import org.glassfish.grizzly.filterchain.FilterChainContext; import org.glassfish.grizzly.http.HttpContent; import org.glassfish.grizzly.http.HttpRequestPacket; +import org.glassfish.grizzly.impl.FutureImpl; +import org.glassfish.grizzly.utils.Futures; + +import static com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProvider.getHttpTransactionContext; +import static java.lang.Boolean.TRUE; +import static java.util.concurrent.TimeUnit.MILLISECONDS; +import static org.glassfish.grizzly.utils.Exceptions.*; /** * {@link BodyGenerator} which may return just part of the payload at the time @@ -38,49 +48,151 @@ public class FeedableBodyGenerator implements BodyGenerator { private volatile HttpRequestPacket requestPacket; private volatile FilterChainContext context; - + private volatile HttpContent.Builder contentBuilder; + + private final EmptyBody EMPTY_BODY = new EmptyBody(); + + + + // ---------------------------------------------- Methods from BodyGenerator + + @Override public Body createBody() throws IOException { - return new EmptyBody(); + return EMPTY_BODY; } - - public void feed(final Buffer buffer, final boolean isLast) - throws IOException { - queue.offer(new BodyPart(buffer, isLast)); + + + // ---------------------------------------------------------- Public Methods + + + /** + * Feeds the specified buffer. This buffer may be queued to be sent later + * or sent immediately. Note that this method may block if data is being + * fed faster than it is being consumed by the peer. + * + * The maximum duration that this method may block is dependent on + * the current value of {@link org.glassfish.grizzly.Transport#getWriteTimeout(java.util.concurrent.TimeUnit)}. + * This value can be customized by using a {@link TransportCustomizer} to + * fine-tune the transport used by the client instance. + * + * @param buffer the {@link Buffer} to feed. + * @param last flag indicating if this is the final buffer of the message. + * @throws IOException if an I/O error occurs. + * + * @see TransportCustomizer + * @see GrizzlyAsyncHttpProviderConfig#addProperty(com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProviderConfig.Property, Object) + * @see GrizzlyAsyncHttpProviderConfig.Property#TRANSPORT_CUSTOMIZER + */ + @SuppressWarnings("UnusedDeclaration") + public void feed(final Buffer buffer, final boolean last) + throws IOException { + queue.offer(new BodyPart(buffer, last)); queueSize.incrementAndGet(); if (context != null) { - flushQueue(); + flushQueue(true); } } + + + // ------------------------------------------------- Package Private Methods + void initializeAsynchronousTransfer(final FilterChainContext context, - final HttpRequestPacket requestPacket) throws IOException { + final HttpRequestPacket requestPacket) + throws IOException { this.context = context; this.requestPacket = requestPacket; - flushQueue(); + this.contentBuilder = HttpContent.builder(requestPacket); + // don't block here. If queue is full at the time of the next feed() + // call, it will block. + flushQueue(false); } - private void flushQueue() throws IOException { + + // --------------------------------------------------------- Private Methods + + + @SuppressWarnings("unchecked") + private void flushQueue(final boolean allowBlocking) throws IOException { if (queueSize.get() > 0) { synchronized(this) { + final Connection c = context.getConnection(); while(queueSize.get() > 0) { + if (allowBlocking) { + blockUntilQueueFree(c); + } final BodyPart bodyPart = queue.poll(); queueSize.decrementAndGet(); final HttpContent content = - requestPacket.httpContentBuilder() - .content(bodyPart.buffer) - .last(bodyPart.isLast) + contentBuilder.content(bodyPart.buffer) + .last(bodyPart.isLast) .build(); - context.write(content, ((!requestPacket.isCommitted()) ? - context.getTransportContext().getCompletionHandler() : - null)); - + context.write(content, + ((!requestPacket.isCommitted()) + ? context.getTransportContext() + .getCompletionHandler() + : null)); } } } } - + + /** + * This method will block if the async write queue is currently larger + * than the configured maximum. The amount of time that this method + * will block is dependent on the write timeout of the transport + * associated with the specified connection. + */ + private void blockUntilQueueFree(final Connection c) { + if (!c.canWrite()) { + final FutureImpl future = + Futures.createSafeFuture(); + + // Connection may be obtained by calling FilterChainContext.getConnection(). + c.notifyCanWrite(new WriteHandler() { + + @Override + public void onWritePossible() throws Exception { + future.result(TRUE); + } + + @Override + public void onError(Throwable t) { + future.failure(makeIOException(t)); + } + }); + + block(c, future); + } + } + + private void block(final Connection c, + final FutureImpl future) { + try { + final long writeTimeout = + c.getTransport().getWriteTimeout(MILLISECONDS); + if (writeTimeout != -1) { + future.get(writeTimeout, MILLISECONDS); + } else { + future.get(); + } + } catch (ExecutionException e) { + GrizzlyAsyncHttpProvider.HttpTransactionContext httpCtx = + getHttpTransactionContext(c); + httpCtx.abort(e.getCause()); + } catch (Exception e) { + GrizzlyAsyncHttpProvider.HttpTransactionContext httpCtx = + getHttpTransactionContext(c); + httpCtx.abort(e); + } + } + + + // ----------------------------------------------------------- Inner Classes + + private final class EmptyBody implements Body { @Override @@ -98,9 +210,14 @@ public void close() throws IOException { context.completeAndRecycle(); context = null; requestPacket = null; + contentBuilder = null; } } - + + + // ---------------------------------------------------------- Nested Classes + + private final static class BodyPart { private final boolean isLast; private final Buffer buffer; diff --git a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java index 3a7a440d3e..3b7baa2551 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java @@ -101,6 +101,7 @@ import org.glassfish.grizzly.utils.DelayedExecutor; import org.glassfish.grizzly.utils.Futures; import org.glassfish.grizzly.utils.IdleTimeoutFilter; +import org.glassfish.grizzly.websockets.ClosingFrame; import org.glassfish.grizzly.websockets.DataFrame; import org.glassfish.grizzly.websockets.HandShake; import org.glassfish.grizzly.websockets.HandshakeException; @@ -109,7 +110,6 @@ import org.glassfish.grizzly.websockets.Version; import org.glassfish.grizzly.websockets.WebSocketFilter; import org.glassfish.grizzly.websockets.WebSocketHolder; -import org.glassfish.grizzly.websockets.draft06.ClosingFrame; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -131,7 +131,6 @@ import java.util.List; import java.util.Locale; import java.util.Map; -import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Semaphore; @@ -157,7 +156,7 @@ public class GrizzlyAsyncHttpProvider implements AsyncHttpProvider { static { SEND_FILE_SUPPORT = /*configSendFileSupport()*/ false; } - private final Attribute REQUEST_STATE_ATTR = + private static final Attribute REQUEST_STATE_ATTR = Grizzly.DEFAULT_ATTRIBUTE_BUILDER.createAttribute(HttpTransactionContext.class.getName()); private final BodyHandlerFactory bodyHandlerFactory = new BodyHandlerFactory(); @@ -263,7 +262,7 @@ public void close() { try { connectionManager.destroy(); - clientTransport.stop(); + clientTransport.shutdownNow(); final ExecutorService service = clientConfig.executorService(); if (service != null) { service.shutdown(); @@ -506,7 +505,7 @@ public void updated(WriteResult result) { } - void setHttpTransactionContext(final AttributeStorage storage, + static void setHttpTransactionContext(final AttributeStorage storage, final HttpTransactionContext httpTransactionState) { if (httpTransactionState == null) { @@ -517,7 +516,7 @@ void setHttpTransactionContext(final AttributeStorage storage, } - HttpTransactionContext getHttpTransactionContext(final AttributeStorage storage) { + static HttpTransactionContext getHttpTransactionContext(final AttributeStorage storage) { return REQUEST_STATE_ATTR.get(storage); @@ -877,7 +876,7 @@ private boolean sendAsGrizzlyRequest(final Request request, if (httpCtx.isWSRequest && !httpCtx.establishingTunnel) { try { final URI wsURI = new URI(httpCtx.wsRequestURI); - httpCtx.protocolHandler = Version.DRAFT17.createHandler(true); + httpCtx.protocolHandler = Version.RFC6455.createHandler(true); httpCtx.handshake = httpCtx.protocolHandler.createHandShake(wsURI); requestPacket = (HttpRequestPacket) httpCtx.handshake.composeHeaders().getHttpHeader(); From 0ca2a274b0a439878204411af064b2a2fcbde53d Mon Sep 17 00:00:00 2001 From: Ryan Lubke Date: Thu, 29 Aug 2013 14:40:13 -0700 Subject: [PATCH 226/264] Didn't mean to commit target/source changes. --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 25246398ae..9cbcc145fd 100644 --- a/pom.xml +++ b/pom.xml @@ -585,8 +585,8 @@ com/ning/http/client/providers/grizzly/*.java com/ning/http/client/async/grizzly/*.java com.ning.http.client.providers.grizzly - 1.6 - 1.6 + 1.5 + 1.5 2.12 From b5d97efe9fe14113ea92fb1f7db192a2d090fad7 Mon Sep 17 00:00:00 2001 From: Ryan Lubke Date: Fri, 30 Aug 2013 12:06:37 -0700 Subject: [PATCH 227/264] Set async queue writer "size" to AUTO_SIZE by default. --- .../client/providers/grizzly/GrizzlyAsyncHttpProvider.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java index 3b7baa2551..f29d29cf3c 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java @@ -61,6 +61,7 @@ import org.glassfish.grizzly.FileTransfer; import org.glassfish.grizzly.Grizzly; import org.glassfish.grizzly.WriteResult; +import org.glassfish.grizzly.asyncqueue.AsyncQueueWriter; import org.glassfish.grizzly.attributes.Attribute; import org.glassfish.grizzly.attributes.AttributeStorage; import org.glassfish.grizzly.filterchain.BaseFilter; @@ -415,7 +416,8 @@ public void onTimeout(Connection connection) { doDefaultTransportConfig(); } fcb.add(new WebSocketFilter()); - clientTransport.getAsyncQueueIO().getWriter().setMaxPendingBytesPerConnection(-1); + clientTransport.getAsyncQueueIO().getWriter() + .setMaxPendingBytesPerConnection(AsyncQueueWriter.AUTO_SIZE); clientTransport.setProcessor(fcb.build()); } From 760d752dc44046c2b6a4b1e918d06633d0f58f3e Mon Sep 17 00:00:00 2001 From: Ryan Lubke Date: Fri, 30 Aug 2013 12:17:36 -0700 Subject: [PATCH 228/264] Reduce sleep to 4 seconds. Verisign is sending a Keep-Alive header with a timeout of 5 seconds. Can lead to the test failing indeterminately when the sleep was 5 seconds. --- .../java/com/ning/http/client/async/NoNullResponseTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/ning/http/client/async/NoNullResponseTest.java b/src/test/java/com/ning/http/client/async/NoNullResponseTest.java index 587b29cabc..21edc3529a 100644 --- a/src/test/java/com/ning/http/client/async/NoNullResponseTest.java +++ b/src/test/java/com/ning/http/client/async/NoNullResponseTest.java @@ -39,7 +39,7 @@ public void multipleSslRequestsWithDelayAndKeepAlive() throws Throwable { try { final BoundRequestBuilder builder = client.prepareGet(VERISIGN_HTTPS_URL); final Response response1 = builder.execute().get(); - Thread.sleep(5000); + Thread.sleep(4000); final Response response2 = builder.execute().get(); if (response2 != null) { System.out.println("Success (2nd response was not null)."); From 204092c9a0c4b33095b6e65ecdad3b4534968bce Mon Sep 17 00:00:00 2001 From: Ryan Lubke Date: Tue, 3 Sep 2013 10:15:19 -0700 Subject: [PATCH 229/264] Call setMaxPendingBytesPerConnection() at the right time. --- .../grizzly/GrizzlyAsyncHttpProvider.java | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java index f29d29cf3c..4050a8e0d5 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java @@ -403,21 +403,17 @@ public void onTimeout(Connection connection) { } fcb.add(eventFilter); fcb.add(clientFilter); - - if (providerConfig != null) { - final TransportCustomizer customizer = (TransportCustomizer) - providerConfig.getProperty(TRANSPORT_CUSTOMIZER); - if (customizer != null) { - customizer.customize(clientTransport, fcb); - } else { - doDefaultTransportConfig(); - } + clientTransport.getAsyncQueueIO().getWriter() + .setMaxPendingBytesPerConnection(AsyncQueueWriter.AUTO_SIZE); + final TransportCustomizer customizer = (TransportCustomizer) + providerConfig.getProperty(TRANSPORT_CUSTOMIZER); + if (customizer != null) { + customizer.customize(clientTransport, fcb); } else { doDefaultTransportConfig(); } fcb.add(new WebSocketFilter()); - clientTransport.getAsyncQueueIO().getWriter() - .setMaxPendingBytesPerConnection(AsyncQueueWriter.AUTO_SIZE); + clientTransport.setProcessor(fcb.build()); } From 078fd37c742b7decff4e977de17e77b6553229ea Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 4 Sep 2013 21:34:52 +0200 Subject: [PATCH 230/264] Use getHostName instead of getHostString for JDK5 compat --- src/main/java/com/ning/http/util/ProxyUtils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/ning/http/util/ProxyUtils.java b/src/main/java/com/ning/http/util/ProxyUtils.java index a78cd2c0fa..b4caab5149 100644 --- a/src/main/java/com/ning/http/util/ProxyUtils.java +++ b/src/main/java/com/ning/http/util/ProxyUtils.java @@ -207,7 +207,7 @@ public ProxyServer select(URI uri) { log.warn("Don't know how to connect to address " + proxy.address()); } else { InetSocketAddress address = (InetSocketAddress) proxy.address(); - return new ProxyServer(Protocol.HTTP, address.getHostString(), address.getPort()); + return new ProxyServer(Protocol.HTTP, address.getHostName(), address.getPort()); } case DIRECT: return null; From 93e5ad90dbb02804c0e82ad9841fb8087efce695 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 5 Sep 2013 13:33:53 +0200 Subject: [PATCH 231/264] Properly initialize AsyncHttpClientConfigBean.ioThreadMultiplier Otherwise, Netty provider will crash as worker count will be 0 --- .../java/com/ning/http/client/AsyncHttpClientConfigBean.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/ning/http/client/AsyncHttpClientConfigBean.java b/src/main/java/com/ning/http/client/AsyncHttpClientConfigBean.java index aa78c69260..a9ed1218e9 100644 --- a/src/main/java/com/ning/http/client/AsyncHttpClientConfigBean.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClientConfigBean.java @@ -54,6 +54,7 @@ void configureDefaults() { maxDefaultRedirects = Integer.getInteger(ASYNC_CLIENT + "defaultMaxRedirects", 5); compressionEnabled = Boolean.getBoolean(ASYNC_CLIENT + "compressionEnabled"); userAgent = System.getProperty(ASYNC_CLIENT + "userAgent", "NING/1.0"); + ioThreadMultiplier = Integer.getInteger(ASYNC_CLIENT + "ioThreadMultiplier", 8); boolean useProxySelector = Boolean.getBoolean(ASYNC_CLIENT + "useProxySelector"); boolean useProxyProperties = Boolean.getBoolean(ASYNC_CLIENT + "useProxyProperties"); From 4945cdb90f636698011b160f95e08a474903f610 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 5 Sep 2013 13:38:32 +0200 Subject: [PATCH 232/264] Standalone test shouldn't target http://foo.com --- .../http/client/async/AsyncProvidersBasicTest.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java b/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java index 0f849674e5..8e37eefffd 100755 --- a/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java +++ b/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java @@ -70,9 +70,9 @@ public abstract class AsyncProvidersBasicTest extends AbstractBasicTest { public void asyncProviderEncodingTest() throws Throwable { AsyncHttpClient client = getAsyncHttpClient(null); try { - Request request = new RequestBuilder("GET").setUrl("http://foo.com/foo.html?q=+%20x").build(); + Request request = new RequestBuilder("GET").setUrl(getTargetUrl() + "?q=+%20x").build(); String requestUrl = request.getUrl(); - Assert.assertEquals(requestUrl, "http://foo.com/foo.html?q=%20%20x"); + Assert.assertEquals(requestUrl, getTargetUrl() + "?q=%20%20x"); Future responseFuture = client.executeRequest(request, new AsyncCompletionHandler() { @Override public String onCompleted(Response response) throws Exception { @@ -87,7 +87,7 @@ public void onThrowable(Throwable t) { }); String url = responseFuture.get(); - Assert.assertEquals(url, "http://foo.com/foo.html?q=%20%20x"); + Assert.assertEquals(url, getTargetUrl() + "?q=%20%20x"); } finally { client.close(); } @@ -97,7 +97,7 @@ public void onThrowable(Throwable t) { public void asyncProviderEncodingTest2() throws Throwable { AsyncHttpClient client = getAsyncHttpClient(null); try { - Request request = new RequestBuilder("GET").setUrl("http://foo.com/foo.html").addQueryParameter("q", "a b").build(); + Request request = new RequestBuilder("GET").setUrl(getTargetUrl() + "").addQueryParameter("q", "a b").build(); Future responseFuture = client.executeRequest(request, new AsyncCompletionHandler() { @Override @@ -113,7 +113,7 @@ public void onThrowable(Throwable t) { }); String url = responseFuture.get(); - Assert.assertEquals(url, "http://foo.com/foo.html?q=a%20b"); + Assert.assertEquals(url, getTargetUrl() + "?q=a%20b"); } finally { client.close(); } @@ -123,7 +123,7 @@ public void onThrowable(Throwable t) { public void emptyRequestURI() throws Throwable { AsyncHttpClient client = getAsyncHttpClient(null); try { - Request request = new RequestBuilder("GET").setUrl("http://foo.com/").build(); + Request request = new RequestBuilder("GET").setUrl(getTargetUrl()).build(); Future responseFuture = client.executeRequest(request, new AsyncCompletionHandler() { @Override @@ -139,7 +139,7 @@ public void onThrowable(Throwable t) { }); String url = responseFuture.get(); - Assert.assertEquals(url, "http://foo.com/"); + Assert.assertEquals(url, getTargetUrl()); } finally { client.close(); } From 6e42df8e30a5de8ec159636662a94410f13553b2 Mon Sep 17 00:00:00 2001 From: Ryan Lubke Date: Mon, 9 Sep 2013 21:45:57 -0700 Subject: [PATCH 233/264] Improvements to the FeedableBodyGenerator (Grizzly's). - Don't allow queueing of data before initiateAsyncTransfer has been invoked. In low memory heaps, this could lead to an OOM if the source is feeding too fast. The new behavior is to block until initiateAsyncTransfer is called, at which time the blocked thread may proceed with the feed operation. - Introduce the concept of a Feeder. Implementations are responsible, at a high level, for: + letting the provider know that data is available to be fed without blocking + allowing the registration of a callback that the Feeder implementation may invoke to signal that more data is available, if it wasn't available at a previous point in time. - When using a Feeder with a secure request, the SSL handshake will be kicked off by the initiateAsyncTransfer call, but feeding of data will not occur until the handshake is complete. This is necessary as the SSLFilter will queue up all writes until the handshake is complete, and currently, the buffer isn't tied in with the transport flow control mechanism. NOTE: This new SSL behavior is not currently applied when invoking the feed() method outside the context of a Feeder. Still need to address that. - Exposed configuration of the async write queue limit through the FeedableBodyGenerator. This is an improvement on using a TransportCustomizer as any configuration there is transport-wide, and therefor applied to all Connections. By exposing it here, each feeder may have a different byte limit. - Improved documentation for this class --- .../grizzly/FeedableBodyGenerator.java | 418 ++++++++++++++++-- 1 file changed, 369 insertions(+), 49 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/grizzly/FeedableBodyGenerator.java b/src/main/java/com/ning/http/client/providers/grizzly/FeedableBodyGenerator.java index 509188552b..a48c6b0a0a 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/FeedableBodyGenerator.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/FeedableBodyGenerator.java @@ -14,19 +14,23 @@ import com.ning.http.client.Body; import com.ning.http.client.BodyGenerator; + import java.io.IOException; import java.nio.ByteBuffer; -import java.util.Queue; -import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ExecutionException; -import java.util.concurrent.atomic.AtomicInteger; + import org.glassfish.grizzly.Buffer; +import org.glassfish.grizzly.CompletionHandler; import org.glassfish.grizzly.Connection; import org.glassfish.grizzly.WriteHandler; +import org.glassfish.grizzly.WriteResult; +import org.glassfish.grizzly.filterchain.FilterChain; import org.glassfish.grizzly.filterchain.FilterChainContext; import org.glassfish.grizzly.http.HttpContent; import org.glassfish.grizzly.http.HttpRequestPacket; import org.glassfish.grizzly.impl.FutureImpl; +import org.glassfish.grizzly.ssl.SSLBaseFilter; +import org.glassfish.grizzly.ssl.SSLFilter; import org.glassfish.grizzly.utils.Futures; import static com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProvider.getHttpTransactionContext; @@ -43,20 +47,39 @@ * @since 1.7.0 */ public class FeedableBodyGenerator implements BodyGenerator { - private final Queue queue = new ConcurrentLinkedQueue(); - private final AtomicInteger queueSize = new AtomicInteger(); - + + /** + * There is no limit on bytes waiting to be written. This configuration + * value should be used with caution as it could lead to out-of-memory + * conditions. + */ + @SuppressWarnings("UnusedDeclaration") + public static final int UNBOUND = -1; + + /** + * Defer to whatever the connection has been configured for max pending bytes. + */ + public static final int DEFAULT = -2; + private volatile HttpRequestPacket requestPacket; private volatile FilterChainContext context; private volatile HttpContent.Builder contentBuilder; private final EmptyBody EMPTY_BODY = new EmptyBody(); + private Feeder feeder; + private int origMaxPendingBytes; + private int configuredMaxPendingBytes = DEFAULT; + private boolean asyncTransferInitiated; + private FutureImpl prematureFeed = Futures.createSafeFuture(); // ---------------------------------------------- Methods from BodyGenerator + /** + * {@inheritDoc} + */ @Override public Body createBody() throws IOException { return EMPTY_BODY; @@ -67,31 +90,97 @@ public Body createBody() throws IOException { /** - * Feeds the specified buffer. This buffer may be queued to be sent later - * or sent immediately. Note that this method may block if data is being - * fed faster than it is being consumed by the peer. + * Configured the maximum number of bytes that may be pending to be written + * to the wire. If not explicitly configured, the connection's current + * configuration will be used instead. + * + * Once all data has been fed, the connection's max pending bytes configuration + * will be restored to its original value. + * + * @param maxPendingBytes maximum number of bytes that may be queued to + * be written to the wire. + * + * @throws IllegalStateException if called after {@link #initializeAsynchronousTransfer(FilterChainContext, HttpRequestPacket)} + * has been called by the {@link GrizzlyAsyncHttpProvider}. + * @throws IllegalArgumentException if maxPendingBytes is less than zero and is + * not {@link #UNBOUND} or {@link #DEFAULT}. + */ + public synchronized void setMaxPendingBytes(final int maxPendingBytes) { + if (maxPendingBytes < DEFAULT) { + throw new IllegalArgumentException("Invalid maxPendingBytes value: " + maxPendingBytes); + } + if (asyncTransferInitiated) { + throw new IllegalStateException("Unable to set max pending bytes after async data transfer has been initiated."); + } + configuredMaxPendingBytes = maxPendingBytes; + } + + + /** + * Add a {@link Feeder} implementation that will be invoked when writing + * without blocking is possible. This method must be set before dispatching + * the request this feeder is associated with. + * + * @param feeder the {@link Feeder} responsible for providing data. + * + * @throws IllegalStateException if called after {@link #initializeAsynchronousTransfer(FilterChainContext, HttpRequestPacket)} + * has been called by the {@link GrizzlyAsyncHttpProvider}. + * @throws IllegalArgumentException if feeder is null + */ + @SuppressWarnings("UnusedDeclaration") + public synchronized void setFeeder(final Feeder feeder) { + if (asyncTransferInitiated) { + throw new IllegalStateException("Unable to set Feeder after async data transfer has been initiated."); + } + if (feeder == null) { + throw new IllegalArgumentException("Feeder argument cannot be null."); + } + this.feeder = feeder; + } + + + /** + * Feeds the specified buffer. Note that this method will block until + * {@link #asyncTransferInitiated} has been invoked by the {@link GrizzlyAsyncHttpProvider}. + * Once the request has been dispatched, the method will become unblocked, but + * may block again if the amount of data fed exceeds the value as configured + * by {@link #setMaxPendingBytes(int)}. * * The maximum duration that this method may block is dependent on * the current value of {@link org.glassfish.grizzly.Transport#getWriteTimeout(java.util.concurrent.TimeUnit)}. * This value can be customized by using a {@link TransportCustomizer} to * fine-tune the transport used by the client instance. * + * Alternatively, it is highly recommended to only invoke this method + * with in the context of {@link FeedableBodyGenerator.Feeder#canFeed()}. By providing + * an implementation of {@link Feeder} the runtime can eliminate blocking. + * * @param buffer the {@link Buffer} to feed. * @param last flag indicating if this is the final buffer of the message. + * * @throws IOException if an I/O error occurs. + * @throws java.lang.IllegalArgumentException if buffer is null. * * @see TransportCustomizer + * @see Feeder * @see GrizzlyAsyncHttpProviderConfig#addProperty(com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProviderConfig.Property, Object) * @see GrizzlyAsyncHttpProviderConfig.Property#TRANSPORT_CUSTOMIZER */ - @SuppressWarnings("UnusedDeclaration") - public void feed(final Buffer buffer, final boolean last) + @SuppressWarnings({"UnusedDeclaration"}) + public synchronized void feed(final Buffer buffer, final boolean last) throws IOException { - queue.offer(new BodyPart(buffer, last)); - queueSize.incrementAndGet(); - - if (context != null) { - flushQueue(true); + if (buffer == null) { + throw new IllegalArgumentException("Buffer argument cannot be null."); + } + if (asyncTransferInitiated) { + write(buffer, last); + } else { + try { + prematureFeed.get(); + } catch (Exception e) { + throw new IOException(e); + } + write(buffer, last); } } @@ -99,43 +188,98 @@ public void feed(final Buffer buffer, final boolean last) // ------------------------------------------------- Package Private Methods - void initializeAsynchronousTransfer(final FilterChainContext context, - final HttpRequestPacket requestPacket) + synchronized void initializeAsynchronousTransfer(final FilterChainContext context, + final HttpRequestPacket requestPacket) throws IOException { - this.context = context; + + if (asyncTransferInitiated) { + throw new IllegalStateException("Async transfer has already been initiated."); + } + assert (context != null); + assert (requestPacket != null); + + asyncTransferInitiated = true; this.requestPacket = requestPacket; this.contentBuilder = HttpContent.builder(requestPacket); - // don't block here. If queue is full at the time of the next feed() - // call, it will block. - flushQueue(false); + final Connection c = context.getConnection(); + origMaxPendingBytes = c.getMaxAsyncWriteQueueSize(); + if (configuredMaxPendingBytes != DEFAULT) { + c.setMaxAsyncWriteQueueSize(configuredMaxPendingBytes); + } + this.context = context; + + if (feeder != null) { + if (requestPacket.isSecure()) { + flushOnSSLHandshakeComplete(); + } else { + flushViaFeeder(); + } + } else { + prematureFeed.result(Boolean.TRUE); + } } // --------------------------------------------------------- Private Methods + private void flushOnSSLHandshakeComplete() throws IOException { + final FilterChain filterChain = context.getFilterChain(); + final int idx = filterChain.indexOfType(SSLFilter.class); + assert (idx != -1); + final SSLFilter filter = (SSLFilter) filterChain.get(idx); + filter.addHandshakeListener(new SSLBaseFilter.HandshakeListener() { + public void onStart(Connection connection) { + System.out.println("HANDSHAKE STARTED"); + } + + public void onComplete(Connection connection) { + flushViaFeeder(); + filter.removeHandshakeListener(this); + } + }); + filter.handshake(context.getConnection(), null); + } + + @SuppressWarnings("unchecked") - private void flushQueue(final boolean allowBlocking) throws IOException { - if (queueSize.get() > 0) { - synchronized(this) { - final Connection c = context.getConnection(); - while(queueSize.get() > 0) { - if (allowBlocking) { - blockUntilQueueFree(c); - } - final BodyPart bodyPart = queue.poll(); - queueSize.decrementAndGet(); - final HttpContent content = - contentBuilder.content(bodyPart.buffer) - .last(bodyPart.isLast) - .build(); - context.write(content, - ((!requestPacket.isCommitted()) - ? context.getTransportContext() - .getCompletionHandler() - : null)); + private void write(final Buffer buffer, final boolean last) { + blockUntilQueueFree(context.getConnection()); + final HttpContent content = + contentBuilder.content(buffer).last(last).build(); + final CompletionHandler handler = + ((last) ? new LastPacketCompletionHandler() : null); + context.write(content, handler); + } + + private void flushViaFeeder() { + final Connection c = context.getConnection(); + + if (feeder.isReady()) { + writeUntilFullOrDone(c); + if (!feeder.isDone()) { + if (!feeder.isReady()) { + feeder.notifyReadyToFeed(new ReadyToFeedListenerImpl()); + } + if (!c.canWrite()) { + // write queue is full, leverage WriteListener to let us know + // when it is safe to write again. + c.notifyCanWrite(new WriteHandlerImpl()); } } + } else { + feeder.notifyReadyToFeed(new ReadyToFeedListenerImpl()); + } + } + + private void writeUntilFullOrDone(final Connection c) { + while (c.canWrite()) { + if (feeder.isReady()) { + feeder.canFeed(); + } + if (!feeder.isReady()) { + break; + } } } @@ -212,19 +356,195 @@ public void close() throws IOException { requestPacket = null; contentBuilder = null; } - } + + } // END EmptyBody + + + private final class LastPacketCompletionHandler implements CompletionHandler { + + private final CompletionHandler delegate; + private final Connection c; + + // -------------------------------------------------------- Constructors + + + @SuppressWarnings("unchecked") + private LastPacketCompletionHandler() { + delegate = ((!requestPacket.isCommitted()) + ? context.getTransportContext().getCompletionHandler() + : null); + c = context.getConnection(); + } + + + // -------------------------------------- Methods from CompletionHandler + + + @Override + public void cancelled() { + c.setMaxAsyncWriteQueueSize(origMaxPendingBytes); + if (delegate != null) { + delegate.cancelled(); + } + } + + @Override + public void failed(Throwable throwable) { + c.setMaxAsyncWriteQueueSize(origMaxPendingBytes); + if (delegate != null) { + delegate.failed(throwable); + } + + } + + @Override + public void completed(WriteResult result) { + c.setMaxAsyncWriteQueueSize(origMaxPendingBytes); + if (delegate != null) { + delegate.completed(result); + } + + } + + @Override + public void updated(WriteResult result) { + if (delegate != null) { + delegate.updated(result); + } + } + + } // END LastPacketCompletionHandler // ---------------------------------------------------------- Nested Classes - private final static class BodyPart { - private final boolean isLast; - private final Buffer buffer; + /** + * Developers may provide implementations of this class in order to + * feed data to the {@link FeedableBodyGenerator} without blocking. + */ + public static abstract class Feeder { + + + protected final FeedableBodyGenerator feedableBodyGenerator; - public BodyPart(final Buffer buffer, final boolean isLast) { - this.buffer = buffer; - this.isLast = isLast; + + // -------------------------------------------------------- Constructors + + + public Feeder(final FeedableBodyGenerator feedableBodyGenerator) { + this.feedableBodyGenerator = feedableBodyGenerator; } - } + + + // ------------------------------------------------------ Public Methods + + + /** + * Notification that it's possible to send another block of data via + * {@link #feed(org.glassfish.grizzly.Buffer, boolean)}. + * + * It's important to only invoke {@link #feed(Buffer, boolean)} + * once per invocation of {@link #canFeed()}. + */ + public abstract void canFeed(); + + /** + * @return true if all data has been fed by this feeder, + * otherwise returns false. + */ + public abstract boolean isDone(); + + /** + * @return true if data is available to be fed, otherwise + * returns false. When this method returns false, + * the {@link FeedableBodyGenerator} will call {@link #notifyReadyToFeed(ReadyToFeedListener)} + * by which this {@link Feeder} implementation may signal data is once + * again available to be fed. + */ + public abstract boolean isReady(); + + /** + * Callback registration to signal the {@link FeedableBodyGenerator} that + * data is available once again to continue feeding. Once this listener + * has been invoked, the Feeder implementation should no longer maintain + * a reference to the listener. + */ + public abstract void notifyReadyToFeed(final ReadyToFeedListener listener); + + + // ------------------------------------------------------- Inner Classes + + + /** + * Listener to signal that data is available to be fed. + */ + public interface ReadyToFeedListener { + + /** + * Data is once again ready to be fed. + */ + @SuppressWarnings("UnusedDeclaration") + void ready(); + + } // END ReadyToFeedListener + + } // END Feeder + + + private final class WriteHandlerImpl implements WriteHandler { + + + private final Connection c; + + + // -------------------------------------------------------- Constructors + + + private WriteHandlerImpl() { + this.c = context.getConnection(); + } + + + // ------------------------------------------ Methods from WriteListener + + @Override + public void onWritePossible() throws Exception { + writeUntilFullOrDone(c); + if (!feeder.isDone()) { + if (!feeder.isReady()) { + feeder.notifyReadyToFeed(new ReadyToFeedListenerImpl()); + } + if (!c.canWrite()) { + // write queue is full, leverage WriteListener to let us know + // when it is safe to write again. + c.notifyCanWrite(this); + } + } + } + + @Override + public void onError(Throwable t) { + c.setMaxAsyncWriteQueueSize(origMaxPendingBytes); + GrizzlyAsyncHttpProvider.HttpTransactionContext ctx = + GrizzlyAsyncHttpProvider.getHttpTransactionContext(c); + ctx.abort(t); + } + + } // END WriteHandlerImpl + + + private final class ReadyToFeedListenerImpl implements Feeder.ReadyToFeedListener { + + + // ------------------------------------ Methods from ReadyToFeedListener + + + @Override + public void ready() { + flushViaFeeder(); + } + + } // END ReadToFeedListenerImpl + } From 56e9656f260b8cf27cfde68b3e3d4df64e2aa540 Mon Sep 17 00:00:00 2001 From: Ryan Lubke Date: Mon, 9 Sep 2013 21:54:12 -0700 Subject: [PATCH 234/264] Missed print. --- .../http/client/providers/grizzly/FeedableBodyGenerator.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/com/ning/http/client/providers/grizzly/FeedableBodyGenerator.java b/src/main/java/com/ning/http/client/providers/grizzly/FeedableBodyGenerator.java index a48c6b0a0a..3f29777207 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/FeedableBodyGenerator.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/FeedableBodyGenerator.java @@ -230,7 +230,6 @@ private void flushOnSSLHandshakeComplete() throws IOException { final SSLFilter filter = (SSLFilter) filterChain.get(idx); filter.addHandshakeListener(new SSLBaseFilter.HandshakeListener() { public void onStart(Connection connection) { - System.out.println("HANDSHAKE STARTED"); } public void onComplete(Connection connection) { From 4e097498bb3229c4be6ecca95c0b126ad9473511 Mon Sep 17 00:00:00 2001 From: Ryan Lubke Date: Wed, 11 Sep 2013 12:35:58 -0700 Subject: [PATCH 235/264] Another round of refactoring of the FeedableBodyGenerator based on Feedback on the Grizzly user list. - Removed FeedableBodyGenerator.feed(). This method is now defined by the Feeder interface and implemented by the BaseFeeder abstract class. - The original Feeder is no called NonBlockingFeeder. - Added SimpleFeeder that is a simple callback notifying the implementation that asyncronous transferring has been initiated. This allows for feeding in the same fashion as the original FeedableBodyGenerator implementation, but doesn't suffer from some of the drawbacks (like unbound feeding before transferring has started or causing an OOM due to feeding large amounts of data while performing an SSL handshake. --- .../grizzly/FeedableBodyGenerator.java | 530 ++++++++++-------- 1 file changed, 302 insertions(+), 228 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/grizzly/FeedableBodyGenerator.java b/src/main/java/com/ning/http/client/providers/grizzly/FeedableBodyGenerator.java index 3f29777207..cab60e48cf 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/FeedableBodyGenerator.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/FeedableBodyGenerator.java @@ -39,9 +39,13 @@ import static org.glassfish.grizzly.utils.Exceptions.*; /** - * {@link BodyGenerator} which may return just part of the payload at the time - * handler is requesting it. If it happens - PartialBodyGenerator becomes responsible - * for finishing payload transferring asynchronously. + * A Grizzly-specific {@link BodyGenerator} that allows data to be fed to the + * connection in blocking or non-blocking fashion via the use of a {@link Feeder}. + * + * This class provides two {@link Feeder} implementations for rapid prototyping. + * First is the {@link SimpleFeeder} which is simply a listener that asynchronous + * data transferring has been initiated. The second is the {@link NonBlockingFeeder} + * which allows reading and feeding data in a non-blocking fashion. * * @author The Grizzly Team * @since 1.7.0 @@ -71,7 +75,6 @@ public class FeedableBodyGenerator implements BodyGenerator { private int origMaxPendingBytes; private int configuredMaxPendingBytes = DEFAULT; private boolean asyncTransferInitiated; - private FutureImpl prematureFeed = Futures.createSafeFuture(); // ---------------------------------------------- Methods from BodyGenerator @@ -105,6 +108,7 @@ public Body createBody() throws IOException { * @throws IllegalArgumentException if maxPendingBytes is less than zero and is * not {@link #UNBOUND} or {@link #DEFAULT}. */ + @SuppressWarnings("UnusedDeclaration") public synchronized void setMaxPendingBytes(final int maxPendingBytes) { if (maxPendingBytes < DEFAULT) { throw new IllegalArgumentException("Invalid maxPendingBytes value: " + maxPendingBytes); @@ -139,52 +143,6 @@ public synchronized void setFeeder(final Feeder feeder) { } - /** - * Feeds the specified buffer. Note that this method will block until - * {@link #asyncTransferInitiated} has been invoked by the {@link GrizzlyAsyncHttpProvider}. - * Once the request has been dispatched, the method will become unblocked, but - * may block again if the amount of data fed exceeds the value as configured - * by {@link #setMaxPendingBytes(int)}. - * - * The maximum duration that this method may block is dependent on - * the current value of {@link org.glassfish.grizzly.Transport#getWriteTimeout(java.util.concurrent.TimeUnit)}. - * This value can be customized by using a {@link TransportCustomizer} to - * fine-tune the transport used by the client instance. - * - * Alternatively, it is highly recommended to only invoke this method - * with in the context of {@link FeedableBodyGenerator.Feeder#canFeed()}. By providing - * an implementation of {@link Feeder} the runtime can eliminate blocking. - * - * @param buffer the {@link Buffer} to feed. - * @param last flag indicating if this is the final buffer of the message. - * - * @throws IOException if an I/O error occurs. - * @throws java.lang.IllegalArgumentException if buffer is null. - * - * @see TransportCustomizer - * @see Feeder - * @see GrizzlyAsyncHttpProviderConfig#addProperty(com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProviderConfig.Property, Object) - * @see GrizzlyAsyncHttpProviderConfig.Property#TRANSPORT_CUSTOMIZER - */ - @SuppressWarnings({"UnusedDeclaration"}) - public synchronized void feed(final Buffer buffer, final boolean last) - throws IOException { - if (buffer == null) { - throw new IllegalArgumentException("Buffer argument cannot be null."); - } - if (asyncTransferInitiated) { - write(buffer, last); - } else { - try { - prematureFeed.get(); - } catch (Exception e) { - throw new IOException(e); - } - write(buffer, last); - } - } - - // ------------------------------------------------- Package Private Methods @@ -195,6 +153,9 @@ synchronized void initializeAsynchronousTransfer(final FilterChainContext contex if (asyncTransferInitiated) { throw new IllegalStateException("Async transfer has already been initiated."); } + if (feeder == null) { + throw new IllegalStateException("No feeder available to perform the transfer."); + } assert (context != null); assert (requestPacket != null); @@ -208,15 +169,12 @@ synchronized void initializeAsynchronousTransfer(final FilterChainContext contex } this.context = context; - if (feeder != null) { - if (requestPacket.isSecure()) { - flushOnSSLHandshakeComplete(); - } else { - flushViaFeeder(); - } + if (requestPacket.isSecure()) { + flushOnSSLHandshakeComplete(); } else { - prematureFeed.result(Boolean.TRUE); + feeder.flush(); } + } @@ -233,106 +191,14 @@ public void onStart(Connection connection) { } public void onComplete(Connection connection) { - flushViaFeeder(); filter.removeHandshakeListener(this); + feeder.flush(); } }); filter.handshake(context.getConnection(), null); } - @SuppressWarnings("unchecked") - private void write(final Buffer buffer, final boolean last) { - blockUntilQueueFree(context.getConnection()); - final HttpContent content = - contentBuilder.content(buffer).last(last).build(); - final CompletionHandler handler = - ((last) ? new LastPacketCompletionHandler() : null); - context.write(content, handler); - } - - private void flushViaFeeder() { - final Connection c = context.getConnection(); - - if (feeder.isReady()) { - writeUntilFullOrDone(c); - if (!feeder.isDone()) { - if (!feeder.isReady()) { - feeder.notifyReadyToFeed(new ReadyToFeedListenerImpl()); - } - if (!c.canWrite()) { - // write queue is full, leverage WriteListener to let us know - // when it is safe to write again. - c.notifyCanWrite(new WriteHandlerImpl()); - } - } - } else { - feeder.notifyReadyToFeed(new ReadyToFeedListenerImpl()); - } - } - - private void writeUntilFullOrDone(final Connection c) { - while (c.canWrite()) { - if (feeder.isReady()) { - feeder.canFeed(); - } - if (!feeder.isReady()) { - break; - } - } - } - - /** - * This method will block if the async write queue is currently larger - * than the configured maximum. The amount of time that this method - * will block is dependent on the write timeout of the transport - * associated with the specified connection. - */ - private void blockUntilQueueFree(final Connection c) { - if (!c.canWrite()) { - final FutureImpl future = - Futures.createSafeFuture(); - - // Connection may be obtained by calling FilterChainContext.getConnection(). - c.notifyCanWrite(new WriteHandler() { - - @Override - public void onWritePossible() throws Exception { - future.result(TRUE); - } - - @Override - public void onError(Throwable t) { - future.failure(makeIOException(t)); - } - }); - - block(c, future); - } - } - - private void block(final Connection c, - final FutureImpl future) { - try { - final long writeTimeout = - c.getTransport().getWriteTimeout(MILLISECONDS); - if (writeTimeout != -1) { - future.get(writeTimeout, MILLISECONDS); - } else { - future.get(); - } - } catch (ExecutionException e) { - GrizzlyAsyncHttpProvider.HttpTransactionContext httpCtx = - getHttpTransactionContext(c); - httpCtx.abort(e.getCause()); - } catch (Exception e) { - GrizzlyAsyncHttpProvider.HttpTransactionContext httpCtx = - getHttpTransactionContext(c); - httpCtx.abort(e); - } - } - - // ----------------------------------------------------------- Inner Classes @@ -359,80 +225,222 @@ public void close() throws IOException { } // END EmptyBody - private final class LastPacketCompletionHandler implements CompletionHandler { + // ---------------------------------------------------------- Nested Classes + + + /** + * Specifies the functionality all Feeders must implement. Typically, + * developers need not worry about implementing this interface directly. + * It should be sufficient, for most use-cases, to simply use the {@link NonBlockingFeeder} + * or {@link SimpleFeeder} implementations. + */ + public interface Feeder { + + /** + * This method will be invoked when it's possible to begin feeding + * data downstream. Implementations of this method must use {@link #feed(Buffer, boolean)} + * to perform the actual write. + */ + void flush(); + + /** + * This method will write the specified {@link Buffer} to the connection. + * Be aware that this method may block depending if data is being fed + * faster than it can write. How much data may be queued is dictated + * by {@link #setMaxPendingBytes(int)}. Once this threshold is exceeded, + * the method will block until the write queue length drops below the + * aforementioned threshold. + * + * @param buffer the {@link Buffer} to write. + * @param last flag indicating if this is the last buffer to send. + * + * @throws IOException if an I/O error occurs. + * @throws java.lang.IllegalArgumentException if buffer + * is null. + * @throws java.lang.IllegalStateException if this method is invoked + * before asynchronous transferring has been initiated. + * + * @see #setMaxPendingBytes(int) + */ + void feed(final Buffer buffer, final boolean last) throws IOException; + + } // END Feeder + + + /** + * Base class for {@link Feeder} implementations. This class provides + * an implementation for the contract defined by the {@link #feed} method. + */ + public static abstract class BaseFeeder implements Feeder { + + protected final FeedableBodyGenerator feedableBodyGenerator; - private final CompletionHandler delegate; - private final Connection c; // -------------------------------------------------------- Constructors - @SuppressWarnings("unchecked") - private LastPacketCompletionHandler() { - delegate = ((!requestPacket.isCommitted()) - ? context.getTransportContext().getCompletionHandler() - : null); - c = context.getConnection(); + protected BaseFeeder(FeedableBodyGenerator feedableBodyGenerator) { + this.feedableBodyGenerator = feedableBodyGenerator; } - // -------------------------------------- Methods from CompletionHandler + // --------------------------------------------- Package Private Methods - @Override - public void cancelled() { - c.setMaxAsyncWriteQueueSize(origMaxPendingBytes); - if (delegate != null) { - delegate.cancelled(); + /** + * {@inheritDoc} + */ + @SuppressWarnings("UnusedDeclaration") + public final synchronized void feed(final Buffer buffer, final boolean last) + throws IOException { + if (buffer == null) { + throw new IllegalArgumentException( + "Buffer argument cannot be null."); + } + if (!feedableBodyGenerator.asyncTransferInitiated) { + throw new IllegalStateException("Asynchronous transfer has not been initiated."); } + blockUntilQueueFree(feedableBodyGenerator.context.getConnection()); + final HttpContent content = + feedableBodyGenerator.contentBuilder.content(buffer).last(last).build(); + final CompletionHandler handler = + ((last) ? new LastPacketCompletionHandler() : null); + feedableBodyGenerator.context.write(content, handler); } - @Override - public void failed(Throwable throwable) { - c.setMaxAsyncWriteQueueSize(origMaxPendingBytes); - if (delegate != null) { - delegate.failed(throwable); + /** + * This method will block if the async write queue is currently larger + * than the configured maximum. The amount of time that this method + * will block is dependent on the write timeout of the transport + * associated with the specified connection. + */ + private static void blockUntilQueueFree(final Connection c) { + if (!c.canWrite()) { + final FutureImpl future = + Futures.createSafeFuture(); + + // Connection may be obtained by calling FilterChainContext.getConnection(). + c.notifyCanWrite(new WriteHandler() { + + @Override + public void onWritePossible() throws Exception { + future.result(TRUE); + } + + @Override + public void onError(Throwable t) { + future.failure(makeIOException(t)); + } + }); + + block(c, future); } + } + private static void block(final Connection c, + final FutureImpl future) { + try { + final long writeTimeout = + c.getTransport().getWriteTimeout(MILLISECONDS); + if (writeTimeout != -1) { + future.get(writeTimeout, MILLISECONDS); + } else { + future.get(); + } + } catch (ExecutionException e) { + GrizzlyAsyncHttpProvider.HttpTransactionContext httpCtx = + getHttpTransactionContext(c); + httpCtx.abort(e.getCause()); + } catch (Exception e) { + GrizzlyAsyncHttpProvider.HttpTransactionContext httpCtx = + getHttpTransactionContext(c); + httpCtx.abort(e); + } } - @Override - public void completed(WriteResult result) { - c.setMaxAsyncWriteQueueSize(origMaxPendingBytes); - if (delegate != null) { - delegate.completed(result); + + // ------------------------------------------------------- Inner Classes + + + private final class LastPacketCompletionHandler + implements CompletionHandler { + + private final CompletionHandler delegate; + private final Connection c; + private final int origMaxPendingBytes; + + // -------------------------------------------------------- Constructors + + + @SuppressWarnings("unchecked") + private LastPacketCompletionHandler() { + delegate = ((!feedableBodyGenerator.requestPacket.isCommitted()) + ? feedableBodyGenerator.context.getTransportContext().getCompletionHandler() + : null); + c = feedableBodyGenerator.context.getConnection(); + origMaxPendingBytes = feedableBodyGenerator.origMaxPendingBytes; } - } - @Override - public void updated(WriteResult result) { - if (delegate != null) { - delegate.updated(result); + // -------------------------------------- Methods from CompletionHandler + + + @Override + public void cancelled() { + c.setMaxAsyncWriteQueueSize(origMaxPendingBytes); + if (delegate != null) { + delegate.cancelled(); + } } - } - } // END LastPacketCompletionHandler + @Override + public void failed(Throwable throwable) { + c.setMaxAsyncWriteQueueSize(origMaxPendingBytes); + if (delegate != null) { + delegate.failed(throwable); + } + } - // ---------------------------------------------------------- Nested Classes + @Override + public void completed(WriteResult result) { + c.setMaxAsyncWriteQueueSize(origMaxPendingBytes); + if (delegate != null) { + delegate.completed(result); + } + } - /** - * Developers may provide implementations of this class in order to - * feed data to the {@link FeedableBodyGenerator} without blocking. - */ - public static abstract class Feeder { + @Override + public void updated(WriteResult result) { + if (delegate != null) { + delegate.updated(result); + } + } + } // END LastPacketCompletionHandler - protected final FeedableBodyGenerator feedableBodyGenerator; + } // END Feeder + + + /** + * Implementations of this class provide the framework to read data from + * some source and feed data to the {@link FeedableBodyGenerator} + * without blocking. + */ + @SuppressWarnings("UnusedDeclaration") + public static abstract class NonBlockingFeeder extends BaseFeeder { // -------------------------------------------------------- Constructors - public Feeder(final FeedableBodyGenerator feedableBodyGenerator) { - this.feedableBodyGenerator = feedableBodyGenerator; + /** + * Constructs the NonBlockingFeeder with the associated + * {@link com.ning.http.client.providers.grizzly.FeedableBodyGenerator}. + */ + public NonBlockingFeeder(final FeedableBodyGenerator feedableBodyGenerator) { + super(feedableBodyGenerator); } @@ -458,7 +466,7 @@ public Feeder(final FeedableBodyGenerator feedableBodyGenerator) { * @return true if data is available to be fed, otherwise * returns false. When this method returns false, * the {@link FeedableBodyGenerator} will call {@link #notifyReadyToFeed(ReadyToFeedListener)} - * by which this {@link Feeder} implementation may signal data is once + * by which this {@link com.ning.http.client.providers.grizzly.FeedableBodyGenerator.NonBlockingFeeder} implementation may signal data is once * again available to be fed. */ public abstract boolean isReady(); @@ -466,12 +474,54 @@ public Feeder(final FeedableBodyGenerator feedableBodyGenerator) { /** * Callback registration to signal the {@link FeedableBodyGenerator} that * data is available once again to continue feeding. Once this listener - * has been invoked, the Feeder implementation should no longer maintain + * has been invoked, the NonBlockingFeeder implementation should no longer maintain * a reference to the listener. */ public abstract void notifyReadyToFeed(final ReadyToFeedListener listener); + // ------------------------------------------------- Methods from Feeder + + + /** + * {@inheritDoc} + */ + @Override + public synchronized void flush() { + final Connection c = feedableBodyGenerator.context.getConnection(); + if (isReady()) { + writeUntilFullOrDone(c); + if (!isDone()) { + if (!isReady()) { + notifyReadyToFeed(new ReadyToFeedListenerImpl()); + } + if (!c.canWrite()) { + // write queue is full, leverage WriteListener to let us know + // when it is safe to write again. + c.notifyCanWrite(new WriteHandlerImpl()); + } + } + } else { + notifyReadyToFeed(new ReadyToFeedListenerImpl()); + } + } + + + // ----------------------------------------------------- Private Methods + + + private void writeUntilFullOrDone(final Connection c) { + while (c.canWrite()) { + if (isReady()) { + canFeed(); + } + if (!isReady()) { + break; + } + } + } + + // ------------------------------------------------------- Inner Classes @@ -488,62 +538,86 @@ public interface ReadyToFeedListener { } // END ReadyToFeedListener - } // END Feeder + private final class WriteHandlerImpl implements WriteHandler { - private final class WriteHandlerImpl implements WriteHandler { + private final Connection c; - private final Connection c; + // -------------------------------------------------------- Constructors - // -------------------------------------------------------- Constructors + private WriteHandlerImpl() { + this.c = feedableBodyGenerator.context.getConnection(); + } - private WriteHandlerImpl() { - this.c = context.getConnection(); - } + // ------------------------------------------ Methods from WriteListener + + @Override + public void onWritePossible() throws Exception { + writeUntilFullOrDone(c); + if (!isDone()) { + if (!isReady()) { + notifyReadyToFeed(new ReadyToFeedListenerImpl()); + } + if (!c.canWrite()) { + // write queue is full, leverage WriteListener to let us know + // when it is safe to write again. + c.notifyCanWrite(this); + } + } + } - // ------------------------------------------ Methods from WriteListener + @Override + public void onError(Throwable t) { + c.setMaxAsyncWriteQueueSize(feedableBodyGenerator.origMaxPendingBytes); + GrizzlyAsyncHttpProvider.HttpTransactionContext ctx = + GrizzlyAsyncHttpProvider.getHttpTransactionContext(c); + ctx.abort(t); + } - @Override - public void onWritePossible() throws Exception { - writeUntilFullOrDone(c); - if (!feeder.isDone()) { - if (!feeder.isReady()) { - feeder.notifyReadyToFeed(new ReadyToFeedListenerImpl()); - } - if (!c.canWrite()) { - // write queue is full, leverage WriteListener to let us know - // when it is safe to write again. - c.notifyCanWrite(this); - } + } // END WriteHandlerImpl + + + private final class ReadyToFeedListenerImpl + implements NonBlockingFeeder.ReadyToFeedListener { + + + // ------------------------------------ Methods from ReadyToFeedListener + + + @Override + public void ready() { + flush(); } - } - @Override - public void onError(Throwable t) { - c.setMaxAsyncWriteQueueSize(origMaxPendingBytes); - GrizzlyAsyncHttpProvider.HttpTransactionContext ctx = - GrizzlyAsyncHttpProvider.getHttpTransactionContext(c); - ctx.abort(t); - } + } // END ReadToFeedListenerImpl - } // END WriteHandlerImpl + } // END NonBlockingFeeder - private final class ReadyToFeedListenerImpl implements Feeder.ReadyToFeedListener { + /** + * This simple {@link Feeder} implementation allows the implementation to + * feed data in whatever fashion is deemed appropriate. + */ + @SuppressWarnings("UnusedDeclaration") + public abstract static class SimpleFeeder extends BaseFeeder { - // ------------------------------------ Methods from ReadyToFeedListener + // -------------------------------------------------------- Constructors - @Override - public void ready() { - flushViaFeeder(); + /** + * Constructs the SimpleFeeder with the associated + * {@link com.ning.http.client.providers.grizzly.FeedableBodyGenerator}. + */ + public SimpleFeeder(FeedableBodyGenerator feedableBodyGenerator) { + super(feedableBodyGenerator); } - } // END ReadToFeedListenerImpl + + } // END BlockingFeeder } From 821d308ce2f0d65f02623f7255426d48d00bffbd Mon Sep 17 00:00:00 2001 From: Ryan Lubke Date: Wed, 11 Sep 2013 12:51:23 -0700 Subject: [PATCH 236/264] Adjust when flag is set. --- .../http/client/providers/grizzly/FeedableBodyGenerator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/ning/http/client/providers/grizzly/FeedableBodyGenerator.java b/src/main/java/com/ning/http/client/providers/grizzly/FeedableBodyGenerator.java index cab60e48cf..1b491d04b8 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/FeedableBodyGenerator.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/FeedableBodyGenerator.java @@ -159,7 +159,6 @@ synchronized void initializeAsynchronousTransfer(final FilterChainContext contex assert (context != null); assert (requestPacket != null); - asyncTransferInitiated = true; this.requestPacket = requestPacket; this.contentBuilder = HttpContent.builder(requestPacket); final Connection c = context.getConnection(); @@ -168,6 +167,7 @@ synchronized void initializeAsynchronousTransfer(final FilterChainContext contex c.setMaxAsyncWriteQueueSize(configuredMaxPendingBytes); } this.context = context; + asyncTransferInitiated = true; if (requestPacket.isSecure()) { flushOnSSLHandshakeComplete(); From a973fc17ede374de3bce3eb8d1aaf14aeeded93c Mon Sep 17 00:00:00 2001 From: Ryan Lubke Date: Wed, 11 Sep 2013 13:28:21 -0700 Subject: [PATCH 237/264] Fix invalid string ref. --- .../http/client/providers/grizzly/FeedableBodyGenerator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/ning/http/client/providers/grizzly/FeedableBodyGenerator.java b/src/main/java/com/ning/http/client/providers/grizzly/FeedableBodyGenerator.java index 1b491d04b8..1f7e9c9369 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/FeedableBodyGenerator.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/FeedableBodyGenerator.java @@ -618,6 +618,6 @@ public SimpleFeeder(FeedableBodyGenerator feedableBodyGenerator) { } - } // END BlockingFeeder + } // END SimpleFeeder } From 263946fdd9021fdbcc0b3158ab6cc312cdef97e7 Mon Sep 17 00:00:00 2001 From: Ryan Lubke Date: Wed, 11 Sep 2013 22:22:31 -0700 Subject: [PATCH 238/264] Deal with the case when the connection is cached. --- .../http/client/providers/grizzly/FeedableBodyGenerator.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/ning/http/client/providers/grizzly/FeedableBodyGenerator.java b/src/main/java/com/ning/http/client/providers/grizzly/FeedableBodyGenerator.java index 1f7e9c9369..9bbf1b2926 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/FeedableBodyGenerator.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/FeedableBodyGenerator.java @@ -31,11 +31,13 @@ import org.glassfish.grizzly.impl.FutureImpl; import org.glassfish.grizzly.ssl.SSLBaseFilter; import org.glassfish.grizzly.ssl.SSLFilter; +import org.glassfish.grizzly.ssl.SSLUtils; import org.glassfish.grizzly.utils.Futures; import static com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProvider.getHttpTransactionContext; import static java.lang.Boolean.TRUE; import static java.util.concurrent.TimeUnit.MILLISECONDS; +import static org.glassfish.grizzly.ssl.SSLUtils.getSSLEngine; import static org.glassfish.grizzly.utils.Exceptions.*; /** @@ -169,7 +171,8 @@ synchronized void initializeAsynchronousTransfer(final FilterChainContext contex this.context = context; asyncTransferInitiated = true; - if (requestPacket.isSecure()) { + if (requestPacket.isSecure() && + (getSSLEngine(context.getConnection()) == null)) { flushOnSSLHandshakeComplete(); } else { feeder.flush(); From 28468176237cf5cd938094b90e5828d0cca71345 Mon Sep 17 00:00:00 2001 From: Ryan Lubke Date: Thu, 12 Sep 2013 10:06:01 -0700 Subject: [PATCH 239/264] Fix the SSLHandshakeListener. Need to discriminate the connection. --- .../grizzly/FeedableBodyGenerator.java | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/grizzly/FeedableBodyGenerator.java b/src/main/java/com/ning/http/client/providers/grizzly/FeedableBodyGenerator.java index 9bbf1b2926..e59e3eca8d 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/FeedableBodyGenerator.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/FeedableBodyGenerator.java @@ -31,7 +31,6 @@ import org.glassfish.grizzly.impl.FutureImpl; import org.glassfish.grizzly.ssl.SSLBaseFilter; import org.glassfish.grizzly.ssl.SSLFilter; -import org.glassfish.grizzly.ssl.SSLUtils; import org.glassfish.grizzly.utils.Futures; import static com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProvider.getHttpTransactionContext; @@ -189,13 +188,22 @@ private void flushOnSSLHandshakeComplete() throws IOException { final int idx = filterChain.indexOfType(SSLFilter.class); assert (idx != -1); final SSLFilter filter = (SSLFilter) filterChain.get(idx); + final Connection c = context.getConnection(); filter.addHandshakeListener(new SSLBaseFilter.HandshakeListener() { public void onStart(Connection connection) { } public void onComplete(Connection connection) { - filter.removeHandshakeListener(this); - feeder.flush(); + if (c.equals(connection)) { + filter.removeHandshakeListener(this); + try { + feeder.flush(); + } catch (IOException ioe) { + GrizzlyAsyncHttpProvider.HttpTransactionContext ctx = + GrizzlyAsyncHttpProvider.getHttpTransactionContext(c); + ctx.abort(ioe); + } + } } }); filter.handshake(context.getConnection(), null); @@ -243,8 +251,10 @@ public interface Feeder { * This method will be invoked when it's possible to begin feeding * data downstream. Implementations of this method must use {@link #feed(Buffer, boolean)} * to perform the actual write. + * + * @throws IOException if an I/O error occurs. */ - void flush(); + void flush() throws IOException; /** * This method will write the specified {@link Buffer} to the connection. @@ -469,7 +479,7 @@ public NonBlockingFeeder(final FeedableBodyGenerator feedableBodyGenerator) { * @return true if data is available to be fed, otherwise * returns false. When this method returns false, * the {@link FeedableBodyGenerator} will call {@link #notifyReadyToFeed(ReadyToFeedListener)} - * by which this {@link com.ning.http.client.providers.grizzly.FeedableBodyGenerator.NonBlockingFeeder} implementation may signal data is once + * by which this {@link NonBlockingFeeder} implementation may signal data is once * again available to be fed. */ public abstract boolean isReady(); From adb42e0373f4a8dd364a2667938af5e6b734130e Mon Sep 17 00:00:00 2001 From: Ryan Lubke Date: Mon, 16 Sep 2013 11:25:03 -0700 Subject: [PATCH 240/264] Update FeedableBodyGenerator to prevent feed logic execution from blocking the selector thread by checking if the current thread is the selector thread and if true, execute the task on a worker thread. --- .../grizzly/FeedableBodyGenerator.java | 39 ++++++++++++++++--- 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/grizzly/FeedableBodyGenerator.java b/src/main/java/com/ning/http/client/providers/grizzly/FeedableBodyGenerator.java index e59e3eca8d..e9d826b651 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/FeedableBodyGenerator.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/FeedableBodyGenerator.java @@ -29,6 +29,8 @@ import org.glassfish.grizzly.http.HttpContent; import org.glassfish.grizzly.http.HttpRequestPacket; import org.glassfish.grizzly.impl.FutureImpl; +import org.glassfish.grizzly.nio.NIOConnection; +import org.glassfish.grizzly.nio.SelectorRunner; import org.glassfish.grizzly.ssl.SSLBaseFilter; import org.glassfish.grizzly.ssl.SSLFilter; import org.glassfish.grizzly.utils.Futures; @@ -169,20 +171,46 @@ synchronized void initializeAsynchronousTransfer(final FilterChainContext contex } this.context = context; asyncTransferInitiated = true; + final Runnable r = new Runnable() { + @Override + public void run() { + try { + if (requestPacket.isSecure() && + (getSSLEngine(context.getConnection()) == null)) { + flushOnSSLHandshakeComplete(); + } else { + feeder.flush(); + } + } catch (IOException ioe) { + GrizzlyAsyncHttpProvider.HttpTransactionContext ctx = + GrizzlyAsyncHttpProvider.getHttpTransactionContext( + c); + ctx.abort(ioe); + } + } + }; - if (requestPacket.isSecure() && - (getSSLEngine(context.getConnection()) == null)) { - flushOnSSLHandshakeComplete(); + // If the current thread is a selector thread, we need to execute + // the remainder of the task on the worker thread to prevent + // it from being blocked. + if (isCurrentThreadSelectorRunner()) { + c.getTransport().getWorkerThreadPool().execute(r); } else { - feeder.flush(); + r.run(); } - } // --------------------------------------------------------- Private Methods + private boolean isCurrentThreadSelectorRunner() { + final NIOConnection c = (NIOConnection) context.getConnection(); + final SelectorRunner runner = c.getSelectorRunner(); + return (Thread.currentThread() == runner.getRunnerThread()); + } + + private void flushOnSSLHandshakeComplete() throws IOException { final FilterChain filterChain = context.getFilterChain(); final int idx = filterChain.indexOfType(SSLFilter.class); @@ -331,7 +359,6 @@ private static void blockUntilQueueFree(final Connection c) { if (!c.canWrite()) { final FutureImpl future = Futures.createSafeFuture(); - // Connection may be obtained by calling FilterChainContext.getConnection(). c.notifyCanWrite(new WriteHandler() { From 5a7fe10c728513e40cc48c10b7c690cc468cc2c9 Mon Sep 17 00:00:00 2001 From: Ryan Lubke Date: Mon, 16 Sep 2013 11:38:57 -0700 Subject: [PATCH 241/264] Add multi-threaded test case for the Grizzly FeedableBodyGenerator. --- .../GrizzlyFeedableBodyGeneratorTest.java | 293 ++++++++++++++++++ 1 file changed, 293 insertions(+) create mode 100644 src/test/java/com/ning/http/client/async/grizzly/GrizzlyFeedableBodyGeneratorTest.java diff --git a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyFeedableBodyGeneratorTest.java b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyFeedableBodyGeneratorTest.java new file mode 100644 index 0000000000..05197ff0a3 --- /dev/null +++ b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyFeedableBodyGeneratorTest.java @@ -0,0 +1,293 @@ +/* + * Copyright (c) 2013 Sonatype, Inc. All rights reserved. + * + * This program is licensed to you under the Apache License Version 2.0, + * and you may not use this file except in compliance with the Apache License Version 2.0. + * You may obtain a copy of the Apache License Version 2.0 at http://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the Apache License Version 2.0 is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under. + */ + +package com.ning.http.client.async.grizzly; + +import com.ning.http.client.AsyncCompletionHandler; +import com.ning.http.client.AsyncHttpClient; +import com.ning.http.client.AsyncHttpClientConfig; +import com.ning.http.client.RequestBuilder; +import com.ning.http.client.providers.grizzly.FeedableBodyGenerator; +import com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProvider; +import org.glassfish.grizzly.Buffer; +import org.glassfish.grizzly.http.server.HttpHandler; +import org.glassfish.grizzly.http.server.HttpServer; +import org.glassfish.grizzly.http.server.NetworkListener; +import org.glassfish.grizzly.http.server.Request; +import org.glassfish.grizzly.http.server.Response; +import org.glassfish.grizzly.memory.Buffers; +import org.glassfish.grizzly.ssl.SSLContextConfigurator; +import org.glassfish.grizzly.ssl.SSLEngineConfigurator; +import org.glassfish.grizzly.utils.Charsets; +import org.testng.annotations.AfterTest; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.Random; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +import static org.glassfish.grizzly.http.server.NetworkListener.DEFAULT_NETWORK_HOST; +import static org.glassfish.grizzly.memory.MemoryManager.DEFAULT_MEMORY_MANAGER; +import static org.testng.Assert.assertNull; +import static org.testng.Assert.fail; +import static org.testng.AssertJUnit.assertEquals; + +public class GrizzlyFeedableBodyGeneratorTest { + + private static final byte[] DATA = + "aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ".getBytes(Charsets.ASCII_CHARSET); + private static final int TEMP_FILE_SIZE = 2 * 1024 * 1024; + private static final int NON_SECURE_PORT = 9991; + private static final int SECURE_PORT = 9992; + + + private HttpServer server; + private File tempFile; + + + // ------------------------------------------------------------------- Setup + + + @BeforeTest + public void setup() throws Exception { + generateTempFile(); + server = new HttpServer(); + NetworkListener nonSecure = + new NetworkListener("nonsecure", + DEFAULT_NETWORK_HOST, + NON_SECURE_PORT); + NetworkListener secure = + new NetworkListener("secure", + DEFAULT_NETWORK_HOST, + SECURE_PORT); + secure.setSecure(true); + secure.setSSLEngineConfig(createSSLConfig()); + server.addListener(nonSecure); + server.addListener(secure); + server.getServerConfiguration().addHttpHandler(new ConsumingHandler(), "/test"); + server.start(); + } + + + // --------------------------------------------------------------- Tear Down + + + @AfterTest + public void tearDown() { + if (!tempFile.delete()) { + tempFile.deleteOnExit(); + } + tempFile = null; + server.shutdownNow(); + server = null; + } + + + // ------------------------------------------------------------ Test Methods + + + @Test + public void testSimpleFeederMultipleThreads() throws Exception { + doSimpleFeeder(false); + } + + @Test + public void testSimpleFeederOverSSLMultipleThreads() throws Exception { + doSimpleFeeder(true); + } + + + // --------------------------------------------------------- Private Methods + + + private void doSimpleFeeder(final boolean secure) { + final int threadCount = 20; + final CountDownLatch latch = new CountDownLatch(threadCount); + final int port = (secure ? SECURE_PORT : NON_SECURE_PORT); + final String scheme = (secure ? "https" : "http"); + ExecutorService service = Executors.newFixedThreadPool(threadCount); + + AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder() + .setMaximumConnectionsPerHost(60) + .setMaximumConnectionsTotal(60) + .build(); + final AsyncHttpClient client = + new AsyncHttpClient(new GrizzlyAsyncHttpProvider(config), config); + final int[] statusCodes = new int[threadCount]; + final int[] totalsReceived = new int[threadCount]; + final Throwable[] errors = new Throwable[threadCount]; + for (int i = 0; i < threadCount; i++) { + final int idx = i; + service.execute(new Runnable() { + @Override + public void run() { + FeedableBodyGenerator generator = + new FeedableBodyGenerator(); + FeedableBodyGenerator.SimpleFeeder simpleFeeder = + new FeedableBodyGenerator.SimpleFeeder(generator) { + @Override + public void flush() throws IOException { + FileInputStream in = null; + try { + final byte[] bytesIn = new byte[2048]; + in = new FileInputStream(tempFile); + int read; + while ((read = in.read(bytesIn)) != -1) { + final Buffer b = + Buffers.wrap( + DEFAULT_MEMORY_MANAGER, + bytesIn, + 0, + read); + feed(b, false); + } + feed(Buffers.EMPTY_BUFFER, true); + } finally { + if (in != null) { + try { + in.close(); + } catch (IOException ignored) { + } + } + } + } + }; + generator.setFeeder(simpleFeeder); + generator.setMaxPendingBytes(10000); + + RequestBuilder builder = new RequestBuilder("POST"); + builder.setUrl(scheme + "://localhost:" + port + "/test"); + builder.setBody(generator); + try { + client.executeRequest(builder.build(), + new AsyncCompletionHandler() { + @Override + public com.ning.http.client.Response onCompleted(com.ning.http.client.Response response) + throws Exception { + try { + totalsReceived[idx] = Integer.parseInt(response.getHeader("x-total")); + } catch (Exception e) { + errors[idx] = e; + } + statusCodes[idx] = response.getStatusCode(); + latch.countDown(); + return response; + } + + @Override + public void onThrowable(Throwable t) { + errors[idx] = t; + t.printStackTrace(); + latch.countDown(); + } + }); + } catch (IOException e) { + errors[idx] = e; + latch.countDown(); + } + } + }); + } + + try { + latch.await(1, TimeUnit.MINUTES); + } catch (InterruptedException e) { + fail("Latch interrupted"); + } + + for (int i = 0; i < threadCount; i++) { + assertEquals(200, statusCodes[i]); + assertNull(errors[i]); + assertEquals(tempFile.length(), totalsReceived[i]); + } + } + + + private static SSLEngineConfigurator createSSLConfig() + throws Exception { + final SSLContextConfigurator sslContextConfigurator = + new SSLContextConfigurator(); + final ClassLoader cl = GrizzlyFeedableBodyGeneratorTest.class.getClassLoader(); + // override system properties + final URL cacertsUrl = cl.getResource("ssltest-cacerts.jks"); + if (cacertsUrl != null) { + sslContextConfigurator.setTrustStoreFile(cacertsUrl.getFile()); + sslContextConfigurator.setTrustStorePass("changeit"); + } + + // override system properties + final URL keystoreUrl = cl.getResource("ssltest-keystore.jks"); + if (keystoreUrl != null) { + sslContextConfigurator.setKeyStoreFile(keystoreUrl.getFile()); + sslContextConfigurator.setKeyStorePass("changeit"); + } + + return new SSLEngineConfigurator( + sslContextConfigurator.createSSLContext(), + false, false, false); + } + + + private void generateTempFile() throws IOException { + tempFile = File.createTempFile("feedable", null); + int total = 0; + byte[] chunk = new byte[1024]; + Random r = new Random(System.currentTimeMillis()); + FileOutputStream out = new FileOutputStream(tempFile); + while (total < TEMP_FILE_SIZE) { + for (int i = 0; i < chunk.length; i++) { + chunk[i] = DATA[r.nextInt(DATA.length)]; + } + out.write(chunk); + total += chunk.length; + } + out.flush(); + out.close(); + } + + + // ---------------------------------------------------------- Nested Classes + + + private static final class ConsumingHandler extends HttpHandler { + + + // -------------------------------------------- Methods from HttpHandler + + + @Override + public void service(Request request, Response response) + throws Exception { + int total = 0; + byte[] bytesIn = new byte[2048]; + InputStream in = request.getInputStream(); + int read; + while ((read = in.read(bytesIn)) != -1) { + total += read; + Thread.sleep(5); + } + response.addHeader("X-Total", Integer.toString(total)); + } + + } // END ConsumingHandler + +} From 6c725af70a47bbe741b39615131680ca98e2ee66 Mon Sep 17 00:00:00 2001 From: Ryan Lubke Date: Mon, 16 Sep 2013 13:29:01 -0700 Subject: [PATCH 242/264] Add grizzly-http-server test dep. --- pom.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pom.xml b/pom.xml index 9cbcc145fd..7856c86eee 100644 --- a/pom.xml +++ b/pom.xml @@ -492,6 +492,12 @@ 2.3.5 true + + org.glassfish.grizzly + grizzly-http-server + 2.3.5 + test + From f7bcdb0310f12d70d2ab9f9a06bbe776dda1ca3b Mon Sep 17 00:00:00 2001 From: Ryan Lubke Date: Mon, 16 Sep 2013 13:30:11 -0700 Subject: [PATCH 243/264] Ensure ordered logging of requests. --- .../providers/grizzly/GrizzlyAsyncHttpProvider.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java index 4050a8e0d5..c735655a80 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java @@ -561,13 +561,17 @@ boolean sendRequest(final FilterChainContext ctx, handler = new ExpectHandler(handler); } context.bodyHandler = handler; + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("REQUEST: " + requestPacket.toString()); + } isWriteComplete = handler.doHandle(ctx, request, requestPacket); } else { + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("REQUEST: " + requestPacket.toString()); + } ctx.write(requestPacket, ctx.getTransportContext().getCompletionHandler()); } - if (LOGGER.isDebugEnabled()) { - LOGGER.debug("REQUEST: " + requestPacket.toString()); - } + return isWriteComplete; } From 6184f2e7f0e9349e0197630f2d948bc6efc2d726 Mon Sep 17 00:00:00 2001 From: Ryan Lubke Date: Thu, 19 Sep 2013 10:51:08 -0700 Subject: [PATCH 244/264] Bug fixing and cleanup. - ensure total cached connections is decremented in all cases. - Remove deprecated API usage --- .../grizzly/GrizzlyConnectionsPool.java | 64 ++++++++++++------- 1 file changed, 42 insertions(+), 22 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyConnectionsPool.java b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyConnectionsPool.java index 50e1a93969..3b9a80db38 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyConnectionsPool.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyConnectionsPool.java @@ -18,11 +18,13 @@ import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.ConnectionsPool; +import org.glassfish.grizzly.CloseListener; +import org.glassfish.grizzly.CloseType; import org.glassfish.grizzly.Connection; import org.glassfish.grizzly.Grizzly; import org.glassfish.grizzly.attributes.Attribute; -import org.glassfish.grizzly.attributes.NullaryFunction; import org.glassfish.grizzly.utils.DataStructures; +import org.glassfish.grizzly.utils.NullaryFunction; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -62,12 +64,14 @@ public class GrizzlyConnectionsPool implements ConnectionsPool() { + public void onClosed(Connection connection, CloseType closeType) + throws IOException { + if (closeType == CloseType.REMOTELY) { if (LOG.isInfoEnabled()) { - LOG.info("Remote closed connection ({}). Removing from cache", connection.toString()); + LOG.info("Remote closed connection ({}). Removing from cache", + connection.toString()); } } GrizzlyConnectionsPool.this.removeAll(connection); @@ -78,6 +82,7 @@ public void onClosed(Connection connection, Connection.CloseType closeType) thro // ------------------------------------------------------------ Constructors + @SuppressWarnings("UnusedDeclaration") public GrizzlyConnectionsPool(final boolean cacheSSLConnections, final int timeout, final int maxConnectionLifeTimeInMs, @@ -94,10 +99,14 @@ public GrizzlyConnectionsPool(final boolean cacheSSLConnections, this.delayedExecutor = delayedExecutor; ownsDelayedExecutor = false; } else { - this.delayedExecutor = new DelayedExecutor(Executors.newSingleThreadExecutor()); - delayedExecutor.start(); + this.delayedExecutor = + new DelayedExecutor(Executors.newSingleThreadExecutor(), + this); ownsDelayedExecutor = true; } + if (!this.delayedExecutor.isStarted) { + this.delayedExecutor.start(); + } } @@ -109,7 +118,7 @@ public GrizzlyConnectionsPool(final AsyncHttpClientConfig config) { maxConnectionsPerHost = config.getMaxConnectionPerHost(); maxConnections = config.getMaxTotalConnections(); unlimitedConnections = (maxConnections == -1); - delayedExecutor = new DelayedExecutor(Executors.newSingleThreadExecutor()); + delayedExecutor = new DelayedExecutor(Executors.newSingleThreadExecutor(), this); delayedExecutor.start(); ownsDelayedExecutor = true; } @@ -148,13 +157,14 @@ public boolean offer(String uri, Connection connection) { final int total = totalCachedConnections.incrementAndGet(); if (LOG.isDebugEnabled()) { LOG.debug("[offer] Pooling connection [{}] for uri [{}]. Current size (for host; before pooling): [{}]. Max size (for host): [{}]. Total number of cached connections: [{}].", - new Object[]{connection, uri, size, maxConnectionsPerHost, total}); + connection, uri, size, maxConnectionsPerHost, total); } return true; } if (LOG.isDebugEnabled()) { LOG.debug("[offer] Unable to pool connection [{}] for uri [{}]. Current size (for host): [{}]. Max size (for host): [{}]. Total number of cached connections: [{}].", - new Object[]{connection, uri, size, maxConnectionsPerHost, totalCachedConnections.get()}); + connection, uri, size, maxConnectionsPerHost, + totalCachedConnections.get()); } return false; @@ -217,6 +227,9 @@ public boolean removeAll(Connection connection) { boolean isRemoved = false; for (Map.Entry entry : connectionsPool.entrySet()) { boolean removed = entry.getValue().remove(connection); + if (removed) { + totalCachedConnections.decrementAndGet(); + } isRemoved |= removed; } return isRemoved; @@ -279,25 +292,31 @@ public static final class DelayedExecutor { private final Object sync = new Object(); private volatile boolean isStarted; private final long checkIntervalMs; + private final AtomicInteger totalCachedConnections; // -------------------------------------------------------- Constructors - public DelayedExecutor(final ExecutorService threadPool) { - this(threadPool, 1000, TimeUnit.MILLISECONDS); + public DelayedExecutor(final ExecutorService threadPool, + final GrizzlyConnectionsPool connectionsPool) { + this(threadPool, 1000, TimeUnit.MILLISECONDS, connectionsPool); } - // ----------------------------------------------------- Private Methods - public DelayedExecutor(final ExecutorService threadPool, final long checkInterval, - final TimeUnit timeunit) { + final TimeUnit timeunit, + final GrizzlyConnectionsPool connectionsPool) { this.threadPool = threadPool; this.checkIntervalMs = TimeUnit.MILLISECONDS.convert(checkInterval, timeunit); + totalCachedConnections = connectionsPool.totalCachedConnections; } + + // ----------------------------------------------------- Private Methods + + private void start() { synchronized (sync) { if (!isStarted) { @@ -327,8 +346,8 @@ private IdleConnectionQueue createIdleConnectionQueue(final long timeout, final } @SuppressWarnings({"NumberEquality"}) - private static boolean wasModified(final Long l1, final Long l2) { - return l1 != l2 && (l1 != null ? !l1.equals(l2) : !l2.equals(l1)); + private static boolean wasModified(final long l1, final long l2) { + return l1 != l2; } @@ -352,7 +371,7 @@ public void run() { final Connection element = it.next(); final Long timeoutMs = resolver.getTimeoutMs(element); - if (timeoutMs == null || timeoutMs == UNSET_TIMEOUT) { + if (timeoutMs == UNSET_TIMEOUT) { it.remove(); if (wasModified(timeoutMs, resolver.getTimeoutMs(element))) { @@ -368,7 +387,8 @@ public void run() { if (LOG.isDebugEnabled()) { LOG.debug("Idle connection ({}) detected. Removing from cache.", element.toString()); } - element.close().markForRecycle(true); + totalCachedConnections.decrementAndGet(); + element.close(); } catch (Exception ignored) { } } @@ -460,7 +480,7 @@ boolean isEmpty() { void destroy() { for (Connection c : queue) { - c.close().markForRecycle(true); + c.close(); } queue.clear(); queues.remove(this); @@ -494,7 +514,7 @@ boolean removeTimeout(final Connection c) { return true; } - Long getTimeoutMs(final Connection c) { + long getTimeoutMs(final Connection c) { return IDLE_ATTR.get(c).timeoutMs; } From f93bb0cea2f64476580e16e6aa55fdf433f5b25d Mon Sep 17 00:00:00 2001 From: Ryan Lubke Date: Fri, 20 Sep 2013 09:42:59 -0700 Subject: [PATCH 245/264] Tweak previous fix. --- .../client/providers/grizzly/GrizzlyConnectionsPool.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyConnectionsPool.java b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyConnectionsPool.java index 3b9a80db38..8859fb821c 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyConnectionsPool.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyConnectionsPool.java @@ -227,11 +227,11 @@ public boolean removeAll(Connection connection) { boolean isRemoved = false; for (Map.Entry entry : connectionsPool.entrySet()) { boolean removed = entry.getValue().remove(connection); - if (removed) { - totalCachedConnections.decrementAndGet(); - } isRemoved |= removed; } + if (isRemoved) { + totalCachedConnections.decrementAndGet(); + } return isRemoved; } From 8363477940316fa4bd636c156356b5ca39cbc69c Mon Sep 17 00:00:00 2001 From: Ryan Lubke Date: Fri, 20 Sep 2013 10:25:38 -0700 Subject: [PATCH 246/264] Update to Grizzly 2.3.6. --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 7856c86eee..8cb5301569 100644 --- a/pom.xml +++ b/pom.xml @@ -489,7 +489,7 @@ org.glassfish.grizzly grizzly-websockets - 2.3.5 + 2.3.6 true From 80fac585252cbf978bc5d8f859e384f8619698ca Mon Sep 17 00:00:00 2001 From: Ryan Lubke Date: Fri, 20 Sep 2013 10:42:53 -0700 Subject: [PATCH 247/264] Set multiplier to two. --- .../java/com/ning/http/client/AsyncHttpClientConfigBean.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/ning/http/client/AsyncHttpClientConfigBean.java b/src/main/java/com/ning/http/client/AsyncHttpClientConfigBean.java index a9ed1218e9..8ea0b17459 100644 --- a/src/main/java/com/ning/http/client/AsyncHttpClientConfigBean.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClientConfigBean.java @@ -54,7 +54,7 @@ void configureDefaults() { maxDefaultRedirects = Integer.getInteger(ASYNC_CLIENT + "defaultMaxRedirects", 5); compressionEnabled = Boolean.getBoolean(ASYNC_CLIENT + "compressionEnabled"); userAgent = System.getProperty(ASYNC_CLIENT + "userAgent", "NING/1.0"); - ioThreadMultiplier = Integer.getInteger(ASYNC_CLIENT + "ioThreadMultiplier", 8); + ioThreadMultiplier = Integer.getInteger(ASYNC_CLIENT + "ioThreadMultiplier", 2); boolean useProxySelector = Boolean.getBoolean(ASYNC_CLIENT + "useProxySelector"); boolean useProxyProperties = Boolean.getBoolean(ASYNC_CLIENT + "useProxyProperties"); From f3eaf19c16f01a774e97b1504d54a8df5b745ee7 Mon Sep 17 00:00:00 2001 From: Ryan Lubke Date: Fri, 20 Sep 2013 13:58:03 -0700 Subject: [PATCH 248/264] [maven-release-plugin] prepare release async-http-client-1.7.20 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 8cb5301569..55c2feb382 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.7.20-SNAPSHOT + 1.7.20 jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From 69dde1036b5c3c0ca41a08a136eea323be3cc495 Mon Sep 17 00:00:00 2001 From: Ryan Lubke Date: Fri, 20 Sep 2013 13:58:07 -0700 Subject: [PATCH 249/264] [maven-release-plugin] prepare for next development iteration --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 55c2feb382..20f2cf1e4b 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.7.20 + 1.7.21-SNAPSHOT jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From a93d327b1905c78497df123e74da491dfb4e7162 Mon Sep 17 00:00:00 2001 From: Ryan Lubke Date: Mon, 23 Sep 2013 16:47:47 -0700 Subject: [PATCH 250/264] Port fix from master. --- .../http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java index c735655a80..d28afb932a 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java @@ -1688,7 +1688,7 @@ private static final class ClientEncodingFilter implements EncodingFilter { public boolean applyEncoding(HttpHeader httpPacket) { httpPacket.addHeader(Header.AcceptEncoding, "gzip"); - return true; + return false; } From 296e71c33874064bc219dfcf4902e626ec70f52f Mon Sep 17 00:00:00 2001 From: Ryan Lubke Date: Mon, 23 Sep 2013 20:19:05 -0700 Subject: [PATCH 251/264] Reduce thread count to debug hudson failure. --- .../client/async/grizzly/GrizzlyFeedableBodyGeneratorTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyFeedableBodyGeneratorTest.java b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyFeedableBodyGeneratorTest.java index 05197ff0a3..df46368153 100644 --- a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyFeedableBodyGeneratorTest.java +++ b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyFeedableBodyGeneratorTest.java @@ -120,7 +120,7 @@ public void testSimpleFeederOverSSLMultipleThreads() throws Exception { private void doSimpleFeeder(final boolean secure) { - final int threadCount = 20; + final int threadCount = 10; final CountDownLatch latch = new CountDownLatch(threadCount); final int port = (secure ? SECURE_PORT : NON_SECURE_PORT); final String scheme = (secure ? "https" : "http"); From 169051cb72ff8487696cd7e19a20e3654f50fc49 Mon Sep 17 00:00:00 2001 From: Petri Louhelainen Date: Thu, 26 Sep 2013 10:37:52 +0300 Subject: [PATCH 252/264] Fix sending multipart bodies through SocketChannel. As per documentation, selector.select() returns only keys that have updated and therefore even if it return zero, it doesn't mean that selectedKeys wouldn't contain keys that are writable. See http://stackoverflow.com/questions/9939989/java-nio-selector-select-returns-0-although-channels-are-ready and http://docs.oracle.com/javase/7/docs/api/java/nio/channels/Selector.html#select() for more details. This commit utilizes the same maxSpin already used in FileChannel case for detecting that writing has stuck somewhere. A configurable timeout for select would be the obvious better solution. --- .../java/com/ning/http/multipart/MultipartBody.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/ning/http/multipart/MultipartBody.java b/src/main/java/com/ning/http/multipart/MultipartBody.java index 55799a3266..2fadcc36e3 100644 --- a/src/main/java/com/ning/http/multipart/MultipartBody.java +++ b/src/main/java/com/ning/http/multipart/MultipartBody.java @@ -578,18 +578,21 @@ private long writeToTarget(WritableByteChannel target, ByteArrayOutputStream byt final SocketChannel channel = (SocketChannel) target; channel.register(selector, SelectionKey.OP_WRITE); - while (written < byteWriter.size() && selector.select() != 0) { + while (written < byteWriter.size()) { + selector.select(1000); + maxSpin++; final Set selectedKeys = selector.selectedKeys(); for (SelectionKey key : selectedKeys) { if (key.isWritable()) { written += target.write(message); + maxSpin = 0; } } - } - if (written < byteWriter.size()) { - throw new IOException("Unable to write on channel " + target); + if (maxSpin >= 10) { + throw new IOException("Unable to write on channel " + target); + } } } finally { selector.close(); From fb2daaca6441d9846db25ffccc194f9921b5a3c8 Mon Sep 17 00:00:00 2001 From: Petri Louhelainen Date: Thu, 26 Sep 2013 12:57:31 +0300 Subject: [PATCH 253/264] Send Content-Disposition header without filename too Some servers, e.g. Jetty save multipart parts with filename present in content disposition header to disk. To prevent this we want to be able to send Content-Disposition header with name only (so we can easily access it) but not store bytes to disk to prevent unwanted IO. --- src/main/java/com/ning/http/multipart/FilePart.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/ning/http/multipart/FilePart.java b/src/main/java/com/ning/http/multipart/FilePart.java index ac6c1972b9..41b7e7025c 100644 --- a/src/main/java/com/ning/http/multipart/FilePart.java +++ b/src/main/java/com/ning/http/multipart/FilePart.java @@ -147,8 +147,8 @@ public FilePart(String name, String fileName, File file, String contentType, Str */ protected void sendDispositionHeader(OutputStream out) throws IOException { String filename = this.source.getFileName(); + super.sendDispositionHeader(out); if (filename != null) { - super.sendDispositionHeader(out); out.write(FILE_NAME_BYTES); out.write(QUOTE_BYTES); out.write(MultipartEncodingUtil.getAsciiBytes(filename)); From d0bc3fc12370a6666592aa94b5e5b8e970664139 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 4 Oct 2013 01:10:07 +0200 Subject: [PATCH 254/264] Backport #391 --- .../providers/apache/ApacheResponse.java | 11 ++++++++- .../providers/grizzly/GrizzlyResponse.java | 23 ++++++++----------- .../client/providers/jdk/JDKResponse.java | 11 ++++++++- .../client/providers/netty/NettyResponse.java | 11 ++++++++- 4 files changed, 40 insertions(+), 16 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/apache/ApacheResponse.java b/src/main/java/com/ning/http/client/providers/apache/ApacheResponse.java index c0ad75bc47..988962dbdd 100644 --- a/src/main/java/com/ning/http/client/providers/apache/ApacheResponse.java +++ b/src/main/java/com/ning/http/client/providers/apache/ApacheResponse.java @@ -146,7 +146,16 @@ public FluentCaseInsensitiveStringsMap getHeaders() { /* @Override */ public boolean isRedirected() { - return (status.getStatusCode() >= 300) && (status.getStatusCode() <= 399); + switch (status.getStatusCode()) { + case 301: + case 302: + case 303: + case 307: + case 308: + return true; + default: + return false; + } } /* @Override */ diff --git a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponse.java b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponse.java index 93c434e960..8df137e885 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponse.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponse.java @@ -248,9 +248,16 @@ public FluentCaseInsensitiveStringsMap getHeaders() { * {@inheritDoc} */ public boolean isRedirected() { - - return between(status.getStatusCode(), 300, 399); - + switch (status.getStatusCode()) { + case 301: + case 302: + case 303: + case 307: + case 308: + return true; + default: + return false; + } } @@ -345,14 +352,4 @@ private Charset getCharset(final String charset) { return Charsets.lookupCharset(charsetLocal); } - - - private boolean between(final int value, - final int lowerBound, - final int upperBound) { - - return (value >= lowerBound && value <= upperBound); - - } - } \ No newline at end of file diff --git a/src/main/java/com/ning/http/client/providers/jdk/JDKResponse.java b/src/main/java/com/ning/http/client/providers/jdk/JDKResponse.java index 0981731bb0..00cae65b0a 100644 --- a/src/main/java/com/ning/http/client/providers/jdk/JDKResponse.java +++ b/src/main/java/com/ning/http/client/providers/jdk/JDKResponse.java @@ -161,7 +161,16 @@ public FluentCaseInsensitiveStringsMap getHeaders() { /* @Override */ public boolean isRedirected() { - return (status.getStatusCode() >= 300) && (status.getStatusCode() <= 399); + switch (status.getStatusCode()) { + case 301: + case 302: + case 303: + case 307: + case 308: + return true; + default: + return false; + } } /* @Override */ diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyResponse.java b/src/main/java/com/ning/http/client/providers/netty/NettyResponse.java index 4269bb7187..787501d3fd 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyResponse.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyResponse.java @@ -170,7 +170,16 @@ public FluentCaseInsensitiveStringsMap getHeaders() { /* @Override */ public boolean isRedirected() { - return (status.getStatusCode() >= 300) && (status.getStatusCode() <= 399); + switch (status.getStatusCode()) { + case 301: + case 302: + case 303: + case 307: + case 308: + return true; + default: + return false; + } } /* @Override */ From a0788dc04135fde909d0532e958d0969d22b9d14 Mon Sep 17 00:00:00 2001 From: Ryan Lubke Date: Wed, 9 Oct 2013 13:26:01 -0700 Subject: [PATCH 255/264] Ensure onStatusReceived() is invoked when there is no realm. --- .../client/providers/grizzly/GrizzlyAsyncHttpProvider.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java index d28afb932a..2d31175bdb 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java @@ -1475,6 +1475,13 @@ public boolean handleStatus(final HttpResponsePacket responsePacket, } if (realm == null) { httpTransactionContext.invocationStatus = InvocationStatus.STOP; + if (httpTransactionContext.handler != null) { + try { + httpTransactionContext.handler.onStatusReceived(httpTransactionContext.responseStatus); + } catch (Exception e) { + httpTransactionContext.abort(e); + } + } return true; } From 86df1618d5b52d369dfae8f4a8f93a57f3620022 Mon Sep 17 00:00:00 2001 From: Ryan Lubke Date: Thu, 10 Oct 2013 13:18:54 -0700 Subject: [PATCH 256/264] Always switch SSL modes if necessary. --- .../grizzly/GrizzlyAsyncHttpProvider.java | 38 +++++++++++++++++-- 1 file changed, 34 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java index 2d31175bdb..66828f7c91 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java @@ -15,6 +15,7 @@ import static com.ning.http.util.MiscUtil.isNonEmpty; +import com.ning.http.client.AsyncHttpClient; import com.ning.org.jboss.netty.handler.codec.http.CookieDecoder; import com.ning.http.client.AsyncHandler; import com.ning.http.client.AsyncHttpClientConfig; @@ -127,6 +128,7 @@ import java.net.URISyntaxException; import java.net.URLEncoder; import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; import java.util.Collection; import java.util.HashMap; import java.util.List; @@ -889,9 +891,9 @@ private boolean sendAsGrizzlyRequest(final Request request, requestPacket = builder.build(); } requestPacket.setSecure(secure); - if (secure) { - ctx.notifyDownstream(new SwitchingSSLFilter.SSLSwitchingEvent(true, ctx.getConnection())); - } + + ctx.notifyDownstream(new SwitchingSSLFilter.SSLSwitchingEvent(secure, ctx.getConnection())); + if (!useProxy && !httpCtx.isWSRequest) { addQueryString(request, requestPacket); } @@ -2839,7 +2841,35 @@ public int hashCode() { return result; } } // END AHCWebSocketListenerAdapter - + + + public static void main(String[] args) { + SecureRandom secureRandom = new SecureRandom(); + SSLContext sslContext = null; + try { + sslContext = SSLContext.getInstance("TLS"); + sslContext.init(null, null, secureRandom); + } catch (Exception e) { + e.printStackTrace(); + } + AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder() + .setConnectionTimeoutInMs(5000) + .setSSLContext(sslContext).build(); + AsyncHttpClient client = new AsyncHttpClient(new GrizzlyAsyncHttpProvider(config), config); + try { + long start = System.currentTimeMillis(); + try { + client.executeRequest(client.prepareGet("http://www.google.com/").build()).get(); + } catch (InterruptedException e) { + e.printStackTrace(); + } catch (ExecutionException e) { + e.printStackTrace(); + } + System.out.println("COMPLETE: " + (System.currentTimeMillis() - start) + "ms"); + } catch (IOException e) { + e.printStackTrace(); + } + } } From da09dbe37616f15843f65d3c3c27fdbc95321e90 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 14 Oct 2013 23:46:06 +0200 Subject: [PATCH 257/264] Remove getPredefinedContentLength --- .../providers/netty/NettyAsyncHttpProvider.java | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java index 4a0e4ac4d2..1722c6e0cf 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyAsyncHttpProvider.java @@ -818,7 +818,7 @@ else if (uri.getRawQuery() != null) nettyRequest.setHeader(HttpHeaders.Names.CONTENT_LENGTH, String.valueOf(mre.getContentLength())); } else if (request.getEntityWriter() != null) { - int length = getPredefinedContentLength(request, nettyRequest); + int length = (int) request.getContentLength(); if (length == -1) { length = MAX_BUFFERED_BYTES; @@ -1609,15 +1609,6 @@ protected static boolean abortOnWriteCloseException(Throwable cause) { return false; } - private final static int getPredefinedContentLength(Request request, HttpRequest r) { - int length = (int) request.getContentLength(); - if (length == -1 && r.getHeader(HttpHeaders.Names.CONTENT_LENGTH) != null) { - length = Integer.valueOf(r.getHeader(HttpHeaders.Names.CONTENT_LENGTH)); - } - - return length; - } - public static NettyResponseFuture newFuture(URI uri, Request request, AsyncHandler asyncHandler, HttpRequest nettyRequest, AsyncHttpClientConfig config, NettyAsyncHttpProvider provider, ProxyServer proxyServer) { NettyResponseFuture f = new NettyResponseFuture(uri,// From 3897106d715a3de8dd6d8a83d4e2041d0d1007ea Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 14 Oct 2013 23:46:23 +0200 Subject: [PATCH 258/264] Add RequestBuilder.setURI, like setUrl, backport #405 --- .../ning/http/client/RequestBuilderBase.java | 35 ++++--------------- 1 file changed, 7 insertions(+), 28 deletions(-) diff --git a/src/main/java/com/ning/http/client/RequestBuilderBase.java b/src/main/java/com/ning/http/client/RequestBuilderBase.java index c1e451fa38..98559f2744 100644 --- a/src/main/java/com/ning/http/client/RequestBuilderBase.java +++ b/src/main/java/com/ning/http/client/RequestBuilderBase.java @@ -370,7 +370,12 @@ protected RequestBuilderBase(Class derived, Request prototype) { } public T setUrl(String url) { - request.originalUri = buildURI(url); + return setURI(URI.create(url)); + } + + public T setURI(URI uri) { + request.originalUri = uri; + addQueryParameters(request.originalUri); request.uri = null; request.rawUri = null; return derived.cast(this); @@ -386,32 +391,7 @@ public T setLocalInetAddress(InetAddress address) { return derived.cast(this); } - private URI buildURI(String url) { - URI uri = URI.create(url); - - if (uri.getRawPath() == null) { - // AHC-96 - // Let's try to derive it - StringBuilder buildedUrl = new StringBuilder(); - - if (uri.getScheme() != null) { - buildedUrl.append(uri.getScheme()); - buildedUrl.append("://"); - } - - if (uri.getAuthority() != null) { - buildedUrl.append(uri.getAuthority()); - } - if (url.indexOf("://") == -1) { - String s = buildedUrl.toString(); - url = s + url.substring(uri.getScheme().length() + 1); - return buildURI(url); - } else { - throw new IllegalArgumentException("Invalid url " - + uri.toString()); - } - } - + private void addQueryParameters(URI uri) { if (isNonEmpty(uri.getRawQuery())) { String[] queries = uri.getRawQuery().split("&"); int pos; @@ -432,7 +412,6 @@ private URI buildURI(String url) { } } } - return uri; } public T setVirtualHost(String virtualHost) { From d4ec320a4cf4c7acde7597bcb7e4ff0f8590ae9a Mon Sep 17 00:00:00 2001 From: Ryan Lubke Date: Tue, 15 Oct 2013 09:10:26 -0700 Subject: [PATCH 259/264] Fix for #402. --- .../http/client/AsyncHttpClientConfig.java | 26 +++++++++++++++---- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java b/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java index a147bbe48b..e5b8a20736 100644 --- a/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java @@ -447,9 +447,29 @@ public boolean isRemoveQueryParamOnRedirect() { * Return true if one of the {@link java.util.concurrent.ExecutorService} has been shutdown. * * @return true if one of the {@link java.util.concurrent.ExecutorService} has been shutdown. + * + * @deprecated use #isValid */ public boolean isClosed() { - return applicationThreadPool.isShutdown() || reaper.isShutdown(); + return !isValid(); + } + + /** + * @return true if both the application and reaper thread pools + * haven't yet been shutdown. + * + * @since 1.7.21 + */ + public boolean isValid() { + boolean atpRunning = true; + try { + atpRunning = applicationThreadPool.isShutdown(); + } catch (Exception ignore) { + // isShutdown() will thrown an exception in an EE7 environment + // when using a ManagedExecutorService. + // When this is the case, we assume it's running. + } + return (atpRunning && !reaper.isShutdown()); } /** @@ -1123,10 +1143,6 @@ public Thread newThread(Runnable r) { }); } - if (applicationThreadPool.isShutdown()) { - throw new IllegalStateException("ExecutorServices closed"); - } - if (proxyServerSelector == null && useProxySelector) { proxyServerSelector = ProxyUtils.getJdkDefaultProxyServerSelector(); } From 34fa953999b67b2568c2142f13eff5a9ec06828f Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 16 Oct 2013 08:22:59 +0200 Subject: [PATCH 260/264] Fix invalidUri test, crappy url format should be supported --- src/main/java/com/ning/http/client/RequestBuilderBase.java | 3 +++ .../com/ning/http/client/async/AsyncProvidersBasicTest.java | 6 ++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/ning/http/client/RequestBuilderBase.java b/src/main/java/com/ning/http/client/RequestBuilderBase.java index 98559f2744..6749cfa767 100644 --- a/src/main/java/com/ning/http/client/RequestBuilderBase.java +++ b/src/main/java/com/ning/http/client/RequestBuilderBase.java @@ -20,6 +20,7 @@ import com.ning.http.client.Request.EntityWriter; import com.ning.http.util.AsyncHttpProviderUtils; import com.ning.http.util.UTF8UrlEncoder; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -374,6 +375,8 @@ public T setUrl(String url) { } public T setURI(URI uri) { + if (uri.getPath() == null) + throw new IllegalArgumentException("Unsupported uri format: " + uri); request.originalUri = uri; addQueryParameters(request.originalUri); request.uri = null; diff --git a/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java b/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java index 8e37eefffd..b17e263423 100755 --- a/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java +++ b/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java @@ -1666,13 +1666,11 @@ protected String getBrokenTargetUrl() { return String.format("http:127.0.0.1:%d/foo/test", port1); } - @Test(groups = { "standalone", "default_provider" }) + @Test(groups = { "standalone", "default_provider" }, expectedExceptions = { IllegalArgumentException.class }) public void invalidUri() throws Exception { AsyncHttpClient client = getAsyncHttpClient(null); try { - AsyncHttpClient.BoundRequestBuilder builder = client.prepareGet(getBrokenTargetUrl()); - Response r = client.executeRequest(builder.build()).get(); - assertEquals(200, r.getStatusCode()); + client.prepareGet(getBrokenTargetUrl()); } finally { client.close(); } From 495eaef7485ec792df880600c60eb1e3f5af1b56 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 16 Oct 2013 12:51:24 +0200 Subject: [PATCH 261/264] Clean up: don't throw in finally blocks --- .../providers/netty/NettyResponseFuture.java | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyResponseFuture.java b/src/main/java/com/ning/http/client/providers/netty/NettyResponseFuture.java index ab43dc91c2..171a2bda6c 100755 --- a/src/main/java/com/ning/http/client/providers/netty/NettyResponseFuture.java +++ b/src/main/java/com/ning/http/client/providers/netty/NettyResponseFuture.java @@ -241,15 +241,17 @@ public V get(long l, TimeUnit tu) throws InterruptedException, TimeoutException, } catch (Throwable t) { // Ignore } - TimeoutException te = new TimeoutException(String.format("No response received after %s", l)); if (!throwableCalled.getAndSet(true)) { try { - asyncHandler.onThrowable(te); - } catch (Throwable t) { - logger.debug("asyncHandler.onThrowable", t); + TimeoutException te = new TimeoutException(String.format("No response received after %s", l)); + try { + asyncHandler.onThrowable(te); + } catch (Throwable t) { + logger.debug("asyncHandler.onThrowable", t); + } + throw new ExecutionException(te); } finally { cancelReaper(); - throw new ExecutionException(te); } } } @@ -278,12 +280,14 @@ V getContent() throws ExecutionException { } catch (Throwable ex) { if (!throwableCalled.getAndSet(true)) { try { - asyncHandler.onThrowable(ex); - } catch (Throwable t) { - logger.debug("asyncHandler.onThrowable", t); + try { + asyncHandler.onThrowable(ex); + } catch (Throwable t) { + logger.debug("asyncHandler.onThrowable", t); + } + throw new RuntimeException(ex); } finally { cancelReaper(); - throw new RuntimeException(ex); } } } From f4c5142f2cbb98305f93e91c3e6a1845cd8b5b11 Mon Sep 17 00:00:00 2001 From: Ryan Lubke Date: Wed, 16 Oct 2013 10:07:30 -0700 Subject: [PATCH 262/264] [maven-release-plugin] prepare release async-http-client-1.7.21 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 20f2cf1e4b..d4182e8087 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.7.21-SNAPSHOT + 1.7.21 jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From 82f6c2bf81b73d65895a63f54067c91e7ad93389 Mon Sep 17 00:00:00 2001 From: Ryan Lubke Date: Wed, 16 Oct 2013 10:07:34 -0700 Subject: [PATCH 263/264] [maven-release-plugin] prepare for next development iteration --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index d4182e8087..b65610df90 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.7.21 + 1.7.22-SNAPSHOT jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From b6b1ea678bfeef3ca4ea1e51ed1e88280cac2680 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 16 Oct 2013 22:33:30 +0200 Subject: [PATCH 264/264] removeQuotes minor optim --- .../http/util/AsyncHttpProviderUtils.java | 23 ++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java index e2e7631b18..bc910361b6 100644 --- a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java +++ b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java @@ -498,7 +498,7 @@ public static Cookie parseCookie(String value) { } public static int convertExpireField(String timestring) { - String trimmedTimeString = removeQuote(timestring.trim()); + String trimmedTimeString = removeQuotes(timestring.trim()); long now = System.currentTimeMillis(); Date date = null; @@ -515,13 +515,24 @@ public static int convertExpireField(String timestring) { throw new IllegalArgumentException("Not a valid expire field " + trimmedTimeString); } - private final static String removeQuote(String s) { + public final static String removeQuotes(String s) { if (MiscUtil.isNonEmpty(s)) { - if (s.charAt(0) == '"') - s = s.substring(1); + int start = 0; + int end = s.length(); + boolean changed = false; - if (s.charAt(s.length() - 1) == '"') - s = s.substring(0, s.length() - 1); + if (s.charAt(0) == '"') { + changed = true; + start++; + } + + if (s.charAt(s.length() - 1) == '"') { + changed = true; + end--; + } + + if (changed) + s = s.substring(start, end); } return s; }