From ab14306ab64b59c201e8c5aae5c901b83a99c261 Mon Sep 17 00:00:00 2001 From: jfarcand Date: Thu, 30 May 2013 17:03:27 -0400 Subject: [PATCH 001/701] [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 002/701] 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 003/701] 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 004/701] 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 005/701] 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 006/701] 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 007/701] 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 008/701] 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 009/701] 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 010/701] 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 011/701] 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 012/701] 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 013/701] 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 014/701] 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 015/701] 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 016/701] 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 017/701] 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 018/701] 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 019/701] 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 020/701] 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 021/701] 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 022/701] 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 023/701] 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 024/701] 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 025/701] 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 026/701] 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 027/701] 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 028/701] 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 029/701] 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 030/701] 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 031/701] 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 032/701] [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 033/701] [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 034/701] 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 035/701] 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 036/701] 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 037/701] 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 038/701] 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 039/701] 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 040/701] 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 041/701] 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 042/701] 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 043/701] 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 044/701] 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 045/701] 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 046/701] 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 047/701] 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 048/701] 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 049/701] 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 050/701] 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 051/701] 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 052/701] 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 053/701] 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 054/701] 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 055/701] 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 056/701] 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 057/701] 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 058/701] 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 059/701] 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 060/701] 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 061/701] 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 062/701] 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 063/701] 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 064/701] 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 065/701] 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 066/701] 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 067/701] 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 068/701] 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 069/701] 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 070/701] 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 071/701] 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 072/701] 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 073/701] [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 074/701] [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 075/701] 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 076/701] 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 077/701] 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 078/701] 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 079/701] - 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 080/701] 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 081/701] 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 082/701] 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 083/701] 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 084/701] 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 085/701] 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 086/701] 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 087/701] 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 088/701] 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 089/701] 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 090/701] 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 091/701] 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 092/701] 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 093/701] 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 094/701] 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 095/701] 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 096/701] 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 097/701] 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 098/701] 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 099/701] 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 100/701] 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 101/701] 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 102/701] [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 103/701] [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 104/701] 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 105/701] 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 106/701] 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 107/701] 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 108/701] 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 109/701] 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 110/701] 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 111/701] 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 112/701] 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 113/701] 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 114/701] 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 115/701] 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 116/701] [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 117/701] [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 118/701] 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; } From 48c5765cb54054dd77b5dce16b522e8566c40597 Mon Sep 17 00:00:00 2001 From: Ryan Lubke Date: Thu, 24 Oct 2013 18:52:16 -0700 Subject: [PATCH 119/701] Fix for #407. --- .../client/providers/grizzly/GrizzlyAsyncHttpProvider.java | 4 ++-- 1 file changed, 2 insertions(+), 2 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 66828f7c91..2f7b9540cd 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 @@ -868,7 +868,7 @@ private boolean sendAsGrizzlyRequest(final Request request, } if (requestHasEntityBody(request)) { final long contentLength = request.getContentLength(); - if (contentLength > 0) { + if (contentLength >= 0) { builder.contentLength(contentLength); builder.chunked(false); } else { @@ -2193,7 +2193,7 @@ public boolean doHandle(final FilterChainContext ctx, final BodyGenerator generator = request.getBodyGenerator(); final Body bodyLocal = generator.createBody(); final long len = bodyLocal.getContentLength(); - if (len > 0) { + if (len >= 0) { requestPacket.setContentLengthLong(len); } else { requestPacket.setChunked(true); From 06203e3fbbac1ee2e33a13e8a7168e6978dd91e1 Mon Sep 17 00:00:00 2001 From: Ryan Lubke Date: Fri, 25 Oct 2013 09:46:05 -0700 Subject: [PATCH 120/701] Leverage utility class for determining thread type. --- .../client/providers/grizzly/FeedableBodyGenerator.java | 9 ++++----- 1 file changed, 4 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 e9d826b651..5024d30c51 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 @@ -33,6 +33,7 @@ import org.glassfish.grizzly.nio.SelectorRunner; import org.glassfish.grizzly.ssl.SSLBaseFilter; import org.glassfish.grizzly.ssl.SSLFilter; +import org.glassfish.grizzly.threadpool.Threads; import org.glassfish.grizzly.utils.Futures; import static com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProvider.getHttpTransactionContext; @@ -193,7 +194,7 @@ public void run() { // 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()) { + if (isServiceThread()) { c.getTransport().getWorkerThreadPool().execute(r); } else { r.run(); @@ -204,10 +205,8 @@ public void run() { // --------------------------------------------------------- Private Methods - private boolean isCurrentThreadSelectorRunner() { - final NIOConnection c = (NIOConnection) context.getConnection(); - final SelectorRunner runner = c.getSelectorRunner(); - return (Thread.currentThread() == runner.getRunnerThread()); + private boolean isServiceThread() { + return Threads.isService(); } From 80667db7550b4bb59dca678a5cfff6ddd49121bb Mon Sep 17 00:00:00 2001 From: Robert Macaulay Date: Fri, 25 Oct 2013 13:13:47 -0500 Subject: [PATCH 121/701] Backport old digest auth to 1.7 Prior patch added old style digest auth to 1.8. Need to get this backported to 1.7 --- src/main/java/com/ning/http/client/Realm.java | 15 +++- .../java/com/ning/http/client/RealmTest.java | 81 +++++++++++++++++++ 2 files changed, 95 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/ning/http/client/Realm.java b/src/main/java/com/ning/http/client/Realm.java index 8e68142c98..2d7899bbdb 100644 --- a/src/main/java/com/ning/http/client/Realm.java +++ b/src/main/java/com/ning/http/client/Realm.java @@ -526,12 +526,23 @@ private void newResponse() throws UnsupportedEncodingException { byte[] ha1 = md.digest(); md.reset(); + + //HA2 if qop is auth-int is methodName:url:md5(entityBody) md.update(new StringBuilder(methodName) .append(':') .append(uri).toString().getBytes("ISO-8859-1")); byte[] ha2 = md.digest(); - md.update(new StringBuilder(toBase16(ha1)) + if(qop==null || qop.equals("")) { + md.update(new StringBuilder(toBase16(ha1)) + .append(':') + .append(nonce) + .append(':') + .append(toBase16(ha2)).toString().getBytes("ISO-8859-1")); + + } else { + //qop ="auth" or "auth-int" + md.update(new StringBuilder(toBase16(ha1)) .append(':') .append(nonce) .append(':') @@ -542,6 +553,8 @@ private void newResponse() throws UnsupportedEncodingException { .append(qop) .append(':') .append(toBase16(ha2)).toString().getBytes("ISO-8859-1")); + } + byte[] digest = md.digest(); response = toHexString(digest); diff --git a/src/test/java/com/ning/http/client/RealmTest.java b/src/test/java/com/ning/http/client/RealmTest.java index f1aac2fcf9..6bd2a622b5 100644 --- a/src/test/java/com/ning/http/client/RealmTest.java +++ b/src/test/java/com/ning/http/client/RealmTest.java @@ -15,6 +15,9 @@ import com.ning.http.client.Realm.AuthScheme; import com.ning.http.client.Realm.RealmBuilder; import org.testng.Assert; +import java.math.BigInteger; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; import org.testng.annotations.Test; public class RealmTest { @@ -36,4 +39,82 @@ public void testClone() { Assert.assertEquals( clone.getAlgorithm(), orig.getAlgorithm() ); Assert.assertEquals( clone.getAuthScheme(), orig.getAuthScheme() ); } + @Test(groups = "fast") + public void testOldDigestEmptyString() { + String qop=""; + testOldDigest(qop); + } + @Test(groups = "fast") + public void testOldDigestNull() { + String qop=null; + testOldDigest(qop); + } + + private void testOldDigest(String qop){ + String user="user"; + String pass="pass"; + String realm="realm"; + String nonce="nonce"; + String method="GET"; + String uri="/foo"; + RealmBuilder builder = new RealmBuilder(); + builder.setPrincipal( user ).setPassword( pass ); + builder.setNonce( nonce ); + builder.setUri( uri ); + builder.setMethodName(method); + builder.setRealmName( realm ); + builder.setQop(qop); + builder.setScheme( AuthScheme.DIGEST ); + Realm orig = builder.build(); + + String ha1=getMd5(user +":" + realm +":"+pass); + String ha2=getMd5(method +":"+ uri); + String expectedResponse=getMd5(ha1 +":" + nonce +":" + ha2); + + Assert.assertEquals(expectedResponse,orig.getResponse()); + } + + @Test(groups = "fast") + public void testStrongDigest() { + String user="user"; + String pass="pass"; + String realm="realm"; + String nonce="nonce"; + String method="GET"; + String uri="/foo"; + String qop="auth"; + RealmBuilder builder = new RealmBuilder(); + builder.setPrincipal( user ).setPassword( pass ); + builder.setNonce( nonce ); + builder.setUri( uri ); + builder.setMethodName(method); + builder.setRealmName( realm ); + builder.setQop(qop); + builder.setScheme( AuthScheme.DIGEST ); + Realm orig = builder.build(); + + String nc = orig.getNc(); + String cnonce = orig.getCnonce(); + String ha1=getMd5(user +":" + realm +":"+pass); + String ha2=getMd5(method +":"+ uri); + String expectedResponse=getMd5(ha1 +":" + nonce +":" + nc + ":" + cnonce +":" + qop + ":" + ha2); + + Assert.assertEquals(expectedResponse,orig.getResponse()); + } + + private String getMd5(String what){ + try { + MessageDigest md = MessageDigest.getInstance("MD5"); + md.update(what.getBytes("ISO-8859-1")); + byte[] hash = md.digest(); + BigInteger bi = new BigInteger(1, hash); + String result = bi.toString(16); + if (result.length() % 2 != 0) { + return "0" + result; + } + return result; + } catch (Exception e) { + throw new RuntimeException(e); + } + } } From 8b512ef212faaf543475cabdf435701ead5be77e Mon Sep 17 00:00:00 2001 From: Ryan Lubke Date: Wed, 30 Oct 2013 10:45:30 -0700 Subject: [PATCH 122/701] Integrate Grizzly 2.3.7. --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index b65610df90..8a12ddae95 100644 --- a/pom.xml +++ b/pom.xml @@ -489,7 +489,7 @@ org.glassfish.grizzly grizzly-websockets - 2.3.6 + 2.3.7 true From 6f60a45d9ebe4ad0ebd6881746e1671f3a3a8317 Mon Sep 17 00:00:00 2001 From: Bongjae Chang Date: Wed, 6 Nov 2013 16:58:01 +0900 Subject: [PATCH 123/701] Fixed for #409 "MultipartBody generates wrong body bytes" and added the testcase --- .../ning/http/multipart/MultipartBody.java | 15 ++- .../http/multipart/MultipartBodyTest.java | 109 ++++++++++++++++++ 2 files changed, 120 insertions(+), 4 deletions(-) create mode 100644 src/test/java/com/ning/http/multipart/MultipartBodyTest.java diff --git a/src/main/java/com/ning/http/multipart/MultipartBody.java b/src/main/java/com/ning/http/multipart/MultipartBody.java index 2fadcc36e3..341f22e98e 100644 --- a/src/main/java/com/ning/http/multipart/MultipartBody.java +++ b/src/main/java/com/ning/http/multipart/MultipartBody.java @@ -78,7 +78,10 @@ public long read(ByteBuffer buffer) throws IOException { try { int overallLength = 0; - int maxLength = buffer.capacity(); + final int maxLength = buffer.remaining(); + if (maxLength <= 0) { + return maxLength; + } if (startPart == parts.size() && endWritten) { return -1; @@ -132,6 +135,7 @@ public long read(ByteBuffer buffer) throws IOException { initializeFileEnd(currentFilePart); } else if (fileLocation == FileLocation.END) { startPart++; + fileLocation = FileLocation.NONE; if (startPart == parts.size() && currentStream.available() == 0) { doneWritingParts = true; } @@ -146,6 +150,7 @@ public long read(ByteBuffer buffer) throws IOException { initializeFileEnd(currentFilePart); } else if (fileLocation == FileLocation.END) { startPart++; + fileLocation = FileLocation.NONE; if (startPart == parts.size() && currentStream.available() == 0) { doneWritingParts = true; } @@ -165,6 +170,7 @@ public long read(ByteBuffer buffer) throws IOException { initializeFileEnd(currentFilePart); } else if (fileLocation == FileLocation.END) { startPart++; + fileLocation = FileLocation.NONE; if (startPart == parts.size() && currentStream.available() == 0) { doneWritingParts = true; } @@ -386,14 +392,15 @@ private StringPart generateClientStringpart(com.ning.http.client.Part part) { private long handleByteArrayPart(WritableByteChannel target, FilePart filePart, byte[] data) throws IOException { - ByteArrayOutputStream output = generateByteArrayBody(filePart); + final ByteArrayOutputStream output = new ByteArrayOutputStream(); + Part.sendPart(output, filePart, boundary); return writeToTarget(target, output); } private ByteArrayOutputStream generateByteArrayBody(FilePart filePart) throws IOException { - ByteArrayOutputStream output = new ByteArrayOutputStream(); - Part.sendPart(output, filePart, boundary); + final ByteArrayOutputStream output = new ByteArrayOutputStream(); + filePart.sendData(output); return output; } diff --git a/src/test/java/com/ning/http/multipart/MultipartBodyTest.java b/src/test/java/com/ning/http/multipart/MultipartBodyTest.java new file mode 100644 index 0000000000..6fcd01895d --- /dev/null +++ b/src/test/java/com/ning/http/multipart/MultipartBodyTest.java @@ -0,0 +1,109 @@ +/* + * 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.multipart; + +import com.ning.http.client.*; +import com.ning.http.client.Part; +import com.ning.http.util.AsyncHttpProviderUtils; +import org.testng.Assert; +import org.testng.annotations.Test; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; + +public class MultipartBodyTest { + + @Test(groups = "fast") + public void testBasics() { + final List parts = new ArrayList(); + + // add a file + final File testFile = getTestfile(); + try { + parts.add(new FilePart("filePart", testFile)); + } catch (FileNotFoundException fne) { + Assert.fail("file not found: " + testFile); + } + + // add a byte array + try { + parts.add(new ByteArrayPart("baPart", "fileName", "testMultiPart".getBytes("utf-8"), "application/test", "utf-8")); + } catch (UnsupportedEncodingException ignore) { + } + + // add a string + parts.add(new StringPart("stringPart", "testString", "utf-8")); + + compareContentLength(parts); + } + + private static File getTestfile() { + final ClassLoader cl = MultipartBodyTest.class.getClassLoader(); + final URL url = cl.getResource("textfile.txt"); + Assert.assertNotNull(url); + File file = null; + try { + file = new File(url.toURI()); + } catch (URISyntaxException use) { + Assert.fail("uri syntax error"); + } + return file; + } + + private static void compareContentLength(final List parts) { + Assert.assertNotNull(parts); + // get expected values + MultipartRequestEntity mre = null; + try { + mre = AsyncHttpProviderUtils.createMultipartRequestEntity(parts, new FluentCaseInsensitiveStringsMap()); + } catch (FileNotFoundException fne) { + Assert.fail("file not found: " + parts); + } + final long expectedContentLength = mre.getContentLength(); + + // get real bytes + final Body multipartBody = new MultipartBody(parts, mre.getContentType(), String.valueOf(expectedContentLength)); + try { + final ByteBuffer buffer = ByteBuffer.allocate(8192); + boolean last = false; + long totalBytes = 0; + while (!last) { + long readBytes = 0; + try { + readBytes = multipartBody.read(buffer); + } catch (IOException ie) { + Assert.fail("read failure"); + } + if (readBytes >= 0) { + totalBytes += readBytes; + } else { + last = true; + } + buffer.clear(); + } + Assert.assertEquals(totalBytes, expectedContentLength); + } finally { + try { + multipartBody.close(); + } catch (IOException ignore) { + } + } + } +} From 47afbcf8b6a7d29b9d873af1a2df24cef79d8164 Mon Sep 17 00:00:00 2001 From: Bongjae Chang Date: Wed, 6 Nov 2013 18:08:44 +0900 Subject: [PATCH 124/701] issue #411 "Improve multipart logic for grizzly provider" (Note) This code/patch should be applied after resolving issue #409 "MultipartBody generates wrong body bytes" --- .../grizzly/GrizzlyAsyncHttpProvider.java | 81 +++++++++++++------ 1 file changed, 58 insertions(+), 23 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 2f7b9540cd..d22f6f567c 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012 Sonatype, Inc. All rights reserved. + * 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. @@ -16,6 +16,8 @@ import static com.ning.http.util.MiscUtil.isNonEmpty; import com.ning.http.client.AsyncHttpClient; +import com.ning.http.client.Part; +import com.ning.http.multipart.MultipartBody; import com.ning.org.jboss.netty.handler.codec.http.CookieDecoder; import com.ning.http.client.AsyncHandler; import com.ning.http.client.AsyncHttpClientConfig; @@ -2072,31 +2074,64 @@ public boolean handlesBodyType(final Request request) { return isNonEmpty(request.getParts()); } - @SuppressWarnings({"unchecked"}) public boolean doHandle(final FilterChainContext ctx, - final Request request, - final HttpRequestPacket requestPacket) - throws IOException { - - MultipartRequestEntity mre = - AsyncHttpProviderUtils.createMultipartRequestEntity( - request.getParts(), - request.getHeaders()); - requestPacket.setContentLengthLong(mre.getContentLength()); - requestPacket.setContentType(mre.getContentType()); - final MemoryManager mm = ctx.getMemoryManager(); - Buffer b = mm.allocate(512); - BufferOutputStream o = new BufferOutputStream(mm, b, true); - mre.writeRequest(o); - b = o.getBuffer(); - b.trim(); - if (b.hasRemaining()) { - final HttpContent content = requestPacket.httpContentBuilder().content(b).build(); - content.setLast(true); - ctx.write(content, ((!requestPacket.isCommitted()) ? ctx.getTransportContext().getCompletionHandler() : null)); + final Request request, + final HttpRequestPacket requestPacket) + throws IOException { + + final List parts = request.getParts(); + final MultipartRequestEntity mre = AsyncHttpProviderUtils.createMultipartRequestEntity(parts, request.getHeaders()); + final long contentLength = mre.getContentLength(); + final String contentType = mre.getContentType(); + requestPacket.setContentLengthLong(contentLength); + requestPacket.setContentType(contentType); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("REQUEST(modified): contentLength={}, contentType={}", new Object[]{requestPacket.getContentLength(), requestPacket.getContentType()}); } - return true; + final FeedableBodyGenerator generator = new FeedableBodyGenerator() { + @Override + public Body createBody() throws IOException { + return new MultipartBody(parts, contentType, String.valueOf(contentLength)); + } + }; + generator.setFeeder(new FeedableBodyGenerator.BaseFeeder(generator) { + @Override + public void flush() throws IOException { + final Body bodyLocal = feedableBodyGenerator.createBody(); + try { + final MemoryManager mm = ctx.getMemoryManager(); + boolean last = false; + while (!last) { + Buffer buffer = mm.allocate(BodyHandler.MAX_CHUNK_SIZE); + buffer.allowBufferDispose(true); + final long readBytes = bodyLocal.read(buffer.toByteBuffer()); + if (readBytes > 0) { + buffer.position((int) readBytes); + buffer.trim(); + } else { + buffer.dispose(); + if (readBytes < 0) { + last = true; + buffer = Buffers.EMPTY_BUFFER; + } else { + throw new IllegalStateException("MultipartBody unexpectedly returned 0 bytes available"); + } + } + feed(buffer, last); + } + } finally { + if (bodyLocal != null) { + try { + bodyLocal.close(); + } catch (IOException ignore) { + } + } + } + } + }); + generator.initializeAsynchronousTransfer(ctx, requestPacket); + return false; } } // END PartsBodyHandler From ddab1c715e0a6640482db9e0f8c174f24d145db9 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 6 Nov 2013 21:06:39 +0100 Subject: [PATCH 125/701] Minor clean up --- .../java/com/ning/http/multipart/MultipartBody.java | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/ning/http/multipart/MultipartBody.java b/src/main/java/com/ning/http/multipart/MultipartBody.java index 341f22e98e..203c0f87dc 100644 --- a/src/main/java/com/ning/http/multipart/MultipartBody.java +++ b/src/main/java/com/ning/http/multipart/MultipartBody.java @@ -79,9 +79,6 @@ public long read(ByteBuffer buffer) throws IOException { int overallLength = 0; final int maxLength = buffer.remaining(); - if (maxLength <= 0) { - return maxLength; - } if (startPart == parts.size() && endWritten) { return -1; @@ -208,7 +205,8 @@ public long read(ByteBuffer buffer) throws IOException { private void initializeByteArrayBody(FilePart filePart) throws IOException { - ByteArrayOutputStream output = generateByteArrayBody(filePart); + ByteArrayOutputStream output = new ByteArrayOutputStream(); + filePart.sendData(output); initializeBuffer(output); @@ -397,13 +395,6 @@ private long handleByteArrayPart(WritableByteChannel target, return writeToTarget(target, output); } - private ByteArrayOutputStream generateByteArrayBody(FilePart filePart) - throws IOException { - final ByteArrayOutputStream output = new ByteArrayOutputStream(); - filePart.sendData(output); - return output; - } - private long handleFileEnd(WritableByteChannel target, FilePart filePart) throws IOException { From d394db55083bc91a15deaabb4f2d5a16aad2ea8f Mon Sep 17 00:00:00 2001 From: Robert Macaulay Date: Mon, 11 Nov 2013 16:33:55 -0600 Subject: [PATCH 126/701] Use keepalive on 401. If client requests keepalive and server allows it, reuse the socket --- .../http/client/providers/netty/NettyAsyncHttpProvider.java | 3 +++ 1 file changed, 3 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 1722c6e0cf..60b7c8ea86 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 @@ -2103,6 +2103,9 @@ public Object call() throws Exception { } }; + if (future.getKeepAlive()) { + future.setReuseChannel(true); + } if (future.getKeepAlive() && response.isChunked()) { // We must make sure there is no bytes left before executing the next request. ctx.setAttachment(ac); From b92a155f990e14282b450eebcd9c7f94968cdb8b Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 12 Nov 2013 10:37:11 +0100 Subject: [PATCH 127/701] Introduce a constant exception for Remotely Closed --- .../client/providers/netty/NettyAsyncHttpProvider.java | 8 +++++++- 1 file 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 60b7c8ea86..8a4941ee80 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 @@ -58,6 +58,7 @@ 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; @@ -106,6 +107,7 @@ import org.slf4j.LoggerFactory; import javax.net.ssl.SSLEngine; + import java.io.File; import java.io.FileInputStream; import java.io.IOException; @@ -153,6 +155,10 @@ import static org.jboss.netty.channel.Channels.pipeline; public class NettyAsyncHttpProvider extends SimpleChannelUpstreamHandler implements AsyncHttpProvider { + public static final IOException REMOTELY_CLOSED_EXCEPTION = new IOException("Remotely Closed"); + static { + REMOTELY_CLOSED_EXCEPTION.setStackTrace(new StackTraceElement[0]); + } private final static String HTTP_HANDLER = "httpHandler"; protected final static String SSL_HANDLER = "sslHandler"; private final static String HTTPS = "https"; @@ -1379,7 +1385,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")); + abort(future, REMOTELY_CLOSED_EXCEPTION); } } else { closeChannel(ctx); From a35881e24d9535e0df7e2dd2bd4f3c160155d5ad Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 14 Nov 2013 15:02:32 +0100 Subject: [PATCH 128/701] All HTTP methods allow passing a body, backport #421 --- src/main/java/com/ning/http/client/RequestBuilderBase.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/main/java/com/ning/http/client/RequestBuilderBase.java b/src/main/java/com/ning/http/client/RequestBuilderBase.java index 6749cfa767..c3f704d302 100644 --- a/src/main/java/com/ning/http/client/RequestBuilderBase.java +++ b/src/main/java/com/ning/http/client/RequestBuilderBase.java @@ -624,7 +624,7 @@ public T setConnectionPoolKeyStrategy(ConnectionPoolKeyStrategy connectionPoolKe } public Request build() { - if ((request.length < 0) && (request.streamData == null) && allowBody(request.getMethod())) { + if (request.length < 0 && request.streamData == null) { // can't concatenate content-length String contentLength = request.headers.getFirstValue("Content-Length"); @@ -639,10 +639,6 @@ public Request build() { return request; } - private boolean allowBody(String method) { - return !(method.equalsIgnoreCase("GET") || method.equalsIgnoreCase("OPTIONS") || method.equalsIgnoreCase("TRACE") || method.equalsIgnoreCase("HEAD")); - } - public T addOrReplaceCookie(Cookie cookie) { String cookieKey = cookie.getName(); boolean replace = false; From a71fee4c70ebd30d325558a6b0113cfcbdcdb394 Mon Sep 17 00:00:00 2001 From: Kelly Byrd Date: Mon, 25 Nov 2013 15:51:00 -0800 Subject: [PATCH 129/701] Fix NPE in NettyAsyncHttpProvider.toString() When maxConnectionsTotal isn't set, freeConnections is always null. --- .../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 8a4941ee80..f90807787c 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 @@ -271,8 +271,9 @@ public NettyAsyncHttpProvider(AsyncHttpClientConfig config) { @Override public String toString() { + int availablePermits = freeConnections != null ? freeConnections.availablePermits() : 0; return String.format("NettyAsyncHttpProvider:\n\t- maxConnections: %d\n\t- openChannels: %s\n\t- connectionPools: %s",// - config.getMaxTotalConnections() - freeConnections.availablePermits(),// + config.getMaxTotalConnections() - availablePermits,// openChannels.toString(),// connectionsPool.toString()); } From 486b241f75e4b46ee25a2172b1d7c0f0807e1b24 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 29 Nov 2013 14:32:53 +0100 Subject: [PATCH 130/701] Allow Multipart with unknown content length, close #427 --- .../providers/netty/NettyAsyncHttpProvider.java | 16 +++++++++++++--- .../com/ning/http/multipart/MultipartBody.java | 3 +-- 2 files changed, 14 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 f90807787c..31a732c330 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 @@ -475,10 +475,18 @@ protected final void writeRequest(final Channel channel, final AsyncHttpClie } else { nettyRequest.setHeader(HttpHeaders.Names.TRANSFER_ENCODING, HttpHeaders.Values.CHUNKED); } - + } else if (future.getRequest().getParts() != null) { String contentType = nettyRequest.getHeader(HttpHeaders.Names.CONTENT_TYPE); - String length = nettyRequest.getHeader(HttpHeaders.Names.CONTENT_LENGTH); + String contentLength = nettyRequest.getHeader(HttpHeaders.Names.CONTENT_LENGTH); + + long length = -1; + if (contentLength != null) { + length = Long.parseLong(contentLength); + } else { + nettyRequest.addHeader(HttpHeaders.Names.TRANSFER_ENCODING, HttpHeaders.Values.CHUNKED); + } + body = new MultipartBody(future.getRequest().getParts(), contentType, length); } } @@ -822,7 +830,9 @@ 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())); + if (mre.getContentLength() >= 0) { + nettyRequest.setHeader(HttpHeaders.Names.CONTENT_LENGTH, String.valueOf(mre.getContentLength())); + } } else if (request.getEntityWriter() != null) { int length = (int) request.getContentLength(); diff --git a/src/main/java/com/ning/http/multipart/MultipartBody.java b/src/main/java/com/ning/http/multipart/MultipartBody.java index 203c0f87dc..9a5a1185ff 100644 --- a/src/main/java/com/ning/http/multipart/MultipartBody.java +++ b/src/main/java/com/ning/http/multipart/MultipartBody.java @@ -48,10 +48,9 @@ public class MultipartBody implements RandomAccessBody { enum FileLocation {NONE, START, MIDDLE, END} - public MultipartBody(List parts, String contentType, String contentLength) { + public MultipartBody(List parts, String contentType, Long contentLength) { this.boundary = MultipartEncodingUtil.getAsciiBytes(contentType.substring(contentType.indexOf("boundary=") + "boundary=".length())); - this.contentLength = Long.parseLong(contentLength); this.parts = parts; files = new ArrayList(); From 18caec709c65f44ac4ed903c2866c3d26eb62415 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 29 Nov 2013 14:37:47 +0100 Subject: [PATCH 131/701] Fix previous commit --- .../http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java | 2 +- src/main/java/com/ning/http/multipart/MultipartBody.java | 2 +- src/test/java/com/ning/http/multipart/MultipartBodyTest.java | 2 +- 3 files 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 d22f6f567c..637c2cef3b 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 @@ -2092,7 +2092,7 @@ public boolean doHandle(final FilterChainContext ctx, final FeedableBodyGenerator generator = new FeedableBodyGenerator() { @Override public Body createBody() throws IOException { - return new MultipartBody(parts, contentType, String.valueOf(contentLength)); + return new MultipartBody(parts, contentType, contentLength); } }; generator.setFeeder(new FeedableBodyGenerator.BaseFeeder(generator) { diff --git a/src/main/java/com/ning/http/multipart/MultipartBody.java b/src/main/java/com/ning/http/multipart/MultipartBody.java index 9a5a1185ff..cea56f7406 100644 --- a/src/main/java/com/ning/http/multipart/MultipartBody.java +++ b/src/main/java/com/ning/http/multipart/MultipartBody.java @@ -48,7 +48,7 @@ public class MultipartBody implements RandomAccessBody { enum FileLocation {NONE, START, MIDDLE, END} - public MultipartBody(List parts, String contentType, Long contentLength) { + public MultipartBody(List parts, String contentType, long contentLength) { this.boundary = MultipartEncodingUtil.getAsciiBytes(contentType.substring(contentType.indexOf("boundary=") + "boundary=".length())); this.parts = parts; diff --git a/src/test/java/com/ning/http/multipart/MultipartBodyTest.java b/src/test/java/com/ning/http/multipart/MultipartBodyTest.java index 6fcd01895d..2e40533451 100644 --- a/src/test/java/com/ning/http/multipart/MultipartBodyTest.java +++ b/src/test/java/com/ning/http/multipart/MultipartBodyTest.java @@ -79,7 +79,7 @@ private static void compareContentLength(final List parts) { final long expectedContentLength = mre.getContentLength(); // get real bytes - final Body multipartBody = new MultipartBody(parts, mre.getContentType(), String.valueOf(expectedContentLength)); + final Body multipartBody = new MultipartBody(parts, mre.getContentType(), expectedContentLength); try { final ByteBuffer buffer = ByteBuffer.allocate(8192); boolean last = false; From ceb9ddf395d7c7cc1eeae2b0078385bfc1060ae6 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 29 Nov 2013 14:56:03 +0100 Subject: [PATCH 132/701] yolo --- src/main/java/com/ning/http/multipart/MultipartBody.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/ning/http/multipart/MultipartBody.java b/src/main/java/com/ning/http/multipart/MultipartBody.java index cea56f7406..588792cc7d 100644 --- a/src/main/java/com/ning/http/multipart/MultipartBody.java +++ b/src/main/java/com/ning/http/multipart/MultipartBody.java @@ -50,8 +50,8 @@ enum FileLocation {NONE, START, MIDDLE, END} public MultipartBody(List parts, String contentType, long contentLength) { this.boundary = MultipartEncodingUtil.getAsciiBytes(contentType.substring(contentType.indexOf("boundary=") + "boundary=".length())); - this.parts = parts; + this.contentLength = contentLength; files = new ArrayList(); From f954d6ee0ffc9528ccd341d5c1046146b81ba2c1 Mon Sep 17 00:00:00 2001 From: jfarcand Date: Tue, 3 Dec 2013 16:19:32 -0500 Subject: [PATCH 133/701] [maven-release-plugin] prepare release async-http-client-1.7.22 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 8a12ddae95..c01f998784 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.7.22-SNAPSHOT + 1.7.22 jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From ff3c63c067705b34d257dbcaefe98eb085aedbea Mon Sep 17 00:00:00 2001 From: jfarcand Date: Tue, 3 Dec 2013 16:19:35 -0500 Subject: [PATCH 134/701] [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 c01f998784..04bb290214 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.7.22 + 1.7.23-SNAPSHOT jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From 9bc2a50e79c638b61ff0db1618e2826e206cde7c Mon Sep 17 00:00:00 2001 From: Ryan Lubke Date: Tue, 3 Dec 2013 19:35:04 -0800 Subject: [PATCH 135/701] Fix for #429. --- .../client/providers/grizzly/GrizzlyAsyncHttpProvider.java | 6 +----- 1 file changed, 1 insertion(+), 5 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 637c2cef3b..9b89ced560 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 @@ -1836,12 +1836,8 @@ public boolean doHandle(final FilterChainContext ctx, final HttpRequestPacket requestPacket) throws IOException { - String charset = request.getBodyEncoding(); - if (charset == null) { - charset = Charsets.ASCII_CHARSET.name(); - } - final byte[] data = new String(request.getByteData(), charset).getBytes(charset); final MemoryManager mm = ctx.getMemoryManager(); + final byte[] data = request.getByteData(); final Buffer gBuffer = Buffers.wrap(mm, data); if (requestPacket.getContentLength() == -1) { if (!clientConfig.isCompressionEnabled()) { From 1fa45b41b8da87b86b866e5dbadd307bbedcf6c4 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 12 Dec 2013 11:04:39 +0100 Subject: [PATCH 136/701] Implement onRequestSent for Netty provider --- .../http/client/AsyncHandlerExtensions.java | 38 +++++++++++++++++++ .../netty/NettyAsyncHttpProvider.java | 4 ++ 2 files changed, 42 insertions(+) create mode 100644 src/main/java/com/ning/http/client/AsyncHandlerExtensions.java diff --git a/src/main/java/com/ning/http/client/AsyncHandlerExtensions.java b/src/main/java/com/ning/http/client/AsyncHandlerExtensions.java new file mode 100644 index 0000000000..c111ccf7fa --- /dev/null +++ b/src/main/java/com/ning/http/client/AsyncHandlerExtensions.java @@ -0,0 +1,38 @@ +/* + * 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; + +/** + * This interface hosts new low level callback methods on {@link AsyncHandler}. + * For now, those methods are in a dedicated interface in order not to break the existing API, + * but could be merged into one of the existing ones in AHC 2. + * + * More additional hooks might come, such as: + *

    + *
  • onRetry()
  • + *
  • onConnected()
  • + *
  • onConnectionClosed()
  • + *
  • onBytesSent(long numberOfBytes)
  • + *
  • onBytesReceived(long numberOfBytes)
  • + *
+ */ +public interface AsyncHandlerExtensions { + + /** + * Notify the callback when a request is being written on the wire. + * If the original request causes multiple requests to be sent, for example, because of authorization or retry, + * it will be notified multiple times. + * Currently only supported by the Netty provider. + */ + void onRequestSent(); +} 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 31a732c330..aee2d7f479 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 com.ning.http.client.AsyncHandler; import com.ning.http.client.AsyncHandler.STATE; +import com.ning.http.client.AsyncHandlerExtensions; import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.AsyncHttpProvider; import com.ning.http.client.Body; @@ -506,6 +507,9 @@ protected final void writeRequest(final Channel channel, final AsyncHttpClie // Leave it to true. if (future.getAndSetWriteHeaders(true)) { try { + if (future.getAsyncHandler() instanceof AsyncHandlerExtensions) + AsyncHandlerExtensions.class.cast(future.getAsyncHandler()).onRequestSent(); + channel.write(nettyRequest).addListener(new ProgressListener(true, future.getAsyncHandler(), future)); } catch (Throwable cause) { log.debug(cause.getMessage(), cause); From 16550ec5ace075e897ad338148edd52e83203073 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 12 Dec 2013 11:48:20 +0100 Subject: [PATCH 137/701] Add new onRetry callback method for #435 --- .../java/com/ning/http/client/AsyncHandlerExtensions.java | 6 +++++- .../http/client/providers/netty/NettyAsyncHttpProvider.java | 6 ++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/ning/http/client/AsyncHandlerExtensions.java b/src/main/java/com/ning/http/client/AsyncHandlerExtensions.java index c111ccf7fa..c8ddbdf761 100644 --- a/src/main/java/com/ning/http/client/AsyncHandlerExtensions.java +++ b/src/main/java/com/ning/http/client/AsyncHandlerExtensions.java @@ -19,7 +19,6 @@ * * More additional hooks might come, such as: *
    - *
  • onRetry()
  • *
  • onConnected()
  • *
  • onConnectionClosed()
  • *
  • onBytesSent(long numberOfBytes)
  • @@ -35,4 +34,9 @@ public interface AsyncHandlerExtensions { * Currently only supported by the Netty provider. */ void onRequestSent(); + + /** + * Notify the callback every time a request is being retried. + */ + void onRetry(); } 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 aee2d7f479..03120eb281 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 @@ -1297,6 +1297,9 @@ private FilterContext handleIoException(FilterContext fc, NettyResponseFuture } private void replayRequest(final NettyResponseFuture future, FilterContext fc, HttpResponse response, ChannelHandlerContext ctx) throws IOException { + if (future.getAsyncHandler() instanceof AsyncHandlerExtensions) { + AsyncHandlerExtensions.class.cast(future.getAsyncHandler()).onRetry(); + } final Request newRequest = fc.getRequest(); future.setAsyncHandler(fc.getAsyncHandler()); future.setState(NettyResponseFuture.STATE.NEW); @@ -1430,6 +1433,9 @@ protected boolean remotelyClosed(Channel channel, NettyResponseFuture future) future.setState(NettyResponseFuture.STATE.RECONNECTED); log.debug("Trying to recover request {}\n", future.getNettyRequest()); + if (future.getAsyncHandler() instanceof AsyncHandlerExtensions) { + AsyncHandlerExtensions.class.cast(future.getAsyncHandler()).onRetry(); + } try { nextRequest(future.getRequest(), future); From 31e7249089e4952807933e596fbc556e560bd948 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 12 Dec 2013 11:49:54 +0100 Subject: [PATCH 138/701] When debug is enabled, Netty ConnectListener erroneously consumes a retry token, close #436 --- .../http/client/providers/netty/NettyConnectListener.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) 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 0dbca7a339..e275e4ffbd 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 @@ -33,6 +33,7 @@ import org.slf4j.LoggerFactory; import javax.net.ssl.HostnameVerifier; + import java.io.IOException; import java.net.ConnectException; import java.net.InetSocketAddress; @@ -85,8 +86,9 @@ public final void operationComplete(ChannelFuture f) throws Exception { } else { Throwable cause = f.getCause(); - 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) + boolean canRetry = future.canRetry(); + logger.debug("Trying to recover a dead cached channel {} with a retry value of {} ", f.getChannel(), canRetry); + if (canRetry && cause != null && (NettyAsyncHttpProvider.abortOnDisconnectException(cause) || cause instanceof ClosedChannelException || future.getState() != NettyResponseFuture.STATE.NEW)) { From e3dd70d8ba3b6c8762e2a804f3d7bbf027d06703 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 12 Dec 2013 14:45:38 +0100 Subject: [PATCH 139/701] Support DEFLATE compression for Netty provider, backport #438 --- .../http/client/providers/netty/NettyAsyncHttpProvider.java | 5 ++++- 1 file changed, 4 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 03120eb281..e5a7fac273 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 @@ -156,6 +156,9 @@ import static org.jboss.netty.channel.Channels.pipeline; public class NettyAsyncHttpProvider extends SimpleChannelUpstreamHandler implements AsyncHttpProvider { + + public static final String GZIP_DEFLATE = HttpHeaders.Values.GZIP + "," + HttpHeaders.Values.DEFLATE; + public static final IOException REMOTELY_CLOSED_EXCEPTION = new IOException("Remotely Closed"); static { REMOTELY_CLOSED_EXCEPTION.setStackTrace(new StackTraceElement[0]); @@ -676,7 +679,7 @@ else if (uri.getRawQuery() != null) } if (config.isCompressionEnabled()) { - nettyRequest.setHeader(HttpHeaders.Names.ACCEPT_ENCODING, HttpHeaders.Values.GZIP); + nettyRequest.setHeader(HttpHeaders.Names.ACCEPT_ENCODING, GZIP_DEFLATE); } } else { List auth = request.getHeaders().get(HttpHeaders.Names.PROXY_AUTHORIZATION); From b2d2434f39a900d3ab9bfe1373425432f91c0137 Mon Sep 17 00:00:00 2001 From: rlubke Date: Thu, 12 Dec 2013 08:35:48 -0800 Subject: [PATCH 140/701] Changes for #434. --- .../grizzly/GrizzlyAsyncHttpProvider.java | 28 +++---------------- 1 file changed, 4 insertions(+), 24 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 9b89ced560..65e0d5644c 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,32 +15,9 @@ import static com.ning.http.util.MiscUtil.isNonEmpty; -import com.ning.http.client.AsyncHttpClient; -import com.ning.http.client.Part; +import com.ning.http.client.*; import com.ning.http.multipart.MultipartBody; 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.ConnectionsPool; -import com.ning.http.client.Cookie; -import com.ning.http.client.FluentCaseInsensitiveStringsMap; -import com.ning.http.client.FluentStringsMap; -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.ProxyServer; -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.UpgradeHandler; import com.ning.http.client.filter.FilterContext; import com.ning.http.client.filter.ResponseFilter; import com.ning.http.client.listener.TransferCompletionHandler; @@ -1112,6 +1089,9 @@ protected void onHttpHeadersEncoded(HttpHeader httpHeader, FilterChainContext ct if (handler instanceof TransferCompletionHandler) { ((TransferCompletionHandler) handler).onHeaderWriteCompleted(); } + if (handler instanceof AsyncHandlerExtensions) { + ((AsyncHandlerExtensions) handler).onRequestSent(); + } } @Override From 5430fa87e0703c046888db61c309f71a10c912a3 Mon Sep 17 00:00:00 2001 From: Gerd Riesselmann Date: Fri, 13 Dec 2013 00:02:14 +0100 Subject: [PATCH 141/701] Respect Rawl URL Setting for Grizzly Provider in 1.7.x branch A backport of my prior pull request #437 to 1.7.x --- .../client/providers/grizzly/GrizzlyAsyncHttpProvider.java | 3 ++- 1 file changed, 2 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 65e0d5644c..b8d6202536 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 @@ -814,7 +814,8 @@ private boolean sendAsGrizzlyRequest(final Request request, httpCtx.isWSRequest = true; convertToUpgradeRequest(httpCtx); } - final URI uri = httpCtx.request.getURI(); + final Request req = httpCtx.request; + final URI uri = req.isUseRawUrl() ? req.getRawURI() : req.getURI(); final HttpRequestPacket.Builder builder = HttpRequestPacket.builder(); boolean secure = "https".equals(uri.getScheme()); builder.method(request.getMethod()); From d5606a5da9e8809436233cc3f0a3179801909c29 Mon Sep 17 00:00:00 2001 From: Gerd Riesselmann Date: Fri, 13 Dec 2013 01:36:25 +0100 Subject: [PATCH 142/701] Resepect Raw URL setting for query string, too (Grizzly, 1.7.x) Even with my prior pull request #439 applied, the query string was still escaped twice, when using raw URL. This change fixes it. The function addQueryString() - that I commented out - seems to do nothing that has not already be done when building the URI in the Request. Except it does not care for the isUseRawUrl() setting. If there's a subtle difference I did not notice, isUseRawUrl() should be added inside the body of that function. All of async-http-client tests still pass. com.ning.http.client.async.QueryParametersTest has no tests for raw URLs, though. But our tests now show the same behavior for both Netty and Grizzly. --- .../client/providers/grizzly/GrizzlyAsyncHttpProvider.java | 3 ++- 1 file changed, 2 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 65e0d5644c..62b015f267 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 @@ -874,7 +874,8 @@ private boolean sendAsGrizzlyRequest(final Request request, ctx.notifyDownstream(new SwitchingSSLFilter.SSLSwitchingEvent(secure, ctx.getConnection())); if (!useProxy && !httpCtx.isWSRequest) { - addQueryString(request, requestPacket); + requestPacket.setQueryString(uri.getRawQuery()); + //addQueryString(request, requestPacket); } addHeaders(request, requestPacket); addCookies(request, requestPacket); From 1a13ee2b3924cace6fb6084f7771a157c050c0e0 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 13 Dec 2013 11:49:14 +0100 Subject: [PATCH 143/701] Fix test after #438 --- .../com/ning/http/client/async/AsyncProvidersBasicTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 b17e263423..baef8496b9 100755 --- a/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java +++ b/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java @@ -777,7 +777,7 @@ public void asyncDoPostBasicGZIPTest() throws Throwable { public Response onCompleted(Response response) throws Exception { try { assertEquals(response.getStatusCode(), 200); - assertEquals(response.getHeader("X-Accept-Encoding"), "gzip"); + assertEquals(response.getHeader("X-Accept-Encoding"), "gzip,deflate"); } finally { l.countDown(); } From 00e78c95d99d712f08d3af994ec24523f19983ff Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 13 Dec 2013 11:50:22 +0100 Subject: [PATCH 144/701] Netty: allow passing a body with all HTTP methods, close #421 --- .../netty/NettyAsyncHttpProvider.java | 115 +++++++++--------- 1 file changed, 56 insertions(+), 59 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 e5a7fac273..ca6fd77816 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 @@ -791,74 +791,71 @@ else if (uri.getRawQuery() != null) nettyRequest.setHeader(HttpHeaders.Names.COOKIE, CookieEncoder.encodeClientSide(request.getCookies(), config.isRfc6265CookieEncoding())); } - String reqType = request.getMethod(); - if (!"GET".equals(reqType) && !"HEAD".equals(reqType) && !"OPTION".equals(reqType) && !"TRACE".equals(reqType)) { - - String bodyCharset = request.getBodyEncoding() == null ? DEFAULT_CHARSET : request.getBodyEncoding(); - - // We already have processed the body. - if (buffer != null && buffer.writerIndex() != 0) { - nettyRequest.setHeader(HttpHeaders.Names.CONTENT_LENGTH, buffer.writerIndex()); - nettyRequest.setContent(buffer); - } else if (request.getByteData() != null) { - nettyRequest.setHeader(HttpHeaders.Names.CONTENT_LENGTH, String.valueOf(request.getByteData().length)); - nettyRequest.setContent(ChannelBuffers.wrappedBuffer(request.getByteData())); - } else if (request.getStringData() != null) { - 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); - int length = lengthWrapper[0]; - nettyRequest.setHeader(HttpHeaders.Names.CONTENT_LENGTH, String.valueOf(length)); - nettyRequest.setContent(ChannelBuffers.wrappedBuffer(bytes, 0, length)); - } else if (isNonEmpty(request.getParams())) { - StringBuilder sb = new StringBuilder(); - for (final Entry> paramEntry : request.getParams()) { - final String key = paramEntry.getKey(); - for (final String value : paramEntry.getValue()) { - if (sb.length() > 0) { - sb.append("&"); - } - UTF8UrlEncoder.appendEncoded(sb, key); - sb.append("="); - UTF8UrlEncoder.appendEncoded(sb, value); + String bodyCharset = request.getBodyEncoding() == null ? DEFAULT_CHARSET : request.getBodyEncoding(); + + // We already have processed the body. + if (buffer != null && buffer.writerIndex() != 0) { + nettyRequest.setHeader(HttpHeaders.Names.CONTENT_LENGTH, buffer.writerIndex()); + nettyRequest.setContent(buffer); + } else if (request.getByteData() != null) { + nettyRequest.setHeader(HttpHeaders.Names.CONTENT_LENGTH, String.valueOf(request.getByteData().length)); + nettyRequest.setContent(ChannelBuffers.wrappedBuffer(request.getByteData())); + } else if (request.getStringData() != null) { + System.err.println("!!!!HEY STRING DATA"); + 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); + int length = lengthWrapper[0]; + nettyRequest.setHeader(HttpHeaders.Names.CONTENT_LENGTH, String.valueOf(length)); + nettyRequest.setContent(ChannelBuffers.wrappedBuffer(bytes, 0, length)); + } else if (isNonEmpty(request.getParams())) { + StringBuilder sb = new StringBuilder(); + for (final Entry> paramEntry : request.getParams()) { + final String key = paramEntry.getKey(); + for (final String value : paramEntry.getValue()) { + if (sb.length() > 0) { + sb.append("&"); } + UTF8UrlEncoder.appendEncoded(sb, key); + sb.append("="); + UTF8UrlEncoder.appendEncoded(sb, value); } - nettyRequest.setHeader(HttpHeaders.Names.CONTENT_LENGTH, String.valueOf(sb.length())); - nettyRequest.setContent(ChannelBuffers.wrappedBuffer(sb.toString().getBytes(bodyCharset))); + } + nettyRequest.setHeader(HttpHeaders.Names.CONTENT_LENGTH, String.valueOf(sb.length())); + nettyRequest.setContent(ChannelBuffers.wrappedBuffer(sb.toString().getBytes(bodyCharset))); - if (!request.getHeaders().containsKey(HttpHeaders.Names.CONTENT_TYPE)) { - nettyRequest.setHeader(HttpHeaders.Names.CONTENT_TYPE, HttpHeaders.Values.APPLICATION_X_WWW_FORM_URLENCODED); - } + if (!request.getHeaders().containsKey(HttpHeaders.Names.CONTENT_TYPE)) { + nettyRequest.setHeader(HttpHeaders.Names.CONTENT_TYPE, HttpHeaders.Values.APPLICATION_X_WWW_FORM_URLENCODED); + } - } else if (request.getParts() != null) { - MultipartRequestEntity mre = AsyncHttpProviderUtils.createMultipartRequestEntity(request.getParts(), request.getHeaders()); + } else if (request.getParts() != null) { + MultipartRequestEntity mre = AsyncHttpProviderUtils.createMultipartRequestEntity(request.getParts(), request.getHeaders()); - nettyRequest.setHeader(HttpHeaders.Names.CONTENT_TYPE, mre.getContentType()); - if (mre.getContentLength() >= 0) { - nettyRequest.setHeader(HttpHeaders.Names.CONTENT_LENGTH, String.valueOf(mre.getContentLength())); - } + nettyRequest.setHeader(HttpHeaders.Names.CONTENT_TYPE, mre.getContentType()); + if (mre.getContentLength() >= 0) { + nettyRequest.setHeader(HttpHeaders.Names.CONTENT_LENGTH, String.valueOf(mre.getContentLength())); + } - } else if (request.getEntityWriter() != null) { - int length = (int) request.getContentLength(); + } else if (request.getEntityWriter() != null) { + int length = (int) request.getContentLength(); - if (length == -1) { - length = MAX_BUFFERED_BYTES; - } + if (length == -1) { + length = MAX_BUFFERED_BYTES; + } - ChannelBuffer b = ChannelBuffers.dynamicBuffer(length); - request.getEntityWriter().writeEntity(new ChannelBufferOutputStream(b)); - nettyRequest.setHeader(HttpHeaders.Names.CONTENT_LENGTH, b.writerIndex()); - nettyRequest.setContent(b); - } else if (request.getFile() != null) { - File file = request.getFile(); - if (!file.isFile()) { - throw new IOException(String.format("File %s is not a file or doesn't exist", file.getAbsolutePath())); - } - nettyRequest.setHeader(HttpHeaders.Names.CONTENT_LENGTH, file.length()); + ChannelBuffer b = ChannelBuffers.dynamicBuffer(length); + request.getEntityWriter().writeEntity(new ChannelBufferOutputStream(b)); + nettyRequest.setHeader(HttpHeaders.Names.CONTENT_LENGTH, b.writerIndex()); + nettyRequest.setContent(b); + } else if (request.getFile() != null) { + File file = request.getFile(); + if (!file.isFile()) { + throw new IOException(String.format("File %s is not a file or doesn't exist", file.getAbsolutePath())); } + nettyRequest.setHeader(HttpHeaders.Names.CONTENT_LENGTH, file.length()); } } return nettyRequest; From 0f0712a963a3636de3585c772a1799935a47c253 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 13 Dec 2013 12:38:42 +0100 Subject: [PATCH 145/701] Woups --- .../ning/http/client/providers/netty/NettyAsyncHttpProvider.java | 1 - 1 file changed, 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 ca6fd77816..8a11cf1929 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 @@ -801,7 +801,6 @@ 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) { - System.err.println("!!!!HEY STRING DATA"); byte[] bytes = request.getStringData().getBytes(bodyCharset); nettyRequest.setHeader(HttpHeaders.Names.CONTENT_LENGTH, String.valueOf(bytes.length)); nettyRequest.setContent(ChannelBuffers.wrappedBuffer(bytes)); From 0bcf45851635bec25aa4ba29aeb3299559a4d67f Mon Sep 17 00:00:00 2001 From: jfarcand Date: Wed, 18 Dec 2013 09:56:35 -0500 Subject: [PATCH 146/701] [maven-release-plugin] prepare release async-http-client-1.7.23 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 04bb290214..c056e7a927 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.7.23-SNAPSHOT + 1.7.23 jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From 16fa2d82af3e4769ca73e0cacd921fa4496130d1 Mon Sep 17 00:00:00 2001 From: jfarcand Date: Wed, 18 Dec 2013 09:56:38 -0500 Subject: [PATCH 147/701] [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 c056e7a927..8200e89cae 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.7.23 + 1.7.24-SNAPSHOT jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From 475c5999d93dc7e2062fd967a9ad3086c4421d8d Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 3 Jan 2014 09:56:37 +0100 Subject: [PATCH 148/701] Setting a Realm shouldn't override existing Authentication headers, close #448 --- .../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 8a11cf1929..7fad6d6585 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 @@ -703,12 +703,12 @@ else if (uri.getRawQuery() != null) switch (realm.getAuthScheme()) { case BASIC: - nettyRequest.setHeader(HttpHeaders.Names.AUTHORIZATION, AuthenticatorUtils.computeBasicAuthentication(realm)); + nettyRequest.addHeader(HttpHeaders.Names.AUTHORIZATION, AuthenticatorUtils.computeBasicAuthentication(realm)); break; case DIGEST: if (isNonEmpty(realm.getNonce())) { try { - nettyRequest.setHeader(HttpHeaders.Names.AUTHORIZATION, AuthenticatorUtils.computeDigestAuthentication(realm)); + nettyRequest.addHeader(HttpHeaders.Names.AUTHORIZATION, AuthenticatorUtils.computeDigestAuthentication(realm)); } catch (NoSuchAlgorithmException e) { throw new SecurityException(e); } @@ -716,7 +716,7 @@ else if (uri.getRawQuery() != null) break; case NTLM: try { - nettyRequest.setHeader(HttpHeaders.Names.AUTHORIZATION, ntlmEngine.generateType1Msg("NTLM " + domain, authHost)); + nettyRequest.addHeader(HttpHeaders.Names.AUTHORIZATION, ntlmEngine.generateType1Msg("NTLM " + domain, authHost)); } catch (NTLMEngineException e) { IOException ie = new IOException(); ie.initCause(e); @@ -734,7 +734,7 @@ else if (uri.getRawQuery() != null) ie.initCause(e); throw ie; } - nettyRequest.setHeader(HttpHeaders.Names.AUTHORIZATION, "Negotiate " + challengeHeader); + nettyRequest.addHeader(HttpHeaders.Names.AUTHORIZATION, "Negotiate " + challengeHeader); break; case NONE: break; From d124b53d026e9e3848c6866f6f878731a412076a Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 15 Jan 2014 12:24:53 +0100 Subject: [PATCH 149/701] Make explicit that writeToTarget uses byte[] --- .../ning/http/multipart/MultipartBody.java | 28 +++++++++---------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/ning/http/multipart/MultipartBody.java b/src/main/java/com/ning/http/multipart/MultipartBody.java index 588792cc7d..f4665ff37a 100644 --- a/src/main/java/com/ning/http/multipart/MultipartBody.java +++ b/src/main/java/com/ning/http/multipart/MultipartBody.java @@ -329,12 +329,11 @@ public long transferTo(long position, long count, WritableByteChannel target) tempPart++; } - ByteArrayOutputStream endWriter = - new ByteArrayOutputStream(); + ByteArrayOutputStream endWriter = new ByteArrayOutputStream(); Part.sendMessageEnd(endWriter, boundary); - overallLength += writeToTarget(target, endWriter); + overallLength += writeToTarget(target, endWriter.toByteArray()); startPart = tempPart; @@ -391,7 +390,7 @@ private long handleByteArrayPart(WritableByteChannel target, final ByteArrayOutputStream output = new ByteArrayOutputStream(); Part.sendPart(output, filePart, boundary); - return writeToTarget(target, output); + return writeToTarget(target, output.toByteArray()); } private long handleFileEnd(WritableByteChannel target, FilePart filePart) @@ -399,7 +398,7 @@ private long handleFileEnd(WritableByteChannel target, FilePart filePart) ByteArrayOutputStream endOverhead = generateFileEnd(filePart); - return this.writeToTarget(target, endOverhead); + return this.writeToTarget(target, endOverhead.toByteArray()); } private ByteArrayOutputStream generateFileEnd(FilePart filePart) @@ -415,7 +414,7 @@ private long handleFileHeaders(WritableByteChannel target, FilePart filePart) th ByteArrayOutputStream overhead = generateFileStart(filePart); - return writeToTarget(target, overhead); + return writeToTarget(target, overhead.toByteArray()); } private ByteArrayOutputStream generateFileStart(FilePart filePart) @@ -525,7 +524,7 @@ private long handlePartSource(WritableByteChannel target, FilePart filePart) thr if (nRead > 0) { ByteArrayOutputStream bos = new ByteArrayOutputStream(nRead); bos.write(bytes, 0, nRead); - writeToTarget(target, bos); + writeToTarget(target, bos.toByteArray()); } } } finally { @@ -544,7 +543,7 @@ private long handleStringPart(WritableByteChannel target, StringPart currentPart Part.sendPart(outputStream, currentPart, boundary); - return writeToTarget(target, outputStream); + return writeToTarget(target, outputStream.toByteArray()); } private long handleMultiPart(WritableByteChannel target, Part currentPart) throws IOException { @@ -561,13 +560,13 @@ private long handleMultiPart(WritableByteChannel target, Part currentPart) throw return 0; } - private long writeToTarget(WritableByteChannel target, ByteArrayOutputStream byteWriter) + private long writeToTarget(WritableByteChannel target, byte[] bytes) throws IOException { int written = 0; int maxSpin = 0; - synchronized (byteWriter) { - ByteBuffer message = ByteBuffer.wrap(byteWriter.toByteArray()); + synchronized (bytes) { + ByteBuffer message = ByteBuffer.wrap(bytes); if (target instanceof SocketChannel) { final Selector selector = Selector.open(); @@ -575,7 +574,7 @@ private long writeToTarget(WritableByteChannel target, ByteArrayOutputStream byt final SocketChannel channel = (SocketChannel) target; channel.register(selector, SelectionKey.OP_WRITE); - while (written < byteWriter.size()) { + while (written < bytes.length) { selector.select(1000); maxSpin++; final Set selectedKeys = selector.selectedKeys(); @@ -595,13 +594,13 @@ private long writeToTarget(WritableByteChannel target, ByteArrayOutputStream byt selector.close(); } } else { - while ((target.isOpen()) && (written < byteWriter.size())) { + while ((target.isOpen()) && (written < bytes.length)) { long nWrite = target.write(message); written += nWrite; if (nWrite == 0 && maxSpin++ < 10) { logger.info("Waiting for writing..."); try { - byteWriter.wait(1000); + bytes.wait(1000); } catch (InterruptedException e) { logger.trace(e.getMessage(), e); } @@ -616,5 +615,4 @@ private long writeToTarget(WritableByteChannel target, ByteArrayOutputStream byt } return written; } - } From fb86b397037066508cf2e8f01fc97385df8de62c Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 15 Jan 2014 12:49:28 +0100 Subject: [PATCH 150/701] initializeBuffer takes byte[], make immutable members final --- .../ning/http/multipart/MultipartBody.java | 50 ++++++++----------- 1 file changed, 22 insertions(+), 28 deletions(-) diff --git a/src/main/java/com/ning/http/multipart/MultipartBody.java b/src/main/java/com/ning/http/multipart/MultipartBody.java index f4665ff37a..14f7e05f20 100644 --- a/src/main/java/com/ning/http/multipart/MultipartBody.java +++ b/src/main/java/com/ning/http/multipart/MultipartBody.java @@ -32,19 +32,21 @@ public class MultipartBody implements RandomAccessBody { - private byte[] boundary; - private long contentLength; - private List parts; - private List files; - private int startPart; private final static Logger logger = LoggerFactory.getLogger(MultipartBody.class); - ByteArrayInputStream currentStream; - int currentStreamPosition; - boolean endWritten; - boolean doneWritingParts; - FileLocation fileLocation; - FilePart currentFilePart; - FileChannel currentFileChannel; + + private final byte[] boundary; + private final long contentLength; + private final List parts; + private final List files = new ArrayList(); + + private int startPart = 0; + private ByteArrayInputStream currentStream; + private int currentStreamPosition = -1; + private boolean endWritten = false; + private boolean doneWritingParts = false; + private FileLocation fileLocation = FileLocation.NONE; + private FilePart currentFilePart; + private FileChannel currentFileChannel; enum FileLocation {NONE, START, MIDDLE, END} @@ -52,15 +54,6 @@ public MultipartBody(List parts, String contentType, this.boundary = MultipartEncodingUtil.getAsciiBytes(contentType.substring(contentType.indexOf("boundary=") + "boundary=".length())); this.parts = parts; this.contentLength = contentLength; - - files = new ArrayList(); - - startPart = 0; - currentStreamPosition = -1; - endWritten = false; - doneWritingParts = false; - fileLocation = FileLocation.NONE; - currentFilePart = null; } public void close() throws IOException { @@ -180,7 +173,7 @@ public long read(ByteBuffer buffer) throws IOException { Part.sendMessageEnd(endWriter, boundary); - initializeBuffer(endWriter); + initializeBuffer(endWriter.toByteArray()); } if (currentStreamPosition > -1) { @@ -207,7 +200,7 @@ private void initializeByteArrayBody(FilePart filePart) ByteArrayOutputStream output = new ByteArrayOutputStream(); filePart.sendData(output); - initializeBuffer(output); + initializeBuffer(output.toByteArray()); fileLocation = FileLocation.MIDDLE; } @@ -217,7 +210,7 @@ private void initializeFileEnd(FilePart currentPart) ByteArrayOutputStream output = generateFileEnd(currentPart); - initializeBuffer(output); + initializeBuffer(output.toByteArray()); fileLocation = FileLocation.END; @@ -238,6 +231,7 @@ private void initializeFileBody(FilePart currentPart) currentFileChannel = raf.getChannel(); } else { + // ByteArrayPartSource PartSource partSource = currentPart.getSource(); InputStream stream = partSource.createInputStream(); @@ -261,7 +255,7 @@ private void initializeFilePart(FilePart filePart) ByteArrayOutputStream output = generateFileStart(filePart); - initializeBuffer(output); + initializeBuffer(output.toByteArray()); fileLocation = FileLocation.START; } @@ -274,7 +268,7 @@ private void initializeStringPart(StringPart currentPart) Part.sendPart(outputStream, currentPart, boundary); - initializeBuffer(outputStream); + initializeBuffer(outputStream.toByteArray()); } private int writeToBuffer(ByteBuffer buffer, int length) @@ -300,10 +294,10 @@ private int writeToBuffer(ByteBuffer buffer, int length) return writeLength; } - private void initializeBuffer(ByteArrayOutputStream outputStream) + private void initializeBuffer(byte[] bytes) throws IOException { - currentStream = new ByteArrayInputStream(outputStream.toByteArray()); + currentStream = new ByteArrayInputStream(bytes); currentStreamPosition = 0; From ef1372fa8f46b573a1682fb979a601c7f1ce1c8d Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 15 Jan 2014 13:20:31 +0100 Subject: [PATCH 151/701] Don't write all the bytes just to compute the length!!! --- .../com/ning/http/multipart/FilePart.java | 12 +++ .../java/com/ning/http/multipart/Part.java | 86 ++++++++++++++++--- 2 files changed, 87 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/ning/http/multipart/FilePart.java b/src/main/java/com/ning/http/multipart/FilePart.java index 41b7e7025c..a064b55169 100644 --- a/src/main/java/com/ning/http/multipart/FilePart.java +++ b/src/main/java/com/ning/http/multipart/FilePart.java @@ -156,6 +156,18 @@ protected void sendDispositionHeader(OutputStream out) throws IOException { } } + protected int dispositionHeaderLength() { + String filename = this.source.getFileName(); + int length = super.dispositionHeaderLength(); + if (filename != null) { + length += FILE_NAME_BYTES.length; + length += QUOTE_BYTES.length; + length += MultipartEncodingUtil.getAsciiBytes(filename).length; + length += QUOTE_BYTES.length; + } + return length; + } + /** * Write the data in "source" to the specified stream. * diff --git a/src/main/java/com/ning/http/multipart/Part.java b/src/main/java/com/ning/http/multipart/Part.java index 7fcfdf603c..362a39825c 100644 --- a/src/main/java/com/ning/http/multipart/Part.java +++ b/src/main/java/com/ning/http/multipart/Part.java @@ -15,7 +15,6 @@ */ package com.ning.http.multipart; -import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; @@ -212,6 +211,10 @@ protected void sendStart(OutputStream out) throws IOException { out.write(getPartBoundary()); } + private int startLength() { + return EXTRA_BYTES.length + getPartBoundary().length; + } + /** * Write the content disposition header to the specified output stream * @@ -228,6 +231,18 @@ protected void sendDispositionHeader(OutputStream out) throws IOException { } } + protected int dispositionHeaderLength() { + int length = 0; + if (getName() != null) { + length += CRLF_BYTES.length; + length += CONTENT_DISPOSITION_BYTES.length; + length += QUOTE_BYTES.length; + length += MultipartEncodingUtil.getAsciiBytes(getName()).length; + length += QUOTE_BYTES.length; + } + return length; + } + /** * Write the content type header to the specified output stream * @@ -248,6 +263,22 @@ protected void sendContentTypeHeader(OutputStream out) throws IOException { } } + protected int contentTypeHeaderLength() { + int length = 0; + String contentType = getContentType(); + if (contentType != null) { + length += CRLF_BYTES.length; + length += CONTENT_TYPE_BYTES.length; + length += MultipartEncodingUtil.getAsciiBytes(contentType).length; + String charSet = getCharSet(); + if (charSet != null) { + length += CHARSET_BYTES.length; + length += MultipartEncodingUtil.getAsciiBytes(charSet).length; + } + } + return length; + } + /** * Write the content transfer encoding header to the specified output stream * @@ -263,6 +294,17 @@ protected void sendTransferEncodingHeader(OutputStream out) throws IOException { } } + protected int transferEncodingHeaderLength() { + int length = 0; + String transferEncoding = getTransferEncoding(); + if (transferEncoding != null) { + length += CRLF_BYTES.length; + length += CONTENT_TRANSFER_ENCODING_BYTES.length; + length += MultipartEncodingUtil.getAsciiBytes(transferEncoding).length; + } + return length; + } + /** * Write the content ID header to the specified output stream * @@ -278,6 +320,17 @@ protected void sendContentIdHeader(OutputStream out) throws IOException { } } + protected int contentIdHeaderLength() { + int length = 0; + String contentId = getContentId(); + if (contentId != null) { + length += CRLF_BYTES.length; + length += CONTENT_ID_BYTES.length; + length += MultipartEncodingUtil.getAsciiBytes(contentId).length; + } + return length; + } + /** * Write the end of the header to the output stream * @@ -289,6 +342,10 @@ protected void sendEndOfHeader(OutputStream out) throws IOException { out.write(CRLF_BYTES); } + protected int endOfHeaderLength() { + return CRLF_BYTES.length * 2; + } + /** * Write the data to the specified output stream * @@ -315,6 +372,10 @@ protected void sendEnd(OutputStream out) throws IOException { out.write(CRLF_BYTES); } + protected int endLength() { + return CRLF_BYTES.length; + } + /** * Write all the data to the output stream. If you override this method make sure to override #length() as well * @@ -339,18 +400,21 @@ public void send(OutputStream out) throws IOException { * @throws IOException If an IO problem occurs */ public long length() throws IOException { - if (lengthOfData() < 0) { + + long lengthOfData = lengthOfData(); + + if (lengthOfData < 0) { return -1; + } else { + return lengthOfData// + + startLength()// + + dispositionHeaderLength()// + + contentTypeHeaderLength()// + + transferEncodingHeaderLength()// + + contentIdHeaderLength()// + + endOfHeaderLength()// + + endLength(); } - ByteArrayOutputStream overhead = new ByteArrayOutputStream(); - sendStart(overhead); - sendDispositionHeader(overhead); - sendContentTypeHeader(overhead); - sendTransferEncodingHeader(overhead); - sendContentIdHeader(overhead); - sendEndOfHeader(overhead); - sendEnd(overhead); - return overhead.size() + lengthOfData(); } /** From feeeb7fa836c8957bdd8ac4e3aacce07f2c88594 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 15 Jan 2014 13:20:42 +0100 Subject: [PATCH 152/701] minor clean up --- .../http/util/AsyncHttpProviderUtils.java | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java index bc910361b6..1c96f5f701 100644 --- a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java +++ b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java @@ -300,25 +300,23 @@ public final static MultipartRequestEntity createMultipartRequestEntity(List Date: Wed, 15 Jan 2014 13:29:20 +0100 Subject: [PATCH 153/701] How come getting a length could result in an IOException? --- src/main/java/com/ning/http/multipart/FilePart.java | 3 +-- src/main/java/com/ning/http/multipart/Part.java | 10 ++++------ src/main/java/com/ning/http/multipart/StringPart.java | 3 +-- 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/ning/http/multipart/FilePart.java b/src/main/java/com/ning/http/multipart/FilePart.java index a064b55169..830d0f81bb 100644 --- a/src/main/java/com/ning/http/multipart/FilePart.java +++ b/src/main/java/com/ning/http/multipart/FilePart.java @@ -217,9 +217,8 @@ protected PartSource getSource() { * Return the length of the data. * * @return The length. - * @throws IOException if an IO problem occurs */ - protected long lengthOfData() throws IOException { + protected long lengthOfData() { return source.getLength(); } diff --git a/src/main/java/com/ning/http/multipart/Part.java b/src/main/java/com/ning/http/multipart/Part.java index 362a39825c..c8ad2726bf 100644 --- a/src/main/java/com/ning/http/multipart/Part.java +++ b/src/main/java/com/ning/http/multipart/Part.java @@ -358,9 +358,8 @@ protected int endOfHeaderLength() { * Return the length of the main content * * @return long The length. - * @throws IOException If an IO problem occurs */ - protected abstract long lengthOfData() throws IOException; + protected abstract long lengthOfData(); /** * Write the end data to the output stream. @@ -399,7 +398,7 @@ public void send(OutputStream out) throws IOException { * @return long The length. * @throws IOException If an IO problem occurs */ - public long length() throws IOException { + public long length() { long lengthOfData = lengthOfData(); @@ -501,9 +500,8 @@ public static void sendPart(OutputStream out, Part part, byte[] partBoundary) th * * @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) { return getLengthOfParts(parts, DEFAULT_BOUNDARY_BYTES); } @@ -516,7 +514,7 @@ public static long getLengthOfParts(Part[] parts) throws IOException { * @throws IOException If an I/O error occurs while writing the parts. * @since 3.0 */ - public static long getLengthOfParts(Part[] parts, byte[] partBoundary) throws IOException { + public static long getLengthOfParts(Part[] parts, byte[] partBoundary) { if (parts == null) { throw new IllegalArgumentException("Parts may not be null"); } diff --git a/src/main/java/com/ning/http/multipart/StringPart.java b/src/main/java/com/ning/http/multipart/StringPart.java index 6cd36c0ebc..b9bb149bd9 100644 --- a/src/main/java/com/ning/http/multipart/StringPart.java +++ b/src/main/java/com/ning/http/multipart/StringPart.java @@ -110,9 +110,8 @@ 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 */ - protected long lengthOfData() throws IOException { + protected long lengthOfData() { return getContent().length; } From 56e449e403badf70792ab497b2ac4d56ed344f6e Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 15 Jan 2014 13:30:58 +0100 Subject: [PATCH 154/701] dead code --- src/main/java/com/ning/http/multipart/Part.java | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/main/java/com/ning/http/multipart/Part.java b/src/main/java/com/ning/http/multipart/Part.java index c8ad2726bf..d74454190f 100644 --- a/src/main/java/com/ning/http/multipart/Part.java +++ b/src/main/java/com/ning/http/multipart/Part.java @@ -495,16 +495,6 @@ public static void sendPart(OutputStream out, Part part, byte[] partBoundary) th part.send(out); } - /** - * Return the total sum of all parts and that of the last boundary - * - * @param parts The parts. - * @return The total length - */ - public static long getLengthOfParts(Part[] parts) { - return getLengthOfParts(parts, DEFAULT_BOUNDARY_BYTES); - } - /** * Gets the length of the multipart message including the given parts. * From 44480ab4457a109a2b42eca5c07b3563d4b7cbbc Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 15 Jan 2014 13:34:26 +0100 Subject: [PATCH 155/701] Compute ContentLength only 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 7fad6d6585..bc9a3d11ce 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 @@ -834,8 +834,9 @@ else if (uri.getRawQuery() != null) MultipartRequestEntity mre = AsyncHttpProviderUtils.createMultipartRequestEntity(request.getParts(), request.getHeaders()); nettyRequest.setHeader(HttpHeaders.Names.CONTENT_TYPE, mre.getContentType()); - if (mre.getContentLength() >= 0) { - nettyRequest.setHeader(HttpHeaders.Names.CONTENT_LENGTH, String.valueOf(mre.getContentLength())); + long contentLength = mre.getContentLength(); + if (contentLength >= 0) { + nettyRequest.setHeader(HttpHeaders.Names.CONTENT_LENGTH, String.valueOf(contentLength)); } } else if (request.getEntityWriter() != null) { From 3a2a6d648e9929e4146ba31f2c883108b8d098b0 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 15 Jan 2014 13:36:50 +0100 Subject: [PATCH 156/701] Part length is long, not int --- .../com/ning/http/multipart/FilePart.java | 4 ++-- .../multipart/MultipartRequestEntity.java | 2 +- .../java/com/ning/http/multipart/Part.java | 24 +++++++++---------- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/ning/http/multipart/FilePart.java b/src/main/java/com/ning/http/multipart/FilePart.java index 830d0f81bb..0f3c84ff22 100644 --- a/src/main/java/com/ning/http/multipart/FilePart.java +++ b/src/main/java/com/ning/http/multipart/FilePart.java @@ -156,9 +156,9 @@ protected void sendDispositionHeader(OutputStream out) throws IOException { } } - protected int dispositionHeaderLength() { + protected long dispositionHeaderLength() { String filename = this.source.getFileName(); - int length = super.dispositionHeaderLength(); + long length = super.dispositionHeaderLength(); if (filename != null) { length += FILE_NAME_BYTES.length; length += QUOTE_BYTES.length; diff --git a/src/main/java/com/ning/http/multipart/MultipartRequestEntity.java b/src/main/java/com/ning/http/multipart/MultipartRequestEntity.java index 673a58c017..97f84b6c3c 100644 --- a/src/main/java/com/ning/http/multipart/MultipartRequestEntity.java +++ b/src/main/java/com/ning/http/multipart/MultipartRequestEntity.java @@ -134,7 +134,7 @@ public long getContentLength() { return Part.getLengthOfParts(parts, multipartBoundary); } catch (Exception e) { log.error("An exception occurred while getting the length of the parts", e); - return 0; + return 0L; } } diff --git a/src/main/java/com/ning/http/multipart/Part.java b/src/main/java/com/ning/http/multipart/Part.java index d74454190f..254b41648b 100644 --- a/src/main/java/com/ning/http/multipart/Part.java +++ b/src/main/java/com/ning/http/multipart/Part.java @@ -231,8 +231,8 @@ protected void sendDispositionHeader(OutputStream out) throws IOException { } } - protected int dispositionHeaderLength() { - int length = 0; + protected long dispositionHeaderLength() { + long length = 0L; if (getName() != null) { length += CRLF_BYTES.length; length += CONTENT_DISPOSITION_BYTES.length; @@ -263,8 +263,8 @@ protected void sendContentTypeHeader(OutputStream out) throws IOException { } } - protected int contentTypeHeaderLength() { - int length = 0; + protected long contentTypeHeaderLength() { + long length = 0L; String contentType = getContentType(); if (contentType != null) { length += CRLF_BYTES.length; @@ -294,8 +294,8 @@ protected void sendTransferEncodingHeader(OutputStream out) throws IOException { } } - protected int transferEncodingHeaderLength() { - int length = 0; + protected long transferEncodingHeaderLength() { + long length = 0L; String transferEncoding = getTransferEncoding(); if (transferEncoding != null) { length += CRLF_BYTES.length; @@ -320,8 +320,8 @@ protected void sendContentIdHeader(OutputStream out) throws IOException { } } - protected int contentIdHeaderLength() { - int length = 0; + protected long contentIdHeaderLength() { + long length = 0L; String contentId = getContentId(); if (contentId != null) { length += CRLF_BYTES.length; @@ -342,7 +342,7 @@ protected void sendEndOfHeader(OutputStream out) throws IOException { out.write(CRLF_BYTES); } - protected int endOfHeaderLength() { + protected long endOfHeaderLength() { return CRLF_BYTES.length * 2; } @@ -371,7 +371,7 @@ protected void sendEnd(OutputStream out) throws IOException { out.write(CRLF_BYTES); } - protected int endLength() { + protected long endLength() { return CRLF_BYTES.length; } @@ -402,8 +402,8 @@ public long length() { long lengthOfData = lengthOfData(); - if (lengthOfData < 0) { - return -1; + if (lengthOfData < 0L) { + return -1L; } else { return lengthOfData// + startLength()// From 188f25bfbc4990c672400dbeb784fc1e581e72bf Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 15 Jan 2014 15:56:16 +0100 Subject: [PATCH 157/701] First step in making parts immutable and thread safe --- .../com/ning/http/client/ByteArrayPart.java | 10 +-- .../java/com/ning/http/client/FilePart.java | 9 +- .../ning/http/multipart/MultipartBody.java | 12 +-- .../java/com/ning/http/multipart/Part.java | 90 +++---------------- 4 files changed, 23 insertions(+), 98 deletions(-) diff --git a/src/main/java/com/ning/http/client/ByteArrayPart.java b/src/main/java/com/ning/http/client/ByteArrayPart.java index 3d7c73186c..41ae3c5abe 100644 --- a/src/main/java/com/ning/http/client/ByteArrayPart.java +++ b/src/main/java/com/ning/http/client/ByteArrayPart.java @@ -17,11 +17,11 @@ package com.ning.http.client; public class ByteArrayPart implements Part { - private String name; - private String fileName; - private byte[] data; - private String mimeType; - private String charSet; + private final String name; + private final String fileName; + private final byte[] data; + private final String mimeType; + private final String charSet; public ByteArrayPart(String name, String fileName, byte[] data, String mimeType, String charSet) { this.name = name; diff --git a/src/main/java/com/ning/http/client/FilePart.java b/src/main/java/com/ning/http/client/FilePart.java index 714395a745..c74571ef15 100644 --- a/src/main/java/com/ning/http/client/FilePart.java +++ b/src/main/java/com/ning/http/client/FilePart.java @@ -22,10 +22,10 @@ * A file multipart part. */ public class FilePart implements Part { - private String name; - private File file; - private String mimeType; - private String charSet; + private final String name; + private final File file; + private final String mimeType; + private final String charSet; public FilePart(String name, File file, String mimeType, String charSet) { this.name = name; @@ -37,7 +37,6 @@ public FilePart(String name, File file, String mimeType, String charSet) { /** * {@inheritDoc} */ - /* @Override */ public String getName() { return name; } diff --git a/src/main/java/com/ning/http/multipart/MultipartBody.java b/src/main/java/com/ning/http/multipart/MultipartBody.java index 14f7e05f20..e3bf3f4143 100644 --- a/src/main/java/com/ning/http/multipart/MultipartBody.java +++ b/src/main/java/com/ning/http/multipart/MultipartBody.java @@ -251,8 +251,6 @@ private void initializeFileBody(FilePart currentPart) private void initializeFilePart(FilePart filePart) throws IOException { - filePart.setPartBoundary(boundary); - ByteArrayOutputStream output = generateFileStart(filePart); initializeBuffer(output.toByteArray()); @@ -262,7 +260,6 @@ private void initializeFilePart(FilePart filePart) private void initializeStringPart(StringPart currentPart) throws IOException { - currentPart.setPartBoundary(boundary); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); @@ -404,7 +401,6 @@ private ByteArrayOutputStream generateFileEnd(FilePart filePart) } private long handleFileHeaders(WritableByteChannel target, FilePart filePart) throws IOException { - filePart.setPartBoundary(boundary); ByteArrayOutputStream overhead = generateFileStart(filePart); @@ -415,9 +411,7 @@ private ByteArrayOutputStream generateFileStart(FilePart filePart) throws IOException { ByteArrayOutputStream overhead = new ByteArrayOutputStream(); - filePart.setPartBoundary(boundary); - - filePart.sendStart(overhead); + filePart.sendStart(overhead, boundary); filePart.sendDispositionHeader(overhead); filePart.sendContentTypeHeader(overhead); filePart.sendTransferEncodingHeader(overhead); @@ -531,8 +525,6 @@ private long handlePartSource(WritableByteChannel target, FilePart filePart) thr private long handleStringPart(WritableByteChannel target, StringPart currentPart) throws IOException { - currentPart.setPartBoundary(boundary); - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); Part.sendPart(outputStream, currentPart, boundary); @@ -542,8 +534,6 @@ private long handleStringPart(WritableByteChannel target, StringPart currentPart private long handleMultiPart(WritableByteChannel target, Part currentPart) throws IOException { - currentPart.setPartBoundary(boundary); - if (currentPart.getClass().equals(StringPart.class)) { return handleStringPart(target, (StringPart) currentPart); } else if (currentPart.getClass().equals(FilePart.class)) { diff --git a/src/main/java/com/ning/http/multipart/Part.java b/src/main/java/com/ning/http/multipart/Part.java index 254b41648b..36057bc686 100644 --- a/src/main/java/com/ning/http/multipart/Part.java +++ b/src/main/java/com/ning/http/multipart/Part.java @@ -25,16 +25,6 @@ */ public abstract class Part implements com.ning.http.client.Part { - /** - * The boundary - */ - protected static final String BOUNDARY = "----------------314159265358979323846"; - - /** - * The default boundary to be used if etBoundaryBytes(byte[]) has not been called. - */ - private static final byte[] DEFAULT_BOUNDARY_BYTES = MultipartEncodingUtil.getAsciiBytes(BOUNDARY); - /** * Carriage return/linefeed */ @@ -115,21 +105,6 @@ public abstract class Part implements com.ning.http.client.Part { */ 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} - */ - public static String getBoundary() { - return BOUNDARY; - } - - /** - * The ASCII bytes to use as the multipart boundary. - */ - private byte[] boundaryBytes; - /** * Return the name of this part. * @@ -165,31 +140,6 @@ public static String getBoundary() { */ public abstract String getContentId(); - /** - * Gets the part boundary to be used. - * - * @return the part boundary as an array of bytes. - * @since 3.0 - */ - protected byte[] getPartBoundary() { - if (boundaryBytes == null) { - // custom boundary bytes have not been set, use the default. - return DEFAULT_BOUNDARY_BYTES; - } else { - return boundaryBytes; - } - } - - /** - * 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 - */ - void setPartBoundary(byte[] boundaryBytes) { - this.boundaryBytes = boundaryBytes; - } - /** * Tests if this part can be sent more than once. * @@ -204,15 +154,16 @@ public boolean isRepeatable() { * Write the start to the specified output stream * * @param out The output stream + * @param boundary the boundary * @throws java.io.IOException If an IO problem occurs. */ - protected void sendStart(OutputStream out) throws IOException { + protected void sendStart(OutputStream out, byte[] boundary) throws IOException { out.write(EXTRA_BYTES); - out.write(getPartBoundary()); + out.write(boundary); } - private int startLength() { - return EXTRA_BYTES.length + getPartBoundary().length; + private int startLength(byte[] boundary) { + return EXTRA_BYTES.length + boundary.length; } /** @@ -379,10 +330,11 @@ protected long endLength() { * 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 + * @param boundary the boundary * @throws IOException If an IO problem occurs. */ - public void send(OutputStream out) throws IOException { - sendStart(out); + public void send(OutputStream out, byte[] boundary) throws IOException { + sendStart(out, boundary); sendDispositionHeader(out); sendContentTypeHeader(out); sendTransferEncodingHeader(out); @@ -398,7 +350,7 @@ public void send(OutputStream out) throws IOException { * @return long The length. * @throws IOException If an IO problem occurs */ - public long length() { + public long length(byte[] boundary) { long lengthOfData = lengthOfData(); @@ -406,7 +358,7 @@ public long length() { return -1L; } else { return lengthOfData// - + startLength()// + + startLength(boundary)// + dispositionHeaderLength()// + contentTypeHeaderLength()// + transferEncodingHeaderLength()// @@ -426,17 +378,6 @@ public String toString() { return this.getName(); } - /** - * 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. - * @throws IOException If an I/O error occurs while writing the parts. - */ - 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. * @@ -455,9 +396,7 @@ public static void sendParts(OutputStream out, Part[] parts, byte[] partBoundary throw new IllegalArgumentException("partBoundary may not be empty"); } for (Part part : parts) { - // set the part boundary before the part is sent - part.setPartBoundary(partBoundary); - part.send(out); + part.send(out, partBoundary); } out.write(EXTRA_BYTES); out.write(partBoundary); @@ -491,8 +430,7 @@ public static void sendPart(OutputStream out, Part part, byte[] partBoundary) th throw new IllegalArgumentException("Parts may not be null"); } - part.setPartBoundary(partBoundary); - part.send(out); + part.send(out, partBoundary); } /** @@ -510,9 +448,7 @@ public static long getLengthOfParts(Part[] parts, byte[] partBoundary) { } long total = 0; for (Part part : parts) { - // set the part boundary before we calculate the part's length - part.setPartBoundary(partBoundary); - long l = part.length(); + long l = part.length(partBoundary); if (l < 0) { return -1; } From e4bec3934233b2938ad5d4501fa34a7cf49a6a4f Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 15 Jan 2014 15:56:22 +0100 Subject: [PATCH 158/701] minor clean up --- .../com/ning/http/multipart/MultipartRequestEntity.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/ning/http/multipart/MultipartRequestEntity.java b/src/main/java/com/ning/http/multipart/MultipartRequestEntity.java index 97f84b6c3c..7233acaea7 100644 --- a/src/main/java/com/ning/http/multipart/MultipartRequestEntity.java +++ b/src/main/java/com/ning/http/multipart/MultipartRequestEntity.java @@ -70,7 +70,6 @@ public static byte[] generateMultipartBoundary() { /** * Creates a new multipart entity containing the given parts. - * * @param parts The parts to include. */ public MultipartRequestEntity(Part[] parts, FluentCaseInsensitiveStringsMap requestHeaders) { @@ -104,8 +103,7 @@ private String computeContentType(String base) { } /** - * 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. * * @return The boundary string of this entity in ASCII encoding. */ @@ -117,8 +115,8 @@ protected byte[] getMultipartBoundary() { * Returns true if all parts are repeatable, false otherwise. */ public boolean isRepeatable() { - for (int i = 0; i < parts.length; i++) { - if (!parts[i].isRepeatable()) { + for (Part part : parts) { + if (!part.isRepeatable()) { return false; } } From 6efae4141380cc470e3fef4bd56d5769397a6321 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 15 Jan 2014 16:03:49 +0100 Subject: [PATCH 159/701] Compute Content-Length in constructor --- .../multipart/MultipartRequestEntity.java | 18 +++------ .../java/com/ning/http/multipart/Part.java | 39 ++++++++++++------- 2 files changed, 31 insertions(+), 26 deletions(-) diff --git a/src/main/java/com/ning/http/multipart/MultipartRequestEntity.java b/src/main/java/com/ning/http/multipart/MultipartRequestEntity.java index 7233acaea7..b486f7da82 100644 --- a/src/main/java/com/ning/http/multipart/MultipartRequestEntity.java +++ b/src/main/java/com/ning/http/multipart/MultipartRequestEntity.java @@ -19,9 +19,6 @@ import com.ning.http.client.FluentCaseInsensitiveStringsMap; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import java.io.IOException; import java.io.OutputStream; import java.util.Random; @@ -57,16 +54,16 @@ public static byte[] generateMultipartBoundary() { return bytes; } - private final Logger log = LoggerFactory.getLogger(MultipartRequestEntity.class); - /** * The MIME parts as set by the constructor */ - protected Part[] parts; + protected final Part[] parts; private final byte[] multipartBoundary; private final String contentType; + + private final long contentLength; /** * Creates a new multipart entity containing the given parts. @@ -93,6 +90,8 @@ public MultipartRequestEntity(Part[] parts, FluentCaseInsensitiveStringsMap requ multipartBoundary = generateMultipartBoundary(); contentType = computeContentType(MULTIPART_FORM_CONTENT_TYPE); } + + contentLength = Part.getLengthOfParts(parts, multipartBoundary); } private String computeContentType(String base) { @@ -128,12 +127,7 @@ public void writeRequest(OutputStream out) throws IOException { } public long getContentLength() { - try { - return Part.getLengthOfParts(parts, multipartBoundary); - } catch (Exception e) { - log.error("An exception occurred while getting the length of the parts", e); - return 0L; - } + return contentLength; } public String getContentType() { diff --git a/src/main/java/com/ning/http/multipart/Part.java b/src/main/java/com/ning/http/multipart/Part.java index 36057bc686..e8f8268b17 100644 --- a/src/main/java/com/ning/http/multipart/Part.java +++ b/src/main/java/com/ning/http/multipart/Part.java @@ -18,6 +18,9 @@ import java.io.IOException; import java.io.OutputStream; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * This class is an adaptation of the Apache HttpClient implementation * @@ -25,6 +28,8 @@ */ public abstract class Part implements com.ning.http.client.Part { + private static final Logger LOGGER = LoggerFactory.getLogger(Part.class); + /** * Carriage return/linefeed */ @@ -443,21 +448,27 @@ public static void sendPart(OutputStream out, Part part, byte[] partBoundary) th * @since 3.0 */ public static long getLengthOfParts(Part[] parts, byte[] partBoundary) { - if (parts == null) { - throw new IllegalArgumentException("Parts may not be null"); - } - long total = 0; - for (Part part : parts) { - long l = part.length(partBoundary); - if (l < 0) { - return -1; + + try { + if (parts == null) { + throw new IllegalArgumentException("Parts may not be null"); + } + long total = 0; + for (Part part : parts) { + long l = part.length(partBoundary); + if (l < 0) { + return -1; + } + total += l; } - total += l; + total += EXTRA_BYTES.length; + total += partBoundary.length; + total += EXTRA_BYTES.length; + total += CRLF_BYTES.length; + return total; + } catch (Exception e) { + LOGGER.error("An exception occurred while getting the length of the parts", e); + return 0L; } - total += EXTRA_BYTES.length; - total += partBoundary.length; - total += EXTRA_BYTES.length; - total += CRLF_BYTES.length; - return total; } } From 028b46df02b1b16906715fd6358fb0881a588b0d Mon Sep 17 00:00:00 2001 From: jfarcand Date: Wed, 15 Jan 2014 10:22:10 -0500 Subject: [PATCH 160/701] [maven-release-plugin] prepare release async-http-client-1.7.24 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 8200e89cae..79c73ab7c2 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.7.24-SNAPSHOT + 1.7.24 jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From dd8a784bc21cbd6599f72d1c4802242b4f12f139 Mon Sep 17 00:00:00 2001 From: jfarcand Date: Wed, 15 Jan 2014 10:22:13 -0500 Subject: [PATCH 161/701] [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 79c73ab7c2..caa65107ac 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.7.24 + 1.7.25-SNAPSHOT jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From 5708fbe96b46279a2efcf70007a5e4a3255c0b90 Mon Sep 17 00:00:00 2001 From: jfarcand Date: Thu, 16 Jan 2014 17:41:19 -0500 Subject: [PATCH 162/701] Fix this craziness about singleton field --- .../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 bc9a3d11ce..1dca665139 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 @@ -2264,7 +2264,6 @@ 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 byte pendingOpcode = OPCODE_UNKNOWN; // We don't need to synchronize as replacing the "ws-decoder" will process using the same thread. private void invokeOnSucces(ChannelHandlerContext ctx, WebSocketUpgradeHandler h) { @@ -2351,6 +2350,7 @@ public void handle(ChannelHandlerContext ctx, MessageEvent e) throws Exception { final WebSocketFrame frame = (WebSocketFrame) e.getMessage(); + byte pendingOpcode = OPCODE_UNKNOWN; if (frame instanceof TextWebSocketFrame) { pendingOpcode = OPCODE_TEXT; } else if (frame instanceof BinaryWebSocketFrame) { From 99da52bf47219e4eaf502f0afc12165f156ee146 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Sat, 18 Jan 2014 23:28:57 +0100 Subject: [PATCH 163/701] BodyDeferringAsyncHandler.onComplete should build response when no part, close #113 --- .../com/ning/http/client/BodyDeferringAsyncHandler.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/ning/http/client/BodyDeferringAsyncHandler.java b/src/main/java/com/ning/http/client/BodyDeferringAsyncHandler.java index 3171d78aab..accce285ec 100644 --- a/src/main/java/com/ning/http/client/BodyDeferringAsyncHandler.java +++ b/src/main/java/com/ning/http/client/BodyDeferringAsyncHandler.java @@ -80,7 +80,7 @@ public class BodyDeferringAsyncHandler implements AsyncHandler { private final OutputStream output; - private volatile boolean responseSet; + private boolean responseSet; private volatile Response response; @@ -151,6 +151,12 @@ protected void closeOut() throws IOException { } public Response onCompleted() throws IOException { + + if (!responseSet) { + response = responseBuilder.build(); + responseSet = true; + } + // Counting down to handle error cases too. // In "normal" cases, latch is already at 0 here // But in other cases, for example when because of some error From 6ce19bb1787f95bda42a1e0dabdbaa671c179653 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Sat, 18 Jan 2014 23:52:35 +0100 Subject: [PATCH 164/701] Remove RequestBuilderBase.checkIfBodyAllowed, close #455 --- .../com/ning/http/client/RequestBuilderBase.java | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/main/java/com/ning/http/client/RequestBuilderBase.java b/src/main/java/com/ning/http/client/RequestBuilderBase.java index c3f704d302..71d3171b85 100644 --- a/src/main/java/com/ning/http/client/RequestBuilderBase.java +++ b/src/main/java/com/ning/http/client/RequestBuilderBase.java @@ -473,20 +473,12 @@ private void resetMultipartData() { request.parts = null; } - private void checkIfBodyAllowed() { - if ("HEAD".equals(request.method)) { - throw new IllegalArgumentException("Can NOT set Body on HTTP Request Method HEAD."); - } - } - public T setBody(File file) { - checkIfBodyAllowed(); request.file = file; return derived.cast(this); } public T setBody(byte[] data) throws IllegalArgumentException { - checkIfBodyAllowed(); resetParameters(); resetNonMultipartData(); resetMultipartData(); @@ -495,7 +487,6 @@ public T setBody(byte[] data) throws IllegalArgumentException { } public T setBody(String data) throws IllegalArgumentException { - checkIfBodyAllowed(); resetParameters(); resetNonMultipartData(); resetMultipartData(); @@ -504,7 +495,6 @@ public T setBody(String data) throws IllegalArgumentException { } public T setBody(InputStream stream) throws IllegalArgumentException { - checkIfBodyAllowed(); resetParameters(); resetNonMultipartData(); resetMultipartData(); @@ -517,7 +507,6 @@ public T setBody(EntityWriter dataWriter) { } public T setBody(EntityWriter dataWriter, long length) throws IllegalArgumentException { - checkIfBodyAllowed(); resetParameters(); resetNonMultipartData(); resetMultipartData(); @@ -527,7 +516,6 @@ public T setBody(EntityWriter dataWriter, long length) throws IllegalArgumentExc } public T setBody(BodyGenerator bodyGenerator) { - checkIfBodyAllowed(); request.bodyGenerator = bodyGenerator; return derived.cast(this); } From d912e01bca227da5ce51e2a4fc20986f4be7d665 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Sun, 19 Jan 2014 00:03:28 +0100 Subject: [PATCH 165/701] Remove old invalid test, fix previous commit --- .../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 baef8496b9..c660beb0b6 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 headShouldNotAllowBody() throws IllegalArgumentException, IOException { - AsyncHttpClient client = getAsyncHttpClient(null); - try { - AsyncHttpClient.BoundRequestBuilder builder = client.prepareHead(getTargetUrl()); - builder.setBody("Boo!"); - builder.execute(); - } finally { - client.close(); - } - } - protected String getBrokenTargetUrl() { return String.format("http:127.0.0.1:%d/foo/test", port1); } From 2b5c6e94469a5706ea7941ee4443105ab57b3545 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Sun, 19 Jan 2014 10:07:41 +0100 Subject: [PATCH 166/701] Upgrade Netty 3.9.0 and Grizzly 2.3.10, close #456 --- pom.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index caa65107ac..c67d479ba6 100644 --- a/pom.xml +++ b/pom.xml @@ -81,7 +81,7 @@ io.netty netty - 3.6.6.Final + 3.9.0.Final @@ -489,13 +489,13 @@ org.glassfish.grizzly grizzly-websockets - 2.3.7 + 2.3.10 true org.glassfish.grizzly grizzly-http-server - 2.3.5 + 2.3.10 test From dece38920dc44316946e5073e827973c66e45f7a Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 20 Jan 2014 17:17:16 +0100 Subject: [PATCH 167/701] Reimplement Netty provider timeouts, backport 4d029594c47405b94729f246168e30eb17b1feaf --- .../netty/NettyAsyncHttpProvider.java | 308 +++++++----------- .../providers/netty/NettyResponseFuture.java | 57 ++-- .../IdleConnectionTimeoutTimerTask.java | 69 ++++ .../timeout/RequestTimeoutTimerTask.java | 45 +++ .../netty/timeout/TimeoutTimerTask.java | 45 +++ .../netty/timeout/TimeoutsHolder.java | 35 ++ .../http/util/AsyncHttpProviderUtils.java | 5 + .../netty/NettyPerRequestTimeoutTest.java | 4 +- 8 files changed, 349 insertions(+), 219 deletions(-) create mode 100644 src/main/java/com/ning/http/client/providers/netty/timeout/IdleConnectionTimeoutTimerTask.java create mode 100644 src/main/java/com/ning/http/client/providers/netty/timeout/RequestTimeoutTimerTask.java create mode 100644 src/main/java/com/ning/http/client/providers/netty/timeout/TimeoutTimerTask.java create mode 100644 src/main/java/com/ning/http/client/providers/netty/timeout/TimeoutsHolder.java 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 1dca665139..162462ea9f 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,38 @@ */ package com.ning.http.client.providers.netty; -import com.ning.http.client.AsyncHandler; -import com.ning.http.client.AsyncHandler.STATE; -import com.ning.http.client.AsyncHandlerExtensions; -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 com.ning.org.jboss.netty.handler.codec.http.CookieEncoder; +import static com.ning.http.client.providers.netty.NettyAsyncHttpProviderConfig.*; +import static com.ning.http.util.AsyncHttpProviderUtils.*; +import static com.ning.http.util.MiscUtil.*; +import static org.jboss.netty.channel.Channels.*; + +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.List; +import java.util.Locale; +import java.util.Map.Entry; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.net.ssl.SSLEngine; import org.jboss.netty.bootstrap.ClientBootstrap; import org.jboss.netty.buffer.ChannelBuffer; @@ -104,56 +92,59 @@ import org.jboss.netty.handler.ssl.SslHandler; import org.jboss.netty.handler.stream.ChunkedFile; import org.jboss.netty.handler.stream.ChunkedWriteHandler; +import org.jboss.netty.util.HashedWheelTimer; +import org.jboss.netty.util.Timeout; +import org.jboss.netty.util.TimerTask; 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.List; -import java.util.Locale; -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.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; -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.AsyncHandlerExtensions; +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.providers.netty.timeout.IdleConnectionTimeoutTimerTask; +import com.ning.http.client.providers.netty.timeout.RequestTimeoutTimerTask; +import com.ning.http.client.providers.netty.timeout.TimeoutsHolder; +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 com.ning.org.jboss.netty.handler.codec.http.CookieEncoder; public class NettyAsyncHttpProvider extends SimpleChannelUpstreamHandler implements AsyncHttpProvider { @@ -208,6 +199,7 @@ public boolean remove(Object o) { private static SpnegoEngine spnegoEngine = null; private final Protocol httpProtocol = new HttpProtocol(); private final Protocol webSocketProtocol = new WebSocketProtocol(); + private HashedWheelTimer hashedWheelTimer; private static boolean isNTLM(List auth) { return isNonEmpty(auth) && auth.get(0).startsWith("NTLM"); @@ -271,6 +263,9 @@ public NettyAsyncHttpProvider(AsyncHttpClientConfig config) { } useRawUrl = config.isUseRawUrl(); + + hashedWheelTimer = new HashedWheelTimer(); + hashedWheelTimer.start(); } @Override @@ -597,18 +592,24 @@ public void operationComplete(ChannelFuture cf) { try { future.touch(); - 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, schedulePeriod, TimeUnit.MILLISECONDS); - reaperFuture.setScheduledFuture(scheduledFuture); - future.setReaperFuture(reaperFuture); + int requestTimeoutInMs = AsyncHttpProviderUtils.requestTimeout(config, future.getRequest()); + TimeoutsHolder timeoutsHolder = new TimeoutsHolder(); + if (requestTimeoutInMs != -1) { + Timeout requestTimeout = newTimeoutInMs(new RequestTimeoutTimerTask(future, this, timeoutsHolder), requestTimeoutInMs); + timeoutsHolder.requestTimeout = requestTimeout; + } + + int idleConnectionTimeoutInMs = config.getIdleConnectionTimeoutInMs(); + if (idleConnectionTimeoutInMs != -1 && idleConnectionTimeoutInMs < requestTimeoutInMs) { + // no need for a idleConnectionTimeout that's less than the requestTimeoutInMs + Timeout idleConnectionTimeout = newTimeoutInMs(new IdleConnectionTimeoutTimerTask(future, this, timeoutsHolder, + requestTimeoutInMs, idleConnectionTimeoutInMs), idleConnectionTimeoutInMs); + timeoutsHolder.idleConnectionTimeout = idleConnectionTimeout; } + } catch (RejectedExecutionException ex) { abort(future, ex); } - } protected final static HttpRequest buildRequest(AsyncHttpClientConfig config, Request request, URI uri, boolean allowConnect, ChannelBuffer buffer, ProxyServer proxyServer) throws IOException { @@ -871,7 +872,7 @@ public void close() { ChannelHandlerContext ctx = channel.getPipeline().getContext(NettyAsyncHttpProvider.class); if (ctx.getAttachment() instanceof NettyResponseFuture) { NettyResponseFuture future = (NettyResponseFuture) ctx.getAttachment(); - future.setReaperFuture(null); + future.cancelTimeouts(); } } @@ -884,6 +885,9 @@ public void close() { webSocketBootstrap.releaseExternalResources(); secureWebSocketBootstrap.releaseExternalResources(); } + + hashedWheelTimer.stop(); + } catch (Throwable t) { log.warn("Unexpected error on close", t); } @@ -907,7 +911,7 @@ private void execute(final Request request, final NettyResponseFuture f, private ListenableFuture doConnect(final Request request, final AsyncHandler asyncHandler, NettyResponseFuture f, boolean useCache, boolean asyncConnect, boolean reclaimCache) throws IOException { - if (isClose.get()) { + if (isClose()) { throw new IOException("Closed"); } @@ -1329,7 +1333,7 @@ private void nextRequest(final Request request, final NettyResponseFuture fut execute(request, future, useCache, true, true); } - private void abort(NettyResponseFuture future, Throwable t) { + public void abort(NettyResponseFuture future, Throwable t) { Channel channel = future.channel(); if (channel != null && openChannels.contains(channel)) { closeChannel(channel.getPipeline().getContext(NettyAsyncHttpProvider.class)); @@ -1364,7 +1368,7 @@ private void upgradeProtocol(ChannelPipeline p, String scheme) throws IOExceptio public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { - if (isClose.get()) { + if (isClose()) { return; } @@ -1413,7 +1417,7 @@ public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws protected boolean remotelyClosed(Channel channel, NettyResponseFuture future) { - if (isClose.get()) { + if (isClose()) { return true; } @@ -1725,94 +1729,6 @@ 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. - */ - private final class ReaperFuture implements Future, Runnable { - private Future scheduledFuture; - private NettyResponseFuture nettyResponseFuture; - - public ReaperFuture(NettyResponseFuture nettyResponseFuture) { - this.nettyResponseFuture = nettyResponseFuture; - } - - public void setScheduledFuture(Future scheduledFuture) { - this.scheduledFuture = scheduledFuture; - } - - /** - * @Override - */ - public boolean cancel(boolean mayInterruptIfRunning) { - nettyResponseFuture = null; - return scheduledFuture.cancel(mayInterruptIfRunning); - } - - /** - * @Override - */ - public Object get() throws InterruptedException, ExecutionException { - return scheduledFuture.get(); - } - - /** - * @Override - */ - public Object get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { - return scheduledFuture.get(timeout, unit); - } - - /** - * @Override - */ - public boolean isCancelled() { - return scheduledFuture.isCancelled(); - } - - /** - * @Override - */ - public boolean isDone() { - return scheduledFuture.isDone(); - } - - private void expire(String message) { - log.debug("{} for {}", message, nettyResponseFuture); - abort(nettyResponseFuture, new TimeoutException(message)); - nettyResponseFuture = null; - } - - /** - * @Override - */ - public synchronized void run() { - if (isClose.get()) { - cancel(true); - return; - } - - boolean futureDone = nettyResponseFuture.isDone(); - boolean futureCanceled = nettyResponseFuture.isCancelled(); - - if (nettyResponseFuture != null && !futureDone && !futureCanceled) { - - long now = millisTime(); - if (nettyResponseFuture.hasRequestTimedOut(now)) { - 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(); - expire("Request reached idle time out of " + nettyResponseFuture.getIdleConnectionTimeoutInMs() + " ms after " + age + " ms"); - } - - } else if (nettyResponseFuture == null || futureDone || futureCanceled) { - cancel(true); - } - } - } - private abstract class AsyncCallable implements Callable { private final NettyResponseFuture future; @@ -2451,6 +2367,14 @@ public void onClose(ChannelHandlerContext ctx, ChannelStateEvent e) { } } } + + public boolean isClose() { + return isClose.get(); + } + + public Timeout newTimeoutInMs(TimerTask task, long delayInMs) { + return hashedWheelTimer.newTimeout(task, delayInMs, TimeUnit.MILLISECONDS); + } private static boolean isWebSocket(URI uri) { return WEBSOCKET.equalsIgnoreCase(uri.getScheme()) || WEBSOCKET_SSL.equalsIgnoreCase(uri.getScheme()); 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 171a2bda6c..ef0580b854 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 @@ -41,6 +41,7 @@ import com.ning.http.client.ProxyServer; import com.ning.http.client.Request; import com.ning.http.client.listenable.AbstractListenableFuture; +import com.ning.http.client.providers.netty.timeout.TimeoutsHolder; /** * A {@link Future} that can be used to track when an asynchronous HTTP request has been fully processed. @@ -70,7 +71,9 @@ enum STATE { private HttpResponse httpResponse; private final AtomicReference exEx = new AtomicReference(); private final AtomicInteger redirectCount = new AtomicInteger(); - private volatile Future reaperFuture; + private volatile boolean requestTimeoutReached; + private volatile boolean idleConnectionTimeoutReached; + private volatile TimeoutsHolder timeoutsHolder; private final AtomicBoolean inAuth = new AtomicBoolean(false); private final AtomicBoolean statusReceived = new AtomicBoolean(false); private final AtomicLong touch = new AtomicLong(millisTime()); @@ -159,7 +162,7 @@ void setAsyncHandler(AsyncHandler asyncHandler) { */ /* @Override */ public boolean cancel(boolean force) { - cancelReaper(); + cancelTimeouts(); if (isCancelled.get()) return false; @@ -189,16 +192,23 @@ public boolean cancel(boolean force) { * @return true if response has expired and should be terminated. */ public boolean hasExpired() { - long now = millisTime(); - return hasConnectionIdleTimedOut(now) || hasRequestTimedOut(now); + return requestTimeoutReached || idleConnectionTimeoutReached; } - public boolean hasConnectionIdleTimedOut(long now) { - return idleConnectionTimeoutInMs != -1 && (now - touch.get()) >= idleConnectionTimeoutInMs; + public void setRequestTimeoutReached() { + this.requestTimeoutReached = true; } - public boolean hasRequestTimedOut(long now) { - return requestTimeoutInMs != -1 && (now - start) >= requestTimeoutInMs; + public boolean isRequestTimeoutReached() { + return requestTimeoutReached; + } + + public void setIdleConnectionTimeoutReached() { + this.idleConnectionTimeoutReached = true; + } + + public boolean isIdleConnectionTimeoutReached() { + return idleConnectionTimeoutReached; } /** @@ -209,14 +219,15 @@ public V get() throws InterruptedException, ExecutionException { try { return get(requestTimeoutInMs, TimeUnit.MILLISECONDS); } catch (TimeoutException e) { - cancelReaper(); + cancelTimeouts(); throw new ExecutionException(e); } } - void cancelReaper() { - if (reaperFuture != null) { - reaperFuture.cancel(false); + public void cancelTimeouts() { + if (timeoutsHolder != null) { + timeoutsHolder.cancel(); + timeoutsHolder = null; } } @@ -251,7 +262,7 @@ public V get(long l, TimeUnit tu) throws InterruptedException, TimeoutException, } throw new ExecutionException(te); } finally { - cancelReaper(); + cancelTimeouts(); } } } @@ -287,7 +298,7 @@ V getContent() throws ExecutionException { } throw new RuntimeException(ex); } finally { - cancelReaper(); + cancelTimeouts(); } } } @@ -299,7 +310,7 @@ V getContent() throws ExecutionException { public final void done() { try { - cancelReaper(); + cancelTimeouts(); if (exEx.get() != null) { return; @@ -320,7 +331,7 @@ public final void done() { } public final void abort(final Throwable t) { - cancelReaper(); + cancelTimeouts(); if (isDone.get() || isCancelled.get()) return; @@ -379,11 +390,6 @@ protected int incrementAndGetCurrentRedirectCount() { return redirectCount.incrementAndGet(); } - protected void setReaperFuture(Future reaperFuture) { - cancelReaper(); - this.reaperFuture = reaperFuture; - } - protected boolean isInAuth() { return inAuth.get(); } @@ -407,15 +413,17 @@ public boolean getAndSetStatusReceived(boolean sr) { /** * {@inheritDoc} */ - /* @Override */ public void touch() { touch.set(millisTime()); } + public long getLastTouch() { + return touch.get(); + } + /** * {@inheritDoc} */ - /* @Override */ public boolean getAndSetWriteHeaders(boolean writeHeaders) { boolean b = this.writeHeaders; this.writeHeaders = writeHeaders; @@ -425,7 +433,6 @@ public boolean getAndSetWriteHeaders(boolean writeHeaders) { /** * {@inheritDoc} */ - /* @Override */ public boolean getAndSetWriteBody(boolean writeBody) { boolean b = this.writeBody; this.writeBody = writeBody; @@ -512,7 +519,7 @@ public String toString() { ",\n\thttpResponse=" + httpResponse + // ",\n\texEx=" + exEx + // ",\n\tredirectCount=" + redirectCount + // - ",\n\treaperFuture=" + reaperFuture + // + ",\n\ttimeoutsHolder=" + timeoutsHolder + // ",\n\tinAuth=" + inAuth + // ",\n\tstatusReceived=" + statusReceived + // ",\n\ttouch=" + touch + // diff --git a/src/main/java/com/ning/http/client/providers/netty/timeout/IdleConnectionTimeoutTimerTask.java b/src/main/java/com/ning/http/client/providers/netty/timeout/IdleConnectionTimeoutTimerTask.java new file mode 100644 index 0000000000..23d2a3251c --- /dev/null +++ b/src/main/java/com/ning/http/client/providers/netty/timeout/IdleConnectionTimeoutTimerTask.java @@ -0,0 +1,69 @@ +/* + * Copyright 2010-2013 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.timeout; + +import static com.ning.http.util.DateUtil.*; + +import org.jboss.netty.util.Timeout; + +import com.ning.http.client.providers.netty.NettyAsyncHttpProvider; +import com.ning.http.client.providers.netty.NettyResponseFuture; + +public class IdleConnectionTimeoutTimerTask extends TimeoutTimerTask { + + private final long idleConnectionTimeout; + private final long requestTimeoutInstant; + + public IdleConnectionTimeoutTimerTask(NettyResponseFuture nettyResponseFuture, NettyAsyncHttpProvider provider, TimeoutsHolder timeoutsHolder, + long requestTimeout, long idleConnectionTimeout) { + super(nettyResponseFuture, provider, timeoutsHolder); + this.idleConnectionTimeout = idleConnectionTimeout; + requestTimeoutInstant = requestTimeout >= 0 ? nettyResponseFuture.getStart() + requestTimeout : Long.MAX_VALUE; + } + + public void run(Timeout timeout) throws Exception { + if (provider.isClose()) { + timeoutsHolder.cancel(); + return; + } + + if (!nettyResponseFuture.isDone() && !nettyResponseFuture.isCancelled()) { + + long now = millisTime(); + + long currentIdleConnectionTimeoutInstant = idleConnectionTimeout - nettyResponseFuture.getLastTouch(); + long durationBeforeCurrentIdleConnectionTimeout = currentIdleConnectionTimeoutInstant - now; + + if (durationBeforeCurrentIdleConnectionTimeout <= 0L) { + // idleConnectionTimeout reached + long durationSinceLastTouch = now - nettyResponseFuture.getLastTouch(); + expire("Connection reached idle timeout of " + idleConnectionTimeout + " ms after " + durationSinceLastTouch + " ms"); + nettyResponseFuture.setIdleConnectionTimeoutReached(); + + } else if (currentIdleConnectionTimeoutInstant < requestTimeoutInstant) { + // reschedule + timeoutsHolder.idleConnectionTimeout = provider.newTimeoutInMs(this, durationBeforeCurrentIdleConnectionTimeout); + + } else { + // otherwise, no need to reschedule: requestTimeout will happen sooner + timeoutsHolder.idleConnectionTimeout = null; + } + + } else { + timeoutsHolder.cancel(); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/ning/http/client/providers/netty/timeout/RequestTimeoutTimerTask.java b/src/main/java/com/ning/http/client/providers/netty/timeout/RequestTimeoutTimerTask.java new file mode 100644 index 0000000000..a6dfb62983 --- /dev/null +++ b/src/main/java/com/ning/http/client/providers/netty/timeout/RequestTimeoutTimerTask.java @@ -0,0 +1,45 @@ +/* + * Copyright 2010-2013 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.timeout; + +import static com.ning.http.util.DateUtil.*; + +import org.jboss.netty.util.Timeout; + +import com.ning.http.client.providers.netty.NettyAsyncHttpProvider; +import com.ning.http.client.providers.netty.NettyResponseFuture; + +public class RequestTimeoutTimerTask extends TimeoutTimerTask { + + public RequestTimeoutTimerTask(NettyResponseFuture nettyResponseFuture, NettyAsyncHttpProvider provider, TimeoutsHolder timeoutsHolder) { + super(nettyResponseFuture, provider, timeoutsHolder); + } + + public void run(Timeout timeout) throws Exception { + + // in any case, cancel possible idleConnectionTimeout + timeoutsHolder.cancel(); + + if (provider.isClose()) { + return; + } + + if (!nettyResponseFuture.isDone() && !nettyResponseFuture.isCancelled()) { + expire("Request reached timeout of " + nettyResponseFuture.getRequestTimeoutInMs() + " ms after " + (millisTime() - nettyResponseFuture.getStart()) + " ms"); + nettyResponseFuture.setRequestTimeoutReached(); + } + } +} diff --git a/src/main/java/com/ning/http/client/providers/netty/timeout/TimeoutTimerTask.java b/src/main/java/com/ning/http/client/providers/netty/timeout/TimeoutTimerTask.java new file mode 100644 index 0000000000..c14512c5bc --- /dev/null +++ b/src/main/java/com/ning/http/client/providers/netty/timeout/TimeoutTimerTask.java @@ -0,0 +1,45 @@ +/* + * Copyright 2010-2013 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.timeout; + +import java.util.concurrent.TimeoutException; + +import org.jboss.netty.util.TimerTask; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.ning.http.client.providers.netty.NettyAsyncHttpProvider; +import com.ning.http.client.providers.netty.NettyResponseFuture; + +public abstract class TimeoutTimerTask implements TimerTask { + + private static final Logger LOGGER = LoggerFactory.getLogger(TimeoutTimerTask.class); + + protected final NettyResponseFuture nettyResponseFuture; + protected final NettyAsyncHttpProvider provider; + protected final TimeoutsHolder timeoutsHolder; + + public TimeoutTimerTask(NettyResponseFuture nettyResponseFuture, NettyAsyncHttpProvider provider, TimeoutsHolder timeoutsHolder) { + this.nettyResponseFuture = nettyResponseFuture; + this.provider = provider; + this.timeoutsHolder = timeoutsHolder; + } + + protected void expire(String message) { + LOGGER.debug("{} for {}", message, nettyResponseFuture); + provider.abort(nettyResponseFuture, new TimeoutException(message)); + } +} diff --git a/src/main/java/com/ning/http/client/providers/netty/timeout/TimeoutsHolder.java b/src/main/java/com/ning/http/client/providers/netty/timeout/TimeoutsHolder.java new file mode 100644 index 0000000000..b501ab321f --- /dev/null +++ b/src/main/java/com/ning/http/client/providers/netty/timeout/TimeoutsHolder.java @@ -0,0 +1,35 @@ +/* + * Copyright 2010-2013 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.timeout; + +import org.jboss.netty.util.Timeout; + +public class TimeoutsHolder { + + public volatile Timeout requestTimeout; + public volatile Timeout idleConnectionTimeout; + + public void cancel() { + if (requestTimeout != null) { + requestTimeout.cancel(); + requestTimeout = null; + } + if (idleConnectionTimeout != null) { + idleConnectionTimeout.cancel(); + idleConnectionTimeout = null; + } + } +} diff --git a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java index 1c96f5f701..14618143ea 100644 --- a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java +++ b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java @@ -35,6 +35,7 @@ import com.ning.http.client.HttpResponseBodyPart; import com.ning.http.client.HttpResponseBodyPartsInputStream; import com.ning.http.client.Part; +import com.ning.http.client.Request; import com.ning.http.client.StringPart; import com.ning.http.multipart.ByteArrayPartSource; import com.ning.http.multipart.MultipartRequestEntity; @@ -548,4 +549,8 @@ public static void checkBodyParts(int statusCode, Collection Date: Tue, 21 Jan 2014 00:18:02 +0100 Subject: [PATCH 168/701] Don't collapse static imports --- .../netty/NettyAsyncHttpProvider.java | 19 +++++++++++++++---- .../providers/netty/NettyConnectListener.java | 1 - .../IdleConnectionTimeoutTimerTask.java | 2 +- .../timeout/RequestTimeoutTimerTask.java | 2 +- 4 files changed, 17 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 162462ea9f..d76af1bbfa 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,10 +15,21 @@ */ package com.ning.http.client.providers.netty; -import static com.ning.http.client.providers.netty.NettyAsyncHttpProviderConfig.*; -import static com.ning.http.util.AsyncHttpProviderUtils.*; -import static com.ning.http.util.MiscUtil.*; -import static org.jboss.netty.channel.Channels.*; +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.MiscUtil.isNonEmpty; +import static org.jboss.netty.channel.Channels.pipeline; import java.io.File; import java.io.FileInputStream; 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 e275e4ffbd..5542e3ae2c 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 @@ -41,7 +41,6 @@ import java.nio.channels.ClosedChannelException; import java.util.concurrent.atomic.AtomicBoolean; - /** * Non Blocking connect. */ diff --git a/src/main/java/com/ning/http/client/providers/netty/timeout/IdleConnectionTimeoutTimerTask.java b/src/main/java/com/ning/http/client/providers/netty/timeout/IdleConnectionTimeoutTimerTask.java index 23d2a3251c..adbb377672 100644 --- a/src/main/java/com/ning/http/client/providers/netty/timeout/IdleConnectionTimeoutTimerTask.java +++ b/src/main/java/com/ning/http/client/providers/netty/timeout/IdleConnectionTimeoutTimerTask.java @@ -15,7 +15,7 @@ */ package com.ning.http.client.providers.netty.timeout; -import static com.ning.http.util.DateUtil.*; +import static com.ning.http.util.DateUtil.millisTime; import org.jboss.netty.util.Timeout; diff --git a/src/main/java/com/ning/http/client/providers/netty/timeout/RequestTimeoutTimerTask.java b/src/main/java/com/ning/http/client/providers/netty/timeout/RequestTimeoutTimerTask.java index a6dfb62983..bee7383498 100644 --- a/src/main/java/com/ning/http/client/providers/netty/timeout/RequestTimeoutTimerTask.java +++ b/src/main/java/com/ning/http/client/providers/netty/timeout/RequestTimeoutTimerTask.java @@ -15,7 +15,7 @@ */ package com.ning.http.client.providers.netty.timeout; -import static com.ning.http.util.DateUtil.*; +import static com.ning.http.util.DateUtil.millisTime; import org.jboss.netty.util.Timeout; From 7afe80773df13668eb2a9d107018017c25b7cdfa Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 21 Jan 2014 18:48:17 +0100 Subject: [PATCH 169/701] Not perfect fix for race condition on remotely closed pooled connection, close #415 --- .../netty/NettyAsyncHttpProvider.java | 108 +++++++++++------- 1 file changed, 66 insertions(+), 42 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 d76af1bbfa..23e5c25804 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 @@ -459,7 +459,7 @@ protected final void writeRequest(final Channel channel, final AsyncHttpClie 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 channelClosed do it's work. */ if (!channel.isOpen() || !channel.isConnected()) { return; @@ -920,6 +920,48 @@ private void execute(final Request request, final NettyResponseFuture f, doConnect(request, f.getAsyncHandler(), f, useCache, asyncConnect, reclaimCache); } + private NettyResponseFuture buildNettyResponseFutureWithCachedChannel(Request request, AsyncHandler asyncHandler, NettyResponseFuture f, ProxyServer proxyServer, + URI uri, ChannelBuffer bufferedBytes, int maxTry) throws IOException { + + for (int i = 0; i < maxTry; i++) { + if (maxTry == 0) + return null; + + Channel channel = null; + if (f != null && f.reuseChannel() && f.channel() != null) { + channel = f.channel(); + } else { + URI connectionKeyUri = proxyServer != null ? proxyServer.getURI() : uri; + channel = lookupInCache(connectionKeyUri, request.getConnectionPoolKeyStrategy()); + } + + if (channel == null) + return null; + else { + HttpRequest nettyRequest = null; + + if (f == null) { + nettyRequest = buildRequest(config, request, uri, false, bufferedBytes, proxyServer); + f = newFuture(uri, request, asyncHandler, nettyRequest, config, this, proxyServer); + } else if (i == 0) { + // only build request on first try + nettyRequest = buildRequest(config, request, uri, f.isConnectAllowed(), bufferedBytes, proxyServer); + f.setNettyRequest(nettyRequest); + } + f.setState(NettyResponseFuture.STATE.POOLED); + f.attachChannel(channel, false); + + if (channel.isOpen() && channel.isConnected()) { + f.channel().getPipeline().getContext(NettyAsyncHttpProvider.class).setAttachment(f); + return f; + } else + // else, channel was closed by the server since we fetched it from the pool, starting over + f.attachChannel(null); + } + } + return null; + } + private ListenableFuture doConnect(final Request request, final AsyncHandler asyncHandler, NettyResponseFuture f, boolean useCache, boolean asyncConnect, boolean reclaimCache) throws IOException { if (isClose()) { @@ -939,58 +981,40 @@ private ListenableFuture doConnect(final Request request, final AsyncHand } else { uri = request.getURI(); } - Channel channel = null; - - if (useCache) { - if (f != null && f.reuseChannel() && f.channel() != null) { - channel = f.channel(); - } else { - 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())) { bufferedBytes = f.getNettyRequest().getContent(); } boolean useSSl = isSecure(uri) && !useProxy; - if (channel != null && channel.isOpen() && channel.isConnected()) { - 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); - f.setNettyRequest(nettyRequest); - } - f.setState(NettyResponseFuture.STATE.POOLED); - f.attachChannel(channel, false); - - log.debug("\nUsing cached Channel {}\n for request \n{}\n", channel, nettyRequest); - channel.getPipeline().getContext(NettyAsyncHttpProvider.class).setAttachment(f); + if (useCache) { + // 3 tentatives + NettyResponseFuture connectedFuture = buildNettyResponseFutureWithCachedChannel(request, asyncHandler, f, proxyServer, uri, bufferedBytes, 3); - try { - writeRequest(channel, config, f); - } catch (Exception ex) { - log.debug("writeRequest failure", ex); - if (useSSl && ex.getMessage() != null && ex.getMessage().contains("SSLEngine")) { - log.debug("SSLEngine failure", ex); - f = null; - } else { - try { - asyncHandler.onThrowable(ex); - } catch (Throwable t) { - log.warn("doConnect.writeRequest()", t); + if (connectedFuture != null) { + log.debug("\nUsing cached Channel {}\n for request \n{}\n", connectedFuture.channel(), connectedFuture.getNettyRequest()); + + try { + writeRequest(connectedFuture.channel(), config, connectedFuture); + } catch (Exception ex) { + log.debug("writeRequest failure", ex); + if (useSSl && ex.getMessage() != null && ex.getMessage().contains("SSLEngine")) { + log.debug("SSLEngine failure", ex); + connectedFuture = null; + } else { + try { + asyncHandler.onThrowable(ex); + } catch (Throwable t) { + log.warn("doConnect.writeRequest()", t); + } + IOException ioe = new IOException(ex.getMessage()); + ioe.initCause(ex); + throw ioe; } - IOException ioe = new IOException(ex.getMessage()); - ioe.initCause(ex); - throw ioe; } + return connectedFuture; } - return f; } // Do not throw an exception when we need an extra connection for a redirect. From 0952fd2d072f5537b8624d52b92926bc8562d38f Mon Sep 17 00:00:00 2001 From: Ryan Lubke Date: Tue, 21 Jan 2014 10:37:47 -0800 Subject: [PATCH 170/701] Changes for #450. --- .../http/client/providers/grizzly/GrizzlyAsyncHttpProvider.java | 1 + 1 file changed, 1 insertion(+) 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 e6241847af..2e0b7fe1d8 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 @@ -860,6 +860,7 @@ private boolean sendAsGrizzlyRequest(final Request request, if (httpCtx.isWSRequest && !httpCtx.establishingTunnel) { try { final URI wsURI = new URI(httpCtx.wsRequestURI); + secure = "wss".equalsIgnoreCase(wsURI.getScheme()); httpCtx.protocolHandler = Version.RFC6455.createHandler(true); httpCtx.handshake = httpCtx.protocolHandler.createHandShake(wsURI); requestPacket = (HttpRequestPacket) From 51b10cc50249037e03344ba976350ff023ae4b89 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 22 Jan 2014 01:51:38 +0100 Subject: [PATCH 171/701] Fix currentIdleConnectionTimeoutInstant computation --- .../providers/netty/timeout/IdleConnectionTimeoutTimerTask.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/timeout/IdleConnectionTimeoutTimerTask.java b/src/main/java/com/ning/http/client/providers/netty/timeout/IdleConnectionTimeoutTimerTask.java index adbb377672..53eaf739ac 100644 --- a/src/main/java/com/ning/http/client/providers/netty/timeout/IdleConnectionTimeoutTimerTask.java +++ b/src/main/java/com/ning/http/client/providers/netty/timeout/IdleConnectionTimeoutTimerTask.java @@ -44,7 +44,7 @@ public void run(Timeout timeout) throws Exception { long now = millisTime(); - long currentIdleConnectionTimeoutInstant = idleConnectionTimeout - nettyResponseFuture.getLastTouch(); + long currentIdleConnectionTimeoutInstant = idleConnectionTimeout + nettyResponseFuture.getLastTouch(); long durationBeforeCurrentIdleConnectionTimeout = currentIdleConnectionTimeoutInstant - now; if (durationBeforeCurrentIdleConnectionTimeout <= 0L) { From 4066b170c851f4d5fa17c5f83daca0b84c6efd64 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 22 Jan 2014 10:46:31 +0100 Subject: [PATCH 172/701] Issue a warning when RequestCompression is enabled, see #93 --- .../providers/netty/NettyAsyncHttpProvider.java | 11 ++++++----- 1 file changed, 6 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 23e5c25804..eca6d70daf 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 @@ -85,7 +85,6 @@ import org.jboss.netty.handler.codec.http.HttpChunk; import org.jboss.netty.handler.codec.http.HttpChunkTrailer; import org.jboss.netty.handler.codec.http.HttpClientCodec; -import org.jboss.netty.handler.codec.http.HttpContentCompressor; import org.jboss.netty.handler.codec.http.HttpContentDecompressor; import org.jboss.netty.handler.codec.http.HttpHeaders; import org.jboss.netty.handler.codec.http.HttpMethod; @@ -159,6 +158,8 @@ public class NettyAsyncHttpProvider extends SimpleChannelUpstreamHandler implements AsyncHttpProvider { + private static final Logger LOGGER = LoggerFactory.getLogger(NettyAsyncHttpProvider.class); + public static final String GZIP_DEFLATE = HttpHeaders.Values.GZIP + "," + HttpHeaders.Values.DEFLATE; public static final IOException REMOTELY_CLOSED_EXCEPTION = new IOException("Remotely Closed"); @@ -224,6 +225,10 @@ public NettyAsyncHttpProvider(AsyncHttpClientConfig config) { asyncHttpProviderConfig = new NettyAsyncHttpProviderConfig(); } + if (config.getRequestCompressionLevel() > 0) { + LOGGER.warn("Request was enabled but Netty actually doesn't support this feature"); + } + if (asyncHttpProviderConfig.getProperty(USE_BLOCKING_IO) != null) { socketChannelFactory = new OioClientSocketChannelFactory(config.executorService()); this.allowReleaseSocketChannelFactory = true; @@ -305,10 +310,6 @@ public ChannelPipeline getPipeline() throws Exception { pipeline.addLast(HTTP_HANDLER, createHttpClientCodec()); - if (config.getRequestCompressionLevel() > 0) { - pipeline.addLast("deflater", new HttpContentCompressor(config.getRequestCompressionLevel())); - } - if (config.isCompressionEnabled()) { pipeline.addLast("inflater", new HttpContentDecompressor()); } From 321f3c0519a38cd5663d41104e365bbb02b92623 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 22 Jan 2014 11:19:00 +0100 Subject: [PATCH 173/701] Prevent multiple close of AsyncHttpProvider and NettyAsyncHttpProvider, close #191 --- .../com/ning/http/client/AsyncHttpClient.java | 5 +- .../netty/NettyAsyncHttpProvider.java | 47 ++++++++++--------- 2 files changed, 27 insertions(+), 25 deletions(-) diff --git a/src/main/java/com/ning/http/client/AsyncHttpClient.java b/src/main/java/com/ning/http/client/AsyncHttpClient.java index ccc5285c17..e26c4559f6 100755 --- a/src/main/java/com/ning/http/client/AsyncHttpClient.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClient.java @@ -365,8 +365,9 @@ public AsyncHttpProvider getProvider() { * Close the underlying connections. */ public void close() { - httpProvider.close(); - isClosed.set(true); + if (isClosed.compareAndSet(false, true)) { + httpProvider.close(); + } } /** 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 eca6d70daf..52a504e063 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 @@ -875,33 +875,34 @@ else if (uri.getRawQuery() != null) } public void close() { - isClose.set(true); - try { - connectionsPool.destroy(); - openChannels.close(); - - for (Channel channel : openChannels) { - ChannelHandlerContext ctx = channel.getPipeline().getContext(NettyAsyncHttpProvider.class); - if (ctx.getAttachment() instanceof NettyResponseFuture) { - NettyResponseFuture future = (NettyResponseFuture) ctx.getAttachment(); - future.cancelTimeouts(); + if (isClose.compareAndSet(false, true)) { + try { + connectionsPool.destroy(); + openChannels.close(); + + for (Channel channel : openChannels) { + ChannelHandlerContext ctx = channel.getPipeline().getContext(NettyAsyncHttpProvider.class); + if (ctx.getAttachment() instanceof NettyResponseFuture) { + NettyResponseFuture future = (NettyResponseFuture) ctx.getAttachment(); + future.cancelTimeouts(); + } } - } - config.executorService().shutdown(); - config.reaper().shutdown(); - if (this.allowReleaseSocketChannelFactory) { - socketChannelFactory.releaseExternalResources(); - plainBootstrap.releaseExternalResources(); - secureBootstrap.releaseExternalResources(); - webSocketBootstrap.releaseExternalResources(); - secureWebSocketBootstrap.releaseExternalResources(); - } + config.executorService().shutdown(); + config.reaper().shutdown(); + if (this.allowReleaseSocketChannelFactory) { + socketChannelFactory.releaseExternalResources(); + plainBootstrap.releaseExternalResources(); + secureBootstrap.releaseExternalResources(); + webSocketBootstrap.releaseExternalResources(); + secureWebSocketBootstrap.releaseExternalResources(); + } - hashedWheelTimer.stop(); + hashedWheelTimer.stop(); - } catch (Throwable t) { - log.warn("Unexpected error on close", t); + } catch (Throwable t) { + log.warn("Unexpected error on close", t); + } } } From f9f9cf4ddb2dde011fde7bbe9fffd4fc89c07a42 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 22 Jan 2014 11:22:04 +0100 Subject: [PATCH 174/701] Make closeAsynchronously shutdown own thread, close #458 --- .../com/ning/http/client/AsyncHttpClient.java | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/ning/http/client/AsyncHttpClient.java b/src/main/java/com/ning/http/client/AsyncHttpClient.java index e26c4559f6..4f2a0321e1 100755 --- a/src/main/java/com/ning/http/client/AsyncHttpClient.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClient.java @@ -375,17 +375,21 @@ public void close() { */ public void closeAsynchronously() { final ExecutorService e = Executors.newSingleThreadExecutor(); - e.submit(new Runnable() { - public void run() { - try { - close(); - } catch (Throwable t) { - logger.warn("", t); - } finally { - e.shutdown(); + try { + e.submit(new Runnable() { + public void run() { + try { + close(); + } catch (Throwable t) { + logger.warn("", t); + } finally { + e.shutdown(); + } } - } - }); + }); + } finally { + e.shutdown(); + } } @Override From 88ccbf42c1b5c0c27f1ade75baae7a13a295b4bf Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 22 Jan 2014 11:28:33 +0100 Subject: [PATCH 175/701] revert --- .../com/ning/http/client/AsyncHttpClient.java | 24 ++++++++----------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/src/main/java/com/ning/http/client/AsyncHttpClient.java b/src/main/java/com/ning/http/client/AsyncHttpClient.java index 4f2a0321e1..e26c4559f6 100755 --- a/src/main/java/com/ning/http/client/AsyncHttpClient.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClient.java @@ -375,21 +375,17 @@ public void close() { */ public void closeAsynchronously() { final ExecutorService e = Executors.newSingleThreadExecutor(); - try { - e.submit(new Runnable() { - public void run() { - try { - close(); - } catch (Throwable t) { - logger.warn("", t); - } finally { - e.shutdown(); - } + e.submit(new Runnable() { + public void run() { + try { + close(); + } catch (Throwable t) { + logger.warn("", t); + } finally { + e.shutdown(); } - }); - } finally { - e.shutdown(); - } + } + }); } @Override From 754bdbfc77d32a0694165ca0a12872ecf8169dfa Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 22 Jan 2014 14:54:58 +0100 Subject: [PATCH 176/701] Move reaper to Apache provider specific config, close #331 --- .../http/client/AsyncHttpClientConfig.java | 14 +-------- .../client/AsyncHttpClientConfigBean.java | 16 ---------- .../apache/ApacheAsyncHttpProvider.java | 30 +++++++++++++++---- .../apache/ApacheAsyncHttpProviderConfig.java | 14 +++++++-- .../netty/NettyAsyncHttpProvider.java | 1 - 5 files changed, 38 insertions(+), 37 deletions(-) diff --git a/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java b/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java index e5b8a20736..c5f2e9fffd 100644 --- a/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java @@ -65,7 +65,6 @@ public class AsyncHttpClientConfig { protected boolean compressionEnabled; protected String userAgent; protected boolean allowPoolingConnection; - protected ScheduledExecutorService reaper; protected ExecutorService applicationThreadPool; protected ProxyServerSelector proxyServerSelector; protected SSLContext sslContext; @@ -148,7 +147,6 @@ private AsyncHttpClientConfig(int maxTotalConnections, this.ioExceptionFilters = ioExceptionFilters; this.requestCompressionLevel = requestCompressionLevel; this.maxRequestRetry = maxRequestRetry; - this.reaper = reaper; this.allowSslConnectionPool = allowSslConnectionCaching; this.removeQueryParamOnRedirect = removeQueryParamOnRedirect; this.hostnameVerifier = hostnameVerifier; @@ -166,15 +164,6 @@ private AsyncHttpClientConfig(int maxTotalConnections, this.useRawUrl = useRawUrl; } - /** - * A {@link ScheduledExecutorService} used to expire idle connections. - * - * @return {@link ScheduledExecutorService} - */ - public ScheduledExecutorService reaper() { - return reaper; - } - /** * Return the maximum number of connections an {@link com.ning.http.client.AsyncHttpClient} can handle. * @@ -469,7 +458,7 @@ public boolean isValid() { // when using a ManagedExecutorService. // When this is the case, we assume it's running. } - return (atpRunning && !reaper.isShutdown()); + return atpRunning; } /** @@ -1091,7 +1080,6 @@ public Builder(AsyncHttpClientConfig prototype) { userAgent = prototype.getUserAgent(); redirectEnabled = prototype.isRedirectEnabled(); compressionEnabled = prototype.isCompressionEnabled(); - reaper = prototype.reaper(); applicationThreadPool = prototype.executorService(); requestFilters.clear(); diff --git a/src/main/java/com/ning/http/client/AsyncHttpClientConfigBean.java b/src/main/java/com/ning/http/client/AsyncHttpClientConfigBean.java index 8ea0b17459..01aab8d4af 100644 --- a/src/main/java/com/ning/http/client/AsyncHttpClientConfigBean.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClientConfigBean.java @@ -23,7 +23,6 @@ import java.util.LinkedList; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ThreadFactory; /** @@ -79,13 +78,6 @@ public boolean verify(String s, SSLSession sslSession) { } void configureExecutors() { - 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; - } - }); applicationThreadPool = Executors.newCachedThreadPool(new ThreadFactory() { public Thread newThread(Runnable r) { Thread t = new Thread(r, "AsyncHttpClient-Callback"); @@ -150,14 +142,6 @@ public AsyncHttpClientConfigBean setAllowPoolingConnection(boolean allowPoolingC return this; } - public AsyncHttpClientConfigBean setReaper(ScheduledExecutorService reaper) { - if (this.reaper != null) { - this.reaper.shutdownNow(); - } - this.reaper = reaper; - return this; - } - public AsyncHttpClientConfigBean setApplicationThreadPool(ExecutorService applicationThreadPool) { if (this.applicationThreadPool != null) { this.applicationThreadPool.shutdownNow(); 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 a125d1ba9d..0eb710d95e 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 @@ -45,6 +45,7 @@ import com.ning.http.util.AsyncHttpProviderUtils; import com.ning.http.util.ProxyUtils; import com.ning.http.util.UTF8UrlEncoder; + import org.apache.commons.httpclient.CircularRedirectException; import org.apache.commons.httpclient.Credentials; import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler; @@ -85,6 +86,7 @@ import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; + import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; @@ -107,7 +109,10 @@ import java.util.Map; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executors; import java.util.concurrent.Future; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicBoolean; @@ -129,6 +134,7 @@ public class ApacheAsyncHttpProvider implements AsyncHttpProvider { private final AtomicInteger maxConnections = new AtomicInteger(); private final MultiThreadedHttpConnectionManager connectionManager; private final HttpClientParams params; + private final ScheduledExecutorService reaper; static { final SocketFactory factory = new TrustingSSLSocketFactory(); @@ -157,13 +163,26 @@ public ApacheAsyncHttpProvider(AsyncHttpClientConfig config) { params.setCookiePolicy(CookiePolicy.BROWSER_COMPATIBILITY); params.setParameter(HttpMethodParams.RETRY_HANDLER, new DefaultHttpMethodRetryHandler()); - AsyncHttpProviderConfig providerConfig = config.getAsyncHttpProviderConfig(); + reaper = getReaper(config.getAsyncHttpProviderConfig()); + } + + private ScheduledExecutorService getReaper(AsyncHttpProviderConfig providerConfig) { + + ScheduledExecutorService reaper = null; if (providerConfig instanceof ApacheAsyncHttpProvider) { - configure(ApacheAsyncHttpProviderConfig.class.cast(providerConfig)); + reaper = ApacheAsyncHttpProviderConfig.class.cast(providerConfig).getReaper(); } - } - private void configure(ApacheAsyncHttpProviderConfig config) { + 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; + } + }); + + return reaper; } public ListenableFuture execute(Request request, AsyncHandler handler) throws IOException { @@ -211,6 +230,7 @@ public ListenableFuture execute(Request request, AsyncHandler handler) } public void close() { + reaper.shutdown(); if (idleConnectionTimeoutThread != null) { idleConnectionTimeoutThread.shutdown(); idleConnectionTimeoutThread = null; @@ -455,7 +475,7 @@ public T call() { int delay = requestTimeout(config, future.getRequest().getPerRequestConfig()); if (delay != -1) { ReaperFuture reaperFuture = new ReaperFuture(future); - Future scheduledFuture = config.reaper().scheduleAtFixedRate(reaperFuture, delay, 500, TimeUnit.MILLISECONDS); + Future scheduledFuture = reaper.scheduleAtFixedRate(reaperFuture, delay, 500, TimeUnit.MILLISECONDS); reaperFuture.setScheduledFuture(scheduledFuture); future.setReaperFuture(reaperFuture); } diff --git a/src/main/java/com/ning/http/client/providers/apache/ApacheAsyncHttpProviderConfig.java b/src/main/java/com/ning/http/client/providers/apache/ApacheAsyncHttpProviderConfig.java index 8b2aee6d07..280ffad7c2 100644 --- a/src/main/java/com/ning/http/client/providers/apache/ApacheAsyncHttpProviderConfig.java +++ b/src/main/java/com/ning/http/client/providers/apache/ApacheAsyncHttpProviderConfig.java @@ -12,16 +12,18 @@ */ package com.ning.http.client.providers.apache; -import com.ning.http.client.AsyncHttpProviderConfig; - import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ScheduledExecutorService; + +import com.ning.http.client.AsyncHttpProviderConfig; public class ApacheAsyncHttpProviderConfig implements AsyncHttpProviderConfig { private final ConcurrentHashMap properties = new ConcurrentHashMap(); + private ScheduledExecutorService reaper; public AsyncHttpProviderConfig addProperty(String name, String value) { properties.put(name, value); @@ -39,4 +41,12 @@ public String removeProperty(String name) { public Set> propertiesSet() { return properties.entrySet(); } + + public void setReaper(ScheduledExecutorService reaper) { + this.reaper = reaper; + } + + public ScheduledExecutorService getReaper() { + return reaper; + } } 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 52a504e063..7c87d2a007 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 @@ -889,7 +889,6 @@ public void close() { } config.executorService().shutdown(); - config.reaper().shutdown(); if (this.allowReleaseSocketChannelFactory) { socketChannelFactory.releaseExternalResources(); plainBootstrap.releaseExternalResources(); From 8b58fe1576b40d6c41728fa22e034d0ac48064ee Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 22 Jan 2014 16:14:38 +0100 Subject: [PATCH 177/701] Move tests to Netty specific class, Grizzly don't care about ConnectionPool --- .../http/client/async/ConnectionPoolTest.java | 112 +++--------------- .../grizzly/GrizzlyConnectionPoolTest.java | 84 ------------- .../async/netty/NettyConnectionPoolTest.java | 92 ++++++++++++++ 3 files changed, 106 insertions(+), 182 deletions(-) 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 1a82889ec6..1870cb38b2 100644 --- a/src/test/java/com/ning/http/client/async/ConnectionPoolTest.java +++ b/src/test/java/com/ning/http/client/async/ConnectionPoolTest.java @@ -15,17 +15,10 @@ */ package com.ning.http.client.async; -import com.ning.http.client.AsyncCompletionHandler; -import com.ning.http.client.AsyncCompletionHandlerBase; -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 org.jboss.netty.channel.Channel; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.testng.Assert; -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.Map; @@ -35,10 +28,16 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; -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 org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.Assert; +import org.testng.annotations.Test; + +import com.ning.http.client.AsyncCompletionHandler; +import com.ning.http.client.AsyncCompletionHandlerBase; +import com.ning.http.client.AsyncHttpClient; +import com.ning.http.client.AsyncHttpClientConfig; +import com.ning.http.client.Response; public abstract class ConnectionPoolTest extends AbstractBasicTest { protected final Logger log = LoggerFactory.getLogger(AbstractBasicTest.class); @@ -133,89 +132,6 @@ public Response onCompleted(Response response) throws Exception { } } - @Test(groups = { "standalone", "default_provider" }) - public void testInvalidConnectionsPool() { - - ConnectionsPool cp = new ConnectionsPool() { - - public boolean offer(String key, Channel connection) { - return false; - } - - public Channel poll(String connection) { - return null; - } - - public boolean removeAll(Channel connection) { - return false; - } - - public boolean canCacheConnection() { - return false; - } - - public void destroy() { - - } - }; - - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setConnectionsPool(cp).build()); - try { - 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(); - } - } - - @Test(groups = { "standalone", "default_provider" }) - public void testValidConnectionsPool() { - - ConnectionsPool cp = new ConnectionsPool() { - - public boolean offer(String key, Channel connection) { - return true; - } - - public Channel poll(String connection) { - return null; - } - - public boolean removeAll(Channel connection) { - return false; - } - - public boolean canCacheConnection() { - return true; - } - - public void destroy() { - - } - }; - - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setConnectionsPool(cp).build()); - try { - Exception exception = null; - try { - client.prepareGet(getTargetUrl()).execute().get(TIMEOUT, TimeUnit.SECONDS); - } catch (Exception ex) { - ex.printStackTrace(); - exception = ex; - } - assertNull(exception); - } finally { - client.close(); - } - } - @Test(groups = { "standalone", "default_provider" }) public void multipleMaxConnectionOpenTest() throws Throwable { AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setAllowPoolingConnection(true).setConnectionTimeoutInMs(5000).setMaximumConnectionsTotal(1).build(); 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 c810843d6f..ee057a150f 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 @@ -15,17 +15,14 @@ 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.util.concurrent.TimeUnit; -import org.glassfish.grizzly.Connection; import org.testng.annotations.Test; 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; @@ -66,87 +63,6 @@ public void testMaxTotalConnectionsException() { } } - @Override - public void testValidConnectionsPool() { - ConnectionsPool cp = new ConnectionsPool() { - - public boolean offer(String key, Connection connection) { - return true; - } - - public Connection poll(String connection) { - return null; - } - - public boolean removeAll(Connection connection) { - return false; - } - - public boolean canCacheConnection() { - return true; - } - - public void destroy() { - - } - }; - - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setConnectionsPool(cp).build()); - try { - Exception exception = null; - try { - client.prepareGet(getTargetUrl()).execute().get(TIMEOUT, TimeUnit.SECONDS); - } catch (Exception ex) { - ex.printStackTrace(); - exception = ex; - } - assertNull(exception); - } finally { - client.close(); - } - } - - @Test(groups = { "standalone", "default_provider" }) - public void testInvalidConnectionsPool() { - - ConnectionsPool cp = new ConnectionsPool() { - - public boolean offer(String key, Connection connection) { - return false; - } - - public Connection poll(String connection) { - return null; - } - - public boolean removeAll(Connection connection) { - return false; - } - - public boolean canCacheConnection() { - return false; - } - - public void destroy() { - - } - }; - - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setConnectionsPool(cp).build()); - try { - Exception exception = null; - try { - client.prepareGet(getTargetUrl()).execute().get(TIMEOUT, TimeUnit.SECONDS); - } catch (Exception ex) { - ex.printStackTrace(); - exception = ex; - } - assertNotNull(exception); - } finally { - client.close(); - } - } - @Override @Test public void multipleMaxConnectionOpenTest() throws Throwable { diff --git a/src/test/java/com/ning/http/client/async/netty/NettyConnectionPoolTest.java b/src/test/java/com/ning/http/client/async/netty/NettyConnectionPoolTest.java index 3c1720e2cc..b1e08a0252 100644 --- a/src/test/java/com/ning/http/client/async/netty/NettyConnectionPoolTest.java +++ b/src/test/java/com/ning/http/client/async/netty/NettyConnectionPoolTest.java @@ -12,8 +12,18 @@ */ package com.ning.http.client.async.netty; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertNull; + +import java.util.concurrent.TimeUnit; + +import org.jboss.netty.channel.Channel; +import org.testng.annotations.Test; + import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClientConfig; +import com.ning.http.client.ConnectionsPool; import com.ning.http.client.async.ConnectionPoolTest; import com.ning.http.client.async.ProviderUtil; @@ -24,4 +34,86 @@ public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { return ProviderUtil.nettyProvider(config); } + @Test(groups = { "standalone", "default_provider" }) + public void testInvalidConnectionsPool() { + + ConnectionsPool cp = new ConnectionsPool() { + + public boolean offer(String key, Channel connection) { + return false; + } + + public Channel poll(String connection) { + return null; + } + + public boolean removeAll(Channel connection) { + return false; + } + + public boolean canCacheConnection() { + return false; + } + + public void destroy() { + + } + }; + + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setConnectionsPool(cp).build()); + try { + 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(); + } + } + + @Test(groups = { "standalone", "default_provider" }) + public void testValidConnectionsPool() { + + ConnectionsPool cp = new ConnectionsPool() { + + public boolean offer(String key, Channel connection) { + return true; + } + + public Channel poll(String connection) { + return null; + } + + public boolean removeAll(Channel connection) { + return false; + } + + public boolean canCacheConnection() { + return true; + } + + public void destroy() { + + } + }; + + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setConnectionsPool(cp).build()); + try { + Exception exception = null; + try { + client.prepareGet(getTargetUrl()).execute().get(TIMEOUT, TimeUnit.SECONDS); + } catch (Exception ex) { + ex.printStackTrace(); + exception = ex; + } + assertNull(exception); + } finally { + client.close(); + } + } } From a09d9ba195ecbbcf0d99978d04288c4ed61d66a9 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 22 Jan 2014 16:29:37 +0100 Subject: [PATCH 178/701] Add an option for disabling zero-copy in Netty provider, close #380 --- .../netty/NettyAsyncHttpProvider.java | 50 +++++++++---------- .../netty/NettyAsyncHttpProviderConfig.java | 13 +++++ 2 files changed, 38 insertions(+), 25 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 7c87d2a007..7d52b893d6 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 @@ -202,16 +202,17 @@ public boolean remove(Object o) { }; private final ConnectionsPool connectionsPool; private Semaphore freeConnections = null; - private final NettyAsyncHttpProviderConfig asyncHttpProviderConfig; + private final NettyAsyncHttpProviderConfig providerConfig; private boolean executeConnectAsync = true; public static final ThreadLocal IN_IO_THREAD = new ThreadLocalBoolean(); private final boolean trackConnections; private final boolean useRawUrl; + private final boolean disableZeroCopy; private final static NTLMEngine ntlmEngine = new NTLMEngine(); private static SpnegoEngine spnegoEngine = null; private final Protocol httpProtocol = new HttpProtocol(); private final Protocol webSocketProtocol = new WebSocketProtocol(); - private HashedWheelTimer hashedWheelTimer; + private final HashedWheelTimer hashedWheelTimer; private static boolean isNTLM(List auth) { return isNonEmpty(auth) && auth.get(0).startsWith("NTLM"); @@ -220,21 +221,21 @@ private static boolean isNTLM(List auth) { public NettyAsyncHttpProvider(AsyncHttpClientConfig config) { if (config.getAsyncHttpProviderConfig() instanceof NettyAsyncHttpProviderConfig) { - asyncHttpProviderConfig = NettyAsyncHttpProviderConfig.class.cast(config.getAsyncHttpProviderConfig()); + providerConfig = NettyAsyncHttpProviderConfig.class.cast(config.getAsyncHttpProviderConfig()); } else { - asyncHttpProviderConfig = new NettyAsyncHttpProviderConfig(); + providerConfig = new NettyAsyncHttpProviderConfig(); } if (config.getRequestCompressionLevel() > 0) { LOGGER.warn("Request was enabled but Netty actually doesn't support this feature"); } - if (asyncHttpProviderConfig.getProperty(USE_BLOCKING_IO) != null) { + if (providerConfig.getProperty(USE_BLOCKING_IO) != null) { socketChannelFactory = new OioClientSocketChannelFactory(config.executorService()); this.allowReleaseSocketChannelFactory = true; } else { // check if external NioClientSocketChannelFactory is defined - Object oo = asyncHttpProviderConfig.getProperty(SOCKET_CHANNEL_FACTORY); + Object oo = providerConfig.getProperty(SOCKET_CHANNEL_FACTORY); if (oo instanceof NioClientSocketChannelFactory) { this.socketChannelFactory = NioClientSocketChannelFactory.class.cast(oo); @@ -242,7 +243,7 @@ public NettyAsyncHttpProvider(AsyncHttpClientConfig config) { this.allowReleaseSocketChannelFactory = false; } else { ExecutorService e; - Object o = asyncHttpProviderConfig.getProperty(BOSS_EXECUTOR_SERVICE); + Object o = providerConfig.getProperty(BOSS_EXECUTOR_SERVICE); if (o instanceof ExecutorService) { e = ExecutorService.class.cast(o); } else { @@ -279,7 +280,7 @@ public NettyAsyncHttpProvider(AsyncHttpClientConfig config) { } useRawUrl = config.isUseRawUrl(); - + disableZeroCopy = providerConfig.isDisableZeroCopy(); hashedWheelTimer = new HashedWheelTimer(); hashedWheelTimer.start(); } @@ -294,8 +295,8 @@ public String toString() { } void configureNetty() { - if (asyncHttpProviderConfig != null) { - for (Entry entry : asyncHttpProviderConfig.propertiesSet()) { + if (providerConfig != null) { + for (Entry entry : providerConfig.propertiesSet()) { plainBootstrap.setOption(entry.getKey(), entry.getValue()); } configureHttpClientCodec(); @@ -304,7 +305,6 @@ void configureNetty() { plainBootstrap.setPipelineFactory(new ChannelPipelineFactory() { - /* @Override */ public ChannelPipeline getPipeline() throws Exception { ChannelPipeline pipeline = pipeline(); @@ -320,11 +320,11 @@ public ChannelPipeline getPipeline() throws Exception { }); DefaultChannelFuture.setUseDeadLockChecker(false); - if (asyncHttpProviderConfig != null) { - Object value = asyncHttpProviderConfig.getProperty(EXECUTE_ASYNC_CONNECT); + if (providerConfig != null) { + Object value = providerConfig.getProperty(EXECUTE_ASYNC_CONNECT); if (value instanceof Boolean) { executeConnectAsync = Boolean.class.cast(value); - } else if (asyncHttpProviderConfig.getProperty(DISABLE_NESTED_REQUEST) != null) { + } else if (providerConfig.getProperty(DISABLE_NESTED_REQUEST) != null) { DefaultChannelFuture.setUseDeadLockChecker(true); } } @@ -343,15 +343,15 @@ public ChannelPipeline getPipeline() throws Exception { } protected void configureHttpClientCodec() { - 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); + httpClientCodecMaxInitialLineLength = providerConfig.getProperty(HTTP_CLIENT_CODEC_MAX_INITIAL_LINE_LENGTH, Integer.class, httpClientCodecMaxInitialLineLength); + httpClientCodecMaxHeaderSize = providerConfig.getProperty(HTTP_CLIENT_CODEC_MAX_HEADER_SIZE, Integer.class, httpClientCodecMaxHeaderSize); + httpClientCodecMaxChunkSize = providerConfig.getProperty(HTTP_CLIENT_CODEC_MAX_CHUNK_SIZE, Integer.class, httpClientCodecMaxChunkSize); } protected void configureHttpsClientCodec() { - 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); + httpsClientCodecMaxInitialLineLength = providerConfig.getProperty(HTTPS_CLIENT_CODEC_MAX_INITIAL_LINE_LENGTH, Integer.class, httpsClientCodecMaxInitialLineLength); + httpsClientCodecMaxHeaderSize = providerConfig.getProperty(HTTPS_CLIENT_CODEC_MAX_HEADER_SIZE, Integer.class, httpsClientCodecMaxHeaderSize); + httpsClientCodecMaxChunkSize = providerConfig.getProperty(HTTPS_CLIENT_CODEC_MAX_CHUNK_SIZE, Integer.class, httpsClientCodecMaxChunkSize); } void constructSSLPipeline(final NettyConnectListener cl) { @@ -399,8 +399,8 @@ public ChannelPipeline getPipeline() throws Exception { } }); - if (asyncHttpProviderConfig != null) { - for (Entry entry : asyncHttpProviderConfig.propertiesSet()) { + if (providerConfig != null) { + for (Entry entry : providerConfig.propertiesSet()) { secureBootstrap.setOption(entry.getKey(), entry.getValue()); secureWebSocketBootstrap.setOption(entry.getKey(), entry.getValue()); } @@ -544,7 +544,7 @@ protected final void writeRequest(final Channel channel, final AsyncHttpClie fileLength = raf.length(); ChannelFuture writeFuture; - if (ssl) { + if (ssl || disableZeroCopy) { writeFuture = channel.write(new ChunkedFile(raf, 0, fileLength, MAX_BUFFERED_BYTES)); } else { final FileRegion region = new OptimizedFileRegion(raf, 0, fileLength); @@ -572,7 +572,7 @@ public void operationComplete(ChannelFuture cf) { } else if (body != null) { ChannelFuture writeFuture; - if (!ssl && body instanceof RandomAccessBody) { + if (!ssl && !disableZeroCopy && body instanceof RandomAccessBody) { BodyFileRegion bodyFileRegion = new BodyFileRegion((RandomAccessBody) body); writeFuture = channel.write(bodyFileRegion); } else { @@ -1059,7 +1059,7 @@ private ListenableFuture doConnect(final Request request, final AsyncHand // Do no enable this with win. if (!System.getProperty("os.name").toLowerCase(Locale.ENGLISH).contains("win")) { - bootstrap.setOption("reuseAddress", asyncHttpProviderConfig.getProperty(REUSE_ADDRESS)); + bootstrap.setOption("reuseAddress", providerConfig.getProperty(REUSE_ADDRESS)); } try { 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 79bd0741b7..f11bf07af6 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 @@ -78,6 +78,11 @@ public class NettyAsyncHttpProviderConfig implements AsyncHttpProviderConfig properties = new ConcurrentHashMap(); + /** + * Allow one to disable zero copy for bodies and use chunking instead; + */ + private boolean disableZeroCopy; + public NettyAsyncHttpProviderConfig() { properties.put(REUSE_ADDRESS, "false"); } @@ -136,4 +141,12 @@ public Object removeProperty(String name) { public Set> propertiesSet() { return properties.entrySet(); } + + public void setDisableZeroCopy(boolean disableZeroCopy) { + this.disableZeroCopy = disableZeroCopy; + } + + public boolean isDisableZeroCopy() { + return disableZeroCopy; + } } \ No newline at end of file From 8a7328c12db62cbf5ab8ccec8db317711e37f4be Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 22 Jan 2014 16:50:02 +0100 Subject: [PATCH 179/701] Clean up --- src/test/java/com/ning/http/client/async/BasicAuthTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 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 9a2d0a2d29..01c7632923 100644 --- a/src/test/java/com/ning/http/client/async/BasicAuthTest.java +++ b/src/test/java/com/ning/http/client/async/BasicAuthTest.java @@ -287,9 +287,9 @@ public void redirectAndBasicAuthTest() throws Exception, ExecutionException, Tim Future f = r.execute(); Response resp = f.get(3, TimeUnit.SECONDS); - assertEquals(resp.getStatusCode(), HttpServletResponse.SC_OK); - assertNotNull(resp); - assertNotNull(resp.getHeader("X-Auth")); + assertNotNull(resp, "Response shouldn't be null"); + assertEquals(resp.getStatusCode(), HttpServletResponse.SC_OK, "Status code should be 200-OK"); + assertNotNull(resp.getHeader("X-Auth"), "X-Auth shouldn't be null"); } finally { if (client != null) From ccf12d76c91922affe2dbb22330701e1abaea089 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 22 Jan 2014 18:08:21 +0100 Subject: [PATCH 180/701] Have Netty provider notify last chunk (always empty when chunked), close #428 --- .../providers/netty/NettyAsyncHttpProvider.java | 4 +--- .../com/ning/http/client/async/EmptyBodyTest.java | 12 +++++++----- 2 files changed, 8 insertions(+), 8 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 7d52b893d6..d345a950f3 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 @@ -2157,9 +2157,7 @@ public Object call() throws Exception { finishUpdate(future, ctx, response.isChunked()); return; } else if (!response.isChunked()) { - if (response.getContent().readableBytes() != 0) { - updateBodyAndInterrupt(future, handler, new ResponseBodyPart(future.getURI(), response, NettyAsyncHttpProvider.this, true)); - } + updateBodyAndInterrupt(future, handler, new ResponseBodyPart(future.getURI(), response, NettyAsyncHttpProvider.this, true)); finishUpdate(future, ctx, false); return; } 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 ea0bbab5fa..4583a70e4d 100644 --- a/src/test/java/com/ning/http/client/async/EmptyBodyTest.java +++ b/src/test/java/com/ning/http/client/async/EmptyBodyTest.java @@ -83,13 +83,15 @@ 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.isEmpty()) { - // noinspection ThrowableInstanceNeverThrown + + byte[] bytes = e.getBodyPartBytes(); + + if (bytes.length != 0) { + String s = new String(bytes); + log.info("got part: {}", s); log.warn("Sampling stacktrace.", new Throwable("trace that, we should not get called for empty body.")); + queue.put(s); } - queue.put(s); return STATE.CONTINUE; } From d756bb86f0f441e8dbddc219d0ee9d9504f4a203 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 22 Jan 2014 23:28:12 +0100 Subject: [PATCH 181/701] typo --- .../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 d345a950f3..f3ad404690 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 @@ -415,7 +415,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 against a proxy that require upgrading from http to + // only occurs when a HttpMethod.CONNECT is used against a proxy that requires upgrading from http to // https. return verifyChannelPipeline(channel, uri.getScheme()); } catch (Exception ex) { From 38d019658dbaa3cabbb5a538fffffc04567450bb Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 23 Jan 2014 11:49:39 +0100 Subject: [PATCH 182/701] Netty ResponseBodyPart doesn't need to hold a reference of the Response and the Chunk, close #461 --- .../providers/netty/ResponseBodyPart.java | 23 ++++++------------- 1 file changed, 7 insertions(+), 16 deletions(-) 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 6ed8abc945..7b80e48a67 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 @@ -32,23 +32,18 @@ */ public class ResponseBodyPart extends HttpResponseBodyPart { - private final HttpChunk chunk; - private final HttpResponse response; + private final ChannelBuffer content; private final AtomicReference bytes = new AtomicReference(null); private final boolean isLast; private boolean closeConnection = false; public ResponseBodyPart(URI uri, HttpResponse response, AsyncHttpProvider provider, boolean last) { - super(uri, provider); - isLast = last; - this.chunk = null; - this.response = response; + this(uri, response, provider, null, last); } public ResponseBodyPart(URI uri, HttpResponse response, AsyncHttpProvider provider, HttpChunk chunk, boolean last) { super(uri, provider); - this.chunk = chunk; - this.response = response; + content = chunk != null ? chunk.getContent() : response.getContent(); isLast = last; } @@ -63,9 +58,9 @@ public byte[] getBodyPartBytes() { return bytes.get(); } - byte[] rb = ChannelBufferUtil.channelBuffer2bytes(getChannelBuffer()); - bytes.set(rb); - return rb; + byte[] b = ChannelBufferUtil.channelBuffer2bytes(getChannelBuffer()); + bytes.set(b); + return b; } public int writeTo(OutputStream outputStream) throws IOException { @@ -80,7 +75,7 @@ public int writeTo(OutputStream outputStream) throws IOException { } public ChannelBuffer getChannelBuffer() { - return chunk != null ? chunk.getContent() : response.getContent(); + return content; } @Override @@ -111,8 +106,4 @@ public void markUnderlyingConnectionAsClosed() { public boolean closeUnderlyingConnection() { return closeConnection; } - - protected HttpChunk chunk() { - return chunk; - } } From 13851e82b49a32de80bf4b800da372b14134828a Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 23 Jan 2014 11:51:20 +0100 Subject: [PATCH 183/701] Add HttpResponseBodyPart.length(), close #460 --- .../com/ning/http/client/HttpResponseBodyPart.java | 13 +++++++------ .../providers/apache/ApacheResponseBodyPart.java | 7 ++++++- .../providers/grizzly/GrizzlyResponseBodyPart.java | 4 ++++ .../http/client/providers/jdk/ResponseBodyPart.java | 7 ++++++- .../client/providers/netty/ResponseBodyPart.java | 7 +++++++ 5 files changed, 30 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/ning/http/client/HttpResponseBodyPart.java b/src/main/java/com/ning/http/client/HttpResponseBodyPart.java index ca73d4824b..140c60983f 100644 --- a/src/main/java/com/ning/http/client/HttpResponseBodyPart.java +++ b/src/main/java/com/ning/http/client/HttpResponseBodyPart.java @@ -34,7 +34,7 @@ public HttpResponseBodyPart(URI uri, AsyncHttpProvider provider) { * * @return the response body's part bytes received. */ - abstract public byte[] getBodyPartBytes(); + public abstract byte[] getBodyPartBytes(); /** * Write the available bytes to the {@link java.io.OutputStream} @@ -43,7 +43,7 @@ public HttpResponseBodyPart(URI uri, AsyncHttpProvider provider) { * @return The number of bytes written * @throws IOException */ - abstract public int writeTo(OutputStream outputStream) throws IOException; + public abstract int writeTo(OutputStream outputStream) throws IOException; /** * Return a {@link ByteBuffer} that wraps the actual bytes read from the response's chunk. The {@link ByteBuffer} @@ -51,27 +51,28 @@ public HttpResponseBodyPart(URI uri, AsyncHttpProvider provider) { * * @return {@link ByteBuffer} */ - abstract public ByteBuffer getBodyByteBuffer(); + public abstract ByteBuffer getBodyByteBuffer(); /** * Return true if this is the last part. * * @return true if this is the last part. */ - abstract public boolean isLast(); + public abstract boolean isLast(); /** * Close the underlying connection once the processing has completed. Invoking that method means the * underlying TCP connection will be closed as soon as the processing of the response is completed. That * means the underlying connection will never get pooled. */ - abstract public void markUnderlyingConnectionAsClosed(); + public abstract void markUnderlyingConnectionAsClosed(); /** * Return true of the underlying connection will be closed once the response has been fully processed. * * @return true of the underlying connection will be closed once the response has been fully processed. */ - abstract public boolean closeUnderlyingConnection(); + public abstract boolean closeUnderlyingConnection(); + public abstract int length(); } diff --git a/src/main/java/com/ning/http/client/providers/apache/ApacheResponseBodyPart.java b/src/main/java/com/ning/http/client/providers/apache/ApacheResponseBodyPart.java index c66823baeb..0e87dd0587 100644 --- a/src/main/java/com/ning/http/client/providers/apache/ApacheResponseBodyPart.java +++ b/src/main/java/com/ning/http/client/providers/apache/ApacheResponseBodyPart.java @@ -78,4 +78,9 @@ public void markUnderlyingConnectionAsClosed() { public boolean closeUnderlyingConnection() { return closeConnection; } -} \ No newline at end of file + + @Override + public int length() { + return chunk != null? chunk.length: 0; + } +} diff --git a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponseBodyPart.java b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponseBodyPart.java index 4692cfe071..d304f1164f 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponseBodyPart.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponseBodyPart.java @@ -139,4 +139,8 @@ Buffer getBodyBuffer() { } + @Override + public int length() { + return content.getContent().remaining(); + } } diff --git a/src/main/java/com/ning/http/client/providers/jdk/ResponseBodyPart.java b/src/main/java/com/ning/http/client/providers/jdk/ResponseBodyPart.java index 7fd42649b1..89faefd938 100644 --- a/src/main/java/com/ning/http/client/providers/jdk/ResponseBodyPart.java +++ b/src/main/java/com/ning/http/client/providers/jdk/ResponseBodyPart.java @@ -78,4 +78,9 @@ public void markUnderlyingConnectionAsClosed() { public boolean closeUnderlyingConnection() { return closeConnection; } -} \ No newline at end of file + + @Override + public int length() { + return chunk != null? chunk.length: 0; + } +} 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 7b80e48a67..5abdf8546c 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 @@ -35,6 +35,7 @@ public class ResponseBodyPart extends HttpResponseBodyPart { private final ChannelBuffer content; private final AtomicReference bytes = new AtomicReference(null); private final boolean isLast; + private final int length; private boolean closeConnection = false; public ResponseBodyPart(URI uri, HttpResponse response, AsyncHttpProvider provider, boolean last) { @@ -44,6 +45,7 @@ public ResponseBodyPart(URI uri, HttpResponse response, AsyncHttpProvider provid public ResponseBodyPart(URI uri, HttpResponse response, AsyncHttpProvider provider, HttpChunk chunk, boolean last) { super(uri, provider); content = chunk != null ? chunk.getContent() : response.getContent(); + length = content.readableBytes(); isLast = last; } @@ -106,4 +108,9 @@ public void markUnderlyingConnectionAsClosed() { public boolean closeUnderlyingConnection() { return closeConnection; } + + @Override + public int length() { + return length; + } } From 5507fae093299f9ac6b39483623296f110e11aa4 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 23 Jan 2014 13:12:30 +0100 Subject: [PATCH 184/701] NettyResponseFuture.isDone should return true when cancelled, close #417 --- .../client/providers/netty/NettyResponseFuture.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 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 ef0580b854..67e4d81cc0 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 @@ -87,7 +87,7 @@ enum STATE { private final int maxRetry; private boolean writeHeaders; private boolean writeBody; - private final AtomicBoolean throwableCalled = new AtomicBoolean(false); + private final AtomicBoolean onThrowableCalled = new AtomicBoolean(false); private boolean allowConnect = false; private final ConnectionPoolKeyStrategy connectionPoolKeyStrategy; private final ProxyServer proxyServer; @@ -142,7 +142,7 @@ public ProxyServer getProxyServer() { */ /* @Override */ public boolean isDone() { - return isDone.get(); + return isDone.get() || isCancelled.get(); } /** @@ -173,7 +173,7 @@ public boolean cancel(boolean force) { } catch (Throwable t) { // Ignore } - if (!throwableCalled.getAndSet(true)) { + if (!onThrowableCalled.getAndSet(true)) { try { asyncHandler.onThrowable(new CancellationException()); } catch (Throwable t) { @@ -252,7 +252,7 @@ public V get(long l, TimeUnit tu) throws InterruptedException, TimeoutException, } catch (Throwable t) { // Ignore } - if (!throwableCalled.getAndSet(true)) { + if (!onThrowableCalled.getAndSet(true)) { try { TimeoutException te = new TimeoutException(String.format("No response received after %s", l)); try { @@ -289,7 +289,7 @@ V getContent() throws ExecutionException { try { update = asyncHandler.onCompleted(); } catch (Throwable ex) { - if (!throwableCalled.getAndSet(true)) { + if (!onThrowableCalled.getAndSet(true)) { try { try { asyncHandler.onThrowable(ex); @@ -337,7 +337,7 @@ public final void abort(final Throwable t) { return; exEx.compareAndSet(null, new ExecutionException(t)); - if (!throwableCalled.getAndSet(true)) { + if (onThrowableCalled.compareAndSet(false, true)) { try { asyncHandler.onThrowable(t); } catch (Throwable te) { From 1a8c347455ecd1781e56ba2a15b6ddd43ab04fa9 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 23 Jan 2014 16:43:06 +0100 Subject: [PATCH 185/701] Netty Channel pool key should be (proxy +) target, close #364 --- .../providers/netty/NettyAsyncHttpProvider.java | 15 ++++++++------- .../providers/netty/NettyResponseFuture.java | 3 +-- 2 files changed, 9 insertions(+), 9 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 f3ad404690..e5c93b0755 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 @@ -1287,20 +1287,21 @@ private Realm ntlmProxyChallenge(List wwwAuth, Request request, ProxySer addType3NTLMAuthorizationHeader(wwwAuth, headers, proxyServer.getPrincipal(), proxyServer.getPassword(), proxyServer.getNtlmDomain(), proxyServer.getHost()); Realm newRealm; - Realm.RealmBuilder realmBuilder; + Realm.RealmBuilder realmBuilder = new Realm.RealmBuilder(); if (realm != null) { - realmBuilder = new Realm.RealmBuilder().clone(realm); - } else { - realmBuilder = new Realm.RealmBuilder(); + realmBuilder = realmBuilder.clone(realm); } 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 String getPoolKey(NettyResponseFuture future) { + + String serverPart = future.getConnectionPoolKeyStrategy().getKey(future.getURI()); + + ProxyServer proxy = future.getProxyServer(); + return proxy != null? AsyncHttpProviderUtils.getBaseUrl(proxy.getURI()) + serverPart : serverPart; } private void drainChannel(final ChannelHandlerContext ctx, final NettyResponseFuture future) { 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 67e4d81cc0..aca137ee90 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,7 +17,6 @@ import static com.ning.http.util.DateUtil.millisTime; -import java.net.MalformedURLException; import java.net.URI; import java.util.concurrent.CancellationException; import java.util.concurrent.CountDownLatch; @@ -121,7 +120,7 @@ public NettyResponseFuture(URI uri,// writeBody = true; } - protected URI getURI() throws MalformedURLException { + protected URI getURI() { return uri; } From a3d4224c97d4a1502068d577dca7880c85009cee Mon Sep 17 00:00:00 2001 From: jfarcand Date: Thu, 23 Jan 2014 11:47:06 -0500 Subject: [PATCH 186/701] Fixes #110 --- .../websocket/WebSocketUpgradeHandler.java | 13 +++++- .../client/websocket/TextMessageTest.java | 41 +++++++++++++++++++ 2 files changed, 53 insertions(+), 1 deletion(-) 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 6f7e20f472..2daab0f0cb 100644 --- a/src/main/java/com/ning/http/client/websocket/WebSocketUpgradeHandler.java +++ b/src/main/java/com/ning/http/client/websocket/WebSocketUpgradeHandler.java @@ -33,6 +33,7 @@ public class WebSocketUpgradeHandler implements UpgradeHandler, Async private final long maxTextSize; private final AtomicBoolean ok = new AtomicBoolean(false); private final AtomicBoolean onSuccessCalled = new AtomicBoolean(false); + private int status; protected WebSocketUpgradeHandler(Builder b) { l = b.l; @@ -49,7 +50,7 @@ public void onThrowable(Throwable t) { onFailure(t); } - public boolean touchSuccess(){ + public boolean touchSuccess() { return onSuccessCalled.getAndSet(true); } @@ -70,6 +71,7 @@ public STATE onBodyPartReceived(HttpResponseBodyPart bodyPart) throws Exception */ @Override public STATE onStatusReceived(HttpResponseStatus responseStatus) throws Exception { + status = responseStatus.getStatusCode(); if (responseStatus.getStatusCode() == 101) { return STATE.UPGRADE; } else { @@ -90,6 +92,14 @@ public STATE onHeadersReceived(HttpResponseHeaders headers) throws Exception { */ @Override public WebSocket onCompleted() throws Exception { + + if (status != 101) { + for (WebSocketListener w : l) { + w.onError(new IllegalStateException(String.format("Invalid Status Code %d", status))); + } + return null; + } + if (webSocket == null) { throw new IllegalStateException("WebSocket is null"); } @@ -203,6 +213,7 @@ public Builder setMaxTextSize(long maxTextSize) { /** * Build a {@link WebSocketUpgradeHandler} + * * @return a {@link WebSocketUpgradeHandler} */ public WebSocketUpgradeHandler build() { 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 219502d387..96b7500422 100644 --- a/src/test/java/com/ning/http/client/websocket/TextMessageTest.java +++ b/src/test/java/com/ning/http/client/websocket/TextMessageTest.java @@ -21,6 +21,7 @@ import java.util.concurrent.atomic.AtomicReference; import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertTrue; import static org.testng.Assert.fail; @@ -400,4 +401,44 @@ public void onError(Throwable t) { c.close(); } } + + @Test(timeOut = 60000) + public void wrongStatusCode() throws Throwable { + AsyncHttpClient c = getAsyncHttpClient(null); + try { + final CountDownLatch latch = new CountDownLatch(1); + final AtomicReference throwable = new AtomicReference(); + + WebSocket websocket = c.prepareGet("http://apache.org").execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(new WebSocketTextListener() { + + @Override + public void onMessage(String message) { + } + + @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) { + } + + @Override + public void onError(Throwable t) { + throwable.set(t); + latch.countDown(); + } + }).build()).get(); + + latch.await(); + assertNotNull(throwable.get()); + assertEquals(throwable.get().getClass(), IllegalStateException.class); + } finally { + c.close(); + } + } } From 84c86760d77ad9e45334b75f06bf968a4c4809a1 Mon Sep 17 00:00:00 2001 From: jfarcand Date: Thu, 23 Jan 2014 12:11:31 -0500 Subject: [PATCH 187/701] More the test under proper class --- .../websocket/CloseCodeReasonMessageTest.java | 46 +++++++++++++++++-- .../client/websocket/TextMessageTest.java | 40 ---------------- 2 files changed, 41 insertions(+), 45 deletions(-) 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 d1ff9fa5ce..1dd7d952b7 100644 --- a/src/test/java/com/ning/http/client/websocket/CloseCodeReasonMessageTest.java +++ b/src/test/java/com/ning/http/client/websocket/CloseCodeReasonMessageTest.java @@ -13,17 +13,13 @@ package com.ning.http.client.websocket; import com.ning.http.client.AsyncHttpClient; -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 org.testng.annotations.Test; import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicReference; import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertTrue; public abstract class CloseCodeReasonMessageTest extends TextMessageTest { @@ -97,4 +93,44 @@ public void onError(Throwable t) { latch.countDown(); } } + + @Test(timeOut = 60000) + public void wrongStatusCode() throws Throwable { + AsyncHttpClient c = getAsyncHttpClient(null); + try { + final CountDownLatch latch = new CountDownLatch(1); + final AtomicReference throwable = new AtomicReference(); + + WebSocket websocket = c.prepareGet("http://apache.org").execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(new WebSocketTextListener() { + + @Override + public void onMessage(String message) { + } + + @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) { + } + + @Override + public void onError(Throwable t) { + throwable.set(t); + latch.countDown(); + } + }).build()).get(); + + latch.await(); + assertNotNull(throwable.get()); + assertEquals(throwable.get().getClass(), IllegalStateException.class); + } finally { + c.close(); + } + } } 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 96b7500422..000367e43b 100644 --- a/src/test/java/com/ning/http/client/websocket/TextMessageTest.java +++ b/src/test/java/com/ning/http/client/websocket/TextMessageTest.java @@ -401,44 +401,4 @@ public void onError(Throwable t) { c.close(); } } - - @Test(timeOut = 60000) - public void wrongStatusCode() throws Throwable { - AsyncHttpClient c = getAsyncHttpClient(null); - try { - final CountDownLatch latch = new CountDownLatch(1); - final AtomicReference throwable = new AtomicReference(); - - WebSocket websocket = c.prepareGet("http://apache.org").execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(new WebSocketTextListener() { - - @Override - public void onMessage(String message) { - } - - @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) { - } - - @Override - public void onError(Throwable t) { - throwable.set(t); - latch.countDown(); - } - }).build()).get(); - - latch.await(); - assertNotNull(throwable.get()); - assertEquals(throwable.get().getClass(), IllegalStateException.class); - } finally { - c.close(); - } - } } From d86882f74ac943d08fa28208ce635a12c543f5ef Mon Sep 17 00:00:00 2001 From: Ryan Lubke Date: Thu, 23 Jan 2014 10:02:48 -0800 Subject: [PATCH 188/701] Changes for #364. --- .../providers/grizzly/GrizzlyAsyncHttpProvider.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 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 2e0b7fe1d8..5d1d487c5b 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 @@ -2434,8 +2434,12 @@ public void updated(Connection result) { } private static String getPoolKey(Request request, ProxyServer proxyServer) { - URI uri = proxyServer != null? proxyServer.getURI(): request.getURI(); - return request.getConnectionPoolKeyStrategy().getKey(uri); + String serverPart = + request.getConnectionPoolKeyStrategy().getKey(request.getURI()); + return proxyServer != null + ? AsyncHttpProviderUtils.getBaseUrl(proxyServer.getURI()) + + serverPart + : serverPart; } // ------------------------------------------------------ Nested Classes From c222771678cf36909553de86dd71a66283f61c52 Mon Sep 17 00:00:00 2001 From: Ryan Lubke Date: Thu, 23 Jan 2014 15:21:43 -0800 Subject: [PATCH 189/701] Uptake Grizzly 2.3.11. --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index c67d479ba6..6272807848 100644 --- a/pom.xml +++ b/pom.xml @@ -489,13 +489,13 @@ org.glassfish.grizzly grizzly-websockets - 2.3.10 + 2.3.11 true org.glassfish.grizzly grizzly-http-server - 2.3.10 + 2.3.11 test From 7018cb71fa7157c318ab80f700b2c529eee052a6 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 24 Jan 2014 09:56:41 +0100 Subject: [PATCH 190/701] Remove wrong copyright --- .../java/com/ning/http/client/ntlm/NTLMEngine.java | 12 ------------ .../ning/http/client/ntlm/NTLMEngineException.java | 12 ------------ 2 files changed, 24 deletions(-) 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..8af983e759 100644 --- a/src/main/java/com/ning/http/client/ntlm/NTLMEngine.java +++ b/src/main/java/com/ning/http/client/ntlm/NTLMEngine.java @@ -1,15 +1,3 @@ -/* - * 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. - */ /* * ==================================================================== * diff --git a/src/main/java/com/ning/http/client/ntlm/NTLMEngineException.java b/src/main/java/com/ning/http/client/ntlm/NTLMEngineException.java index d1c557520a..78cbdbb382 100644 --- a/src/main/java/com/ning/http/client/ntlm/NTLMEngineException.java +++ b/src/main/java/com/ning/http/client/ntlm/NTLMEngineException.java @@ -1,15 +1,3 @@ -/* - * 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. - */ /* * ==================================================================== * From f5a0b16b0184bd4555e55eff2d8c189e370030c8 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 24 Jan 2014 10:43:22 +0100 Subject: [PATCH 191/701] Now that Handler can be notified with empty chunks, I feel safer with this, see #428 --- src/main/java/com/ning/http/client/Response.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/ning/http/client/Response.java b/src/main/java/com/ning/http/client/Response.java index a4b98464b5..458e6ad254 100644 --- a/src/main/java/com/ning/http/client/Response.java +++ b/src/main/java/com/ning/http/client/Response.java @@ -203,7 +203,9 @@ public ResponseBuilder accumulate(HttpContent httpContent) { } else if (httpContent instanceof HttpResponseHeaders) { headers = (HttpResponseHeaders) httpContent; } else if (httpContent instanceof HttpResponseBodyPart) { - bodies.add((HttpResponseBodyPart) httpContent); + HttpResponseBodyPart part = (HttpResponseBodyPart) httpContent; + if (part.length() > 0) + bodies.add(part); } return this; } From 2deb5d55dc21352f190b4c9220a73a1c0e6e807f Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 24 Jan 2014 11:11:22 +0100 Subject: [PATCH 192/701] Fix NTLM regression, close #462 --- .../providers/netty/NettyAsyncHttpProvider.java | 12 ++++++++---- 1 file changed, 8 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 e5c93b0755..9ad2dcad64 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 @@ -1228,6 +1228,10 @@ private Realm kerberosChallenge(List proxyAuth, Request request, ProxySe return null; } } + + private void addNTLMAuthorization(FluentCaseInsensitiveStringsMap headers, String challengeHeader) { + headers.add(HttpHeaders.Names.AUTHORIZATION, "NTLM " + challengeHeader); + } private void addType3NTLMAuthorizationHeader( List auth, @@ -1238,11 +1242,11 @@ private void addType3NTLMAuthorizationHeader( String workstation) throws NTLMEngineException { headers.remove(HttpHeaders.Names.AUTHORIZATION); - if (isNTLM(auth)) { + // Beware of space!, see #462 + if (isNonEmpty(auth) && auth.get(0).startsWith("NTLM ")) { 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); + addNTLMAuthorization(headers, challengeHeader); } } @@ -1260,7 +1264,7 @@ private Realm ntlmChallenge(List wwwAuth, Request request, ProxyServer p String challengeHeader = ntlmEngine.generateType1Msg(ntlmDomain, ntlmHost); URI uri = request.getURI(); - headers.add(HttpHeaders.Names.AUTHORIZATION, "NTLM " + challengeHeader); + addNTLMAuthorization(headers, challengeHeader); newRealm = new Realm.RealmBuilder().clone(realm).setScheme(realm.getAuthScheme()).setUri(uri.getRawPath()).setMethodName(request.getMethod()).setNtlmMessageType2Received(true).build(); future.getAndSetAuth(false); } else { From 32b3ccb71b4dec8a832c1bd268ede26c9f5470a2 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 24 Jan 2014 11:34:39 +0100 Subject: [PATCH 193/701] Check if this is causing the test failure on Buildhive --- .../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 9ad2dcad64..833b1e07c1 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 @@ -2087,9 +2087,9 @@ public Object call() throws Exception { } }; - if (future.getKeepAlive()) { - future.setReuseChannel(true); - } +// if (future.getKeepAlive()) { +// future.setReuseChannel(true); +// } if (future.getKeepAlive() && response.isChunked()) { // We must make sure there is no bytes left before executing the next request. ctx.setAttachment(ac); From 97f5cd6ee2b44435b755ab3a8fbec8afb09835d5 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 24 Jan 2014 12:35:42 +0100 Subject: [PATCH 194/701] Revert race condition introduced in #420, close #463 --- .../http/client/providers/netty/NettyAsyncHttpProvider.java | 3 --- 1 file changed, 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 833b1e07c1..9a30e9acb3 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 @@ -2087,9 +2087,6 @@ public Object call() throws Exception { } }; -// if (future.getKeepAlive()) { -// future.setReuseChannel(true); -// } if (future.getKeepAlive() && response.isChunked()) { // We must make sure there is no bytes left before executing the next request. ctx.setAttachment(ac); From fb21db166ca0cf125a7a07525ff3b342afcc3b05 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 24 Jan 2014 15:50:29 +0100 Subject: [PATCH 195/701] 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 9a30e9acb3..77752b62b2 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 @@ -1751,7 +1751,7 @@ public void operationComplete(ChannelFuture cf) { * 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(); if (startPublishing && asyncHandler instanceof ProgressAsyncHandler) { if (notifyHeaders) { From e66b7ffcea8c22adec38c243546628e1ce0af024 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 24 Jan 2014 16:44:31 +0100 Subject: [PATCH 196/701] MultipartBody doesn't account for byte[] size when handling a ByteArrayPartSource, close #464 --- src/main/java/com/ning/http/multipart/MultipartBody.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/ning/http/multipart/MultipartBody.java b/src/main/java/com/ning/http/multipart/MultipartBody.java index e3bf3f4143..021ab71ba1 100644 --- a/src/main/java/com/ning/http/multipart/MultipartBody.java +++ b/src/main/java/com/ning/http/multipart/MultipartBody.java @@ -512,7 +512,7 @@ private long handlePartSource(WritableByteChannel target, FilePart filePart) thr if (nRead > 0) { ByteArrayOutputStream bos = new ByteArrayOutputStream(nRead); bos.write(bytes, 0, nRead); - writeToTarget(target, bos.toByteArray()); + length += writeToTarget(target, bos.toByteArray()); } } } finally { From 8978a541df387970b2989408e9a1281006aa4515 Mon Sep 17 00:00:00 2001 From: jfarcand Date: Fri, 24 Jan 2014 11:50:51 -0500 Subject: [PATCH 197/701] Since the Netty's Provider last chunk fixes change the behavior, next release will be 1.8.0 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 6272807848..d20cf4d8b9 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.7.25-SNAPSHOT + 1.8.0-SNAPSHOT jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From 21a0fdfa1b95506a5b6481610fcda8d9dd2359bb Mon Sep 17 00:00:00 2001 From: jfarcand Date: Fri, 24 Jan 2014 12:45:47 -0500 Subject: [PATCH 198/701] Improve fixed for #110. Also fixes #156 by properly invoking the AsyncHandler/WebSocketListener --- .../grizzly/GrizzlyAsyncHttpProvider.java | 7 +- .../netty/NettyAsyncHttpProvider.java | 194 +++++++++--------- .../websocket/CloseCodeReasonMessageTest.java | 40 ++++ 3 files changed, 147 insertions(+), 94 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 5d1d487c5b..990bedf5e3 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 @@ -1180,7 +1180,12 @@ protected void onInitialLineParsed(HttpHeader httpHeader, context.currentState = handler.onStatusReceived(responseStatus); if (context.isWSRequest && context.currentState == AsyncHandler.STATE.ABORT) { httpHeader.setSkipRemainder(true); - context.abort(new HandshakeException("Upgrade failed")); + try { + context.result(handler.onCompleted()); + context.done(); + } catch (Exception e) { + context.abort(e); + } } } } catch (Exception e) { 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 77752b62b2..66ecb3d5bf 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,53 @@ */ package com.ning.http.client.providers.netty; -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.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.List; -import java.util.Locale; -import java.util.Map.Entry; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.RejectedExecutionException; -import java.util.concurrent.Semaphore; -import java.util.concurrent.TimeUnit; -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.AsyncHandlerExtensions; +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.providers.netty.timeout.IdleConnectionTimeoutTimerTask; +import com.ning.http.client.providers.netty.timeout.RequestTimeoutTimerTask; +import com.ning.http.client.providers.netty.timeout.TimeoutsHolder; +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 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; @@ -108,53 +111,48 @@ 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.AsyncHandlerExtensions; -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.providers.netty.timeout.IdleConnectionTimeoutTimerTask; -import com.ning.http.client.providers.netty.timeout.RequestTimeoutTimerTask; -import com.ning.http.client.providers.netty.timeout.TimeoutsHolder; -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 com.ning.org.jboss.netty.handler.codec.http.CookieEncoder; +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.List; +import java.util.Locale; +import java.util.Map.Entry; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + +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.MiscUtil.isNonEmpty; +import static org.jboss.netty.channel.Channels.pipeline; public class NettyAsyncHttpProvider extends SimpleChannelUpstreamHandler implements AsyncHttpProvider { @@ -2279,8 +2277,17 @@ 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) { + try { + h.onCompleted(); + } finally { + future.done(); + } + return; + } + final boolean headerOK = h.onHeadersReceived(responseHeaders) == STATE.CONTINUE; - if (!headerOK || !validStatus || !validUpgrade || !validConnection || !statusReceived) { + if (!headerOK || !validStatus || !validUpgrade || !validConnection) { abort(future, new IOException("Invalid handshake response")); return; } @@ -2288,7 +2295,8 @@ 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(HttpHeaders.Names.SEC_WEBSOCKET_KEY)); if (accept == null || !accept.equals(key)) { - throw new IOException(String.format("Invalid challenge. Actual: %s. Expected: %s", accept, key)); + abort(future, new IOException(String.format("Invalid challenge. Actual: %s. Expected: %s", accept, key))); + return; } ctx.getPipeline().replace("http-encoder", "ws-encoder", new WebSocket08FrameEncoder(true)); 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 1dd7d952b7..412bc8392a 100644 --- a/src/test/java/com/ning/http/client/websocket/CloseCodeReasonMessageTest.java +++ b/src/test/java/com/ning/http/client/websocket/CloseCodeReasonMessageTest.java @@ -133,4 +133,44 @@ public void onError(Throwable t) { c.close(); } } + + @Test(timeOut = 60000) + public void wrongProtocolCode() throws Throwable { + AsyncHttpClient c = getAsyncHttpClient(null); + try { + final CountDownLatch latch = new CountDownLatch(1); + final AtomicReference throwable = new AtomicReference(); + + WebSocket websocket = c.prepareGet("ws://www.google.com/").execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(new WebSocketTextListener() { + + @Override + public void onMessage(String message) { + } + + @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) { + } + + @Override + public void onError(Throwable t) { + throwable.set(t); + latch.countDown(); + } + }).build()).get(); + + latch.await(); + assertNotNull(throwable.get()); + assertEquals(throwable.get().getClass(), IllegalStateException.class); + } finally { + c.close(); + } + } } From 1325729b7cdb5e3a1dd44c2c049f30c2268b5e9b Mon Sep 17 00:00:00 2001 From: jfarcand Date: Fri, 24 Jan 2014 16:26:20 -0500 Subject: [PATCH 199/701] Fixes #301 --- .../providers/netty/NettyWebSocket.java | 108 +++++++++++------- 1 file changed, 65 insertions(+), 43 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 b9d96249d8..84bd9c45ed 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 @@ -38,8 +38,9 @@ public class NettyWebSocket implements WebSocket { private final Channel channel; private final ConcurrentLinkedQueue listeners = new ConcurrentLinkedQueue(); - private StringBuilder textBuffer; - private ByteArrayOutputStream byteBuffer; + private final StringBuilder textBuffer = new StringBuilder(); + private final ByteArrayOutputStream byteBuffer = new ByteArrayOutputStream(); + private int maxBufferSize = 128000000; public NettyWebSocket(Channel channel) { @@ -129,66 +130,87 @@ public void close(int statusCode, String reason) { } protected void onBinaryFragment(byte[] message, boolean last) { + + if (!last) { + try { + byteBuffer.write(message); + } catch (Exception ex) { + byteBuffer.reset(); + onError(ex); + return; + } + + if (byteBuffer.size() > maxBufferSize) { + byteBuffer.reset(); + Exception e = new Exception("Exceeded Netty Web Socket maximum buffer size of " + getMaxBufferSize()); + onError(e); + this.close(); + return; + } + } + for (WebSocketListener l : listeners) { if (l instanceof WebSocketByteListener) { try { - 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; - } + if (!last) { + WebSocketByteListener.class.cast(l).onFragment(message, last); + } else { + if (byteBuffer.size() > 0) { + byteBuffer.write(message); + WebSocketByteListener.class.cast(l).onFragment(message, last); + WebSocketByteListener.class.cast(l).onMessage(byteBuffer.toByteArray()); + } else { + WebSocketByteListener.class.cast(l).onMessage(message); + } + } } catch (Exception ex) { l.onError(ex); } } } + + if (last) { + byteBuffer.reset(); + } } protected void onTextFragment(String message, boolean last) { + + if (!last) { + textBuffer.append(message); + + if (textBuffer.length() > maxBufferSize) { + textBuffer.setLength(0); + Exception e = new Exception("Exceeded Netty Web Socket maximum buffer size of " + getMaxBufferSize()); + onError(e); + this.close(); + return; + } + } + for (WebSocketListener l : listeners) { if (l instanceof WebSocketTextListener) { try { - 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; - } + if (!last) { + WebSocketTextListener.class.cast(l).onFragment(message, last); + } else { + if (textBuffer.length() > 0) { + WebSocketTextListener.class.cast(l).onFragment(message, last); + + WebSocketTextListener.class.cast(l).onMessage(textBuffer.append(message).toString()); + } else { + WebSocketTextListener.class.cast(l).onMessage(message); + } + } } catch (Exception ex) { l.onError(ex); } } } + + if (last) { + textBuffer.setLength(0); + } } protected void onError(Throwable t) { From 31a721d5ece388d80366b8f6144d1fbefedca354 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Sat, 25 Jan 2014 15:55:54 +0100 Subject: [PATCH 200/701] Minor clean up, make file and body handling symmetric --- .../netty/NettyAsyncHttpProvider.java | 20 ++++++++----------- 1 file changed, 8 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 66ecb3d5bf..6c296448b4 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 @@ -535,17 +535,14 @@ protected final void writeRequest(final Channel channel, final AsyncHttpClie if (future.getRequest().getFile() != null) { final File file = future.getRequest().getFile(); - long fileLength = 0; final RandomAccessFile raf = new RandomAccessFile(file, "r"); try { - fileLength = raf.length(); - ChannelFuture writeFuture; - if (ssl || disableZeroCopy) { - writeFuture = channel.write(new ChunkedFile(raf, 0, fileLength, MAX_BUFFERED_BYTES)); + if (disableZeroCopy || ssl) { + writeFuture = channel.write(new ChunkedFile(raf, 0, raf.length(), MAX_BUFFERED_BYTES)); } else { - final FileRegion region = new OptimizedFileRegion(raf, 0, fileLength); + final FileRegion region = new OptimizedFileRegion(raf, 0, raf.length()); writeFuture = channel.write(region); } writeFuture.addListener(new ProgressListener(false, future.getAsyncHandler(), future) { @@ -568,17 +565,16 @@ public void operationComplete(ChannelFuture cf) { throw ex; } } else if (body != null) { + final Body b = body; ChannelFuture writeFuture; - if (!ssl && !disableZeroCopy && body instanceof RandomAccessBody) { - BodyFileRegion bodyFileRegion = new BodyFileRegion((RandomAccessBody) body); - writeFuture = channel.write(bodyFileRegion); - } else { + if (disableZeroCopy || ssl || !(body instanceof RandomAccessBody)) { BodyChunkedInput bodyChunkedInput = new BodyChunkedInput(body); writeFuture = channel.write(bodyChunkedInput); + } else { + BodyFileRegion bodyFileRegion = new BodyFileRegion((RandomAccessBody) body); + writeFuture = channel.write(bodyFileRegion); } - - final Body b = body; writeFuture.addListener(new ProgressListener(false, future.getAsyncHandler(), future) { public void operationComplete(ChannelFuture cf) { try { From 0d5e592ff1fab85f8af965667ad22456256aaf8e Mon Sep 17 00:00:00 2001 From: Ryan Lubke Date: Sun, 26 Jan 2014 17:53:02 -0800 Subject: [PATCH 201/701] Improve Grizzly's copy of the testMaxTotalConnectionsException test. Original copied test logic relied on timing for the failure to occur. New logic uses two requests - one to use the connection and wait, and the second to ensure the connection pool throws an exception because we have a max connection limit of one. --- .../grizzly/GrizzlyConnectionPoolTest.java | 31 ++++++++++--------- 1 file changed, 16 insertions(+), 15 deletions(-) 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 ee057a150f..250bf43919 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 @@ -17,8 +17,10 @@ import static org.testng.Assert.assertNotNull; import static org.testng.Assert.fail; +import java.io.IOException; import java.util.concurrent.TimeUnit; +import com.ning.http.client.ListenableFuture; import org.testng.annotations.Test; import com.ning.http.client.AsyncHttpClient; @@ -42,22 +44,21 @@ public void testMaxTotalConnectionsException() { 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; - } + ListenableFuture lockRequest = null; + try { + lockRequest = client.prepareGet(url).addHeader("LockThread", "true").execute(); + } catch (Exception e) { + fail("Unexpected exception thrown.", e); } - assertNotNull(exception); - assertNotNull(exception.getMessage()); + try { + client.prepareConnect(url).execute().get(); + } catch (IOException ioe) { + assertNotNull(ioe); + assertEquals("Max connections exceeded", ioe.getMessage()); + } catch (Exception e) { + fail("Unexpected exception thrown.", e); + } + lockRequest.cancel(true); } finally { client.close(); } From 9c964835e9372d6bacc4d3af3913fa428ecbd0fa Mon Sep 17 00:00:00 2001 From: Ryan Lubke Date: Sun, 26 Jan 2014 17:56:16 -0800 Subject: [PATCH 202/701] Minor cleanup. --- .../http/client/async/grizzly/GrizzlyConnectionPoolTest.java | 2 -- 1 file changed, 2 deletions(-) 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 250bf43919..0d7216258e 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 @@ -42,8 +42,6 @@ public void testMaxTotalConnectionsException() { AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setAllowPoolingConnection(true).setMaximumConnectionsTotal(1).build()); try { String url = getTargetUrl(); - int i; - Exception exception = null; ListenableFuture lockRequest = null; try { lockRequest = client.prepareGet(url).addHeader("LockThread", "true").execute(); From 8877ef4c16094a42957c412cdd67779b0aebfbc7 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 27 Jan 2014 09:20:15 +0100 Subject: [PATCH 203/701] Close Scanner/File in PropertiesBasedResumableProcessor.load, close #467 --- .../client/resumable/PropertiesBasedResumableProcessor.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) 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 d6ed2fc43b..c9ae94af6e 100644 --- a/src/main/java/com/ning/http/client/resumable/PropertiesBasedResumableProcessor.java +++ b/src/main/java/com/ning/http/client/resumable/PropertiesBasedResumableProcessor.java @@ -98,8 +98,9 @@ private static String append(Map.Entry e) { */ /* @Override */ public Map load() { + Scanner scan = null; try { - Scanner scan = new Scanner(new File(TMP, storeName), "UTF-8"); + scan = new Scanner(new File(TMP, storeName), "UTF-8"); scan.useDelimiter("[=\n]"); String key; @@ -115,6 +116,9 @@ public Map load() { } catch (Throwable ex) { // Survive any exceptions log.warn(ex.getMessage(), ex); + } finally { + if (scan != null) + scan.close(); } return properties; } From d49b86d48b1845d55b4d22bcdea5bd50465e88f2 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 29 Jan 2014 14:59:45 +0100 Subject: [PATCH 204/701] Don't enable idleConnectionTimeout when it's equal to requestTimeoutInMs --- .../http/client/providers/netty/NettyAsyncHttpProvider.java | 3 ++- .../ning/http/client/providers/netty/NettyResponseFuture.java | 3 +-- 2 files 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 6c296448b4..c278f60e3b 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 @@ -606,7 +606,7 @@ public void operationComplete(ChannelFuture cf) { } int idleConnectionTimeoutInMs = config.getIdleConnectionTimeoutInMs(); - if (idleConnectionTimeoutInMs != -1 && idleConnectionTimeoutInMs < requestTimeoutInMs) { + if (idleConnectionTimeoutInMs != -1 && idleConnectionTimeoutInMs <= requestTimeoutInMs) { // no need for a idleConnectionTimeout that's less than the requestTimeoutInMs Timeout idleConnectionTimeout = newTimeoutInMs(new IdleConnectionTimeoutTimerTask(future, this, timeoutsHolder, requestTimeoutInMs, idleConnectionTimeoutInMs), idleConnectionTimeoutInMs); @@ -1496,6 +1496,7 @@ private void markAsDone(final NettyResponseFuture future, final ChannelHandle log.debug(t.getMessage(), t); } + // FIXME why isReadable and not isConnected if (!future.getKeepAlive() || !ctx.getChannel().isReadable()) { closeChannel(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 aca137ee90..c5b4422f25 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 @@ -307,10 +307,9 @@ V getContent() throws ExecutionException { } public final void done() { + cancelTimeouts(); try { - cancelTimeouts(); - if (exEx.get() != null) { return; } From 9b0bf68f966e10d2391c6b6b66895514943fdb51 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 29 Jan 2014 16:44:41 +0100 Subject: [PATCH 205/701] Timeouts weren't properly registered on the ResponseFuture --- .../http/client/providers/netty/NettyAsyncHttpProvider.java | 1 + .../ning/http/client/providers/netty/NettyResponseFuture.java | 4 ++++ 2 files changed, 5 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 c278f60e3b..ed73bf9a3a 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 @@ -612,6 +612,7 @@ public void operationComplete(ChannelFuture cf) { requestTimeoutInMs, idleConnectionTimeoutInMs), idleConnectionTimeoutInMs); timeoutsHolder.idleConnectionTimeout = idleConnectionTimeout; } + future.setTimeoutsHolder(timeoutsHolder); } catch (RejectedExecutionException ex) { abort(future, ex); 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 c5b4422f25..00a3132fa0 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 @@ -210,6 +210,10 @@ public boolean isIdleConnectionTimeoutReached() { return idleConnectionTimeoutReached; } + public void setTimeoutsHolder(TimeoutsHolder timeoutsHolder) { + this.timeoutsHolder = timeoutsHolder; + } + /** * {@inheritDoc} */ From 2d6db79de3a6f9a244332efe822f8a092e09a6d4 Mon Sep 17 00:00:00 2001 From: jfarcand Date: Wed, 29 Jan 2014 18:43:45 -0500 Subject: [PATCH 206/701] Improve robusness --- .../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 ed73bf9a3a..8c5cab50b6 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 @@ -2402,7 +2402,8 @@ public void onClose(ChannelHandlerContext ctx, ChannelStateEvent e) { NettyWebSocket webSocket = NettyWebSocket.class.cast(h.onCompleted()); h.resetSuccess(); - if (!(ctx.getAttachment() instanceof DiscardEvent)) + log.trace("Connection was closed abnormally (that is, with no close frame being sent)."); + if (!(ctx.getAttachment() instanceof DiscardEvent) && webSocket != null) webSocket.close(1006, "Connection was closed abnormally (that is, with no close frame being sent)."); } catch (Throwable t) { log.error("onError", t); From e8176296df0d701f103a88a878d42020968a203f Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 30 Jan 2014 11:38:54 +0100 Subject: [PATCH 207/701] Backport 92c1822c73b1acd08c0d80fa0efd32604e2ee7c0 and 802cf250348a51e96eafe0eaf07dd25005cbd891 --- .../netty/NettyAsyncHttpProvider.java | 284 ++++++++++-------- .../netty/NettyAsyncHttpProviderConfig.java | 46 ++- .../providers/netty/NettyConnectionsPool.java | 92 +++--- 3 files changed, 234 insertions(+), 188 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 8c5cab50b6..d150ba0c79 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,53 +15,50 @@ */ package com.ning.http.client.providers.netty; -import com.ning.http.client.AsyncHandler; -import com.ning.http.client.AsyncHandler.STATE; -import com.ning.http.client.AsyncHandlerExtensions; -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.providers.netty.timeout.IdleConnectionTimeoutTimerTask; -import com.ning.http.client.providers.netty.timeout.RequestTimeoutTimerTask; -import com.ning.http.client.providers.netty.timeout.TimeoutsHolder; -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 com.ning.org.jboss.netty.handler.codec.http.CookieEncoder; +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.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.List; +import java.util.Locale; +import java.util.Map.Entry; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.net.ssl.SSLEngine; + import org.jboss.netty.bootstrap.ClientBootstrap; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBufferOutputStream; @@ -111,48 +108,53 @@ 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.List; -import java.util.Locale; -import java.util.Map.Entry; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.RejectedExecutionException; -import java.util.concurrent.Semaphore; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; - -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.MiscUtil.isNonEmpty; -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.AsyncHandlerExtensions; +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.providers.netty.timeout.IdleConnectionTimeoutTimerTask; +import com.ning.http.client.providers.netty.timeout.RequestTimeoutTimerTask; +import com.ning.http.client.providers.netty.timeout.TimeoutsHolder; +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 com.ning.org.jboss.netty.handler.codec.http.CookieEncoder; public class NettyAsyncHttpProvider extends SimpleChannelUpstreamHandler implements AsyncHttpProvider { @@ -210,6 +212,7 @@ public boolean remove(Object o) { private static SpnegoEngine spnegoEngine = null; private final Protocol httpProtocol = new HttpProtocol(); private final Protocol webSocketProtocol = new WebSocketProtocol(); + private final boolean allowStopHashedWheelTimer; private final HashedWheelTimer hashedWheelTimer; private static boolean isNTLM(List auth) { @@ -230,15 +233,15 @@ public NettyAsyncHttpProvider(AsyncHttpClientConfig config) { if (providerConfig.getProperty(USE_BLOCKING_IO) != null) { socketChannelFactory = new OioClientSocketChannelFactory(config.executorService()); - this.allowReleaseSocketChannelFactory = true; + allowReleaseSocketChannelFactory = true; } else { // check if external NioClientSocketChannelFactory is defined Object oo = providerConfig.getProperty(SOCKET_CHANNEL_FACTORY); if (oo instanceof NioClientSocketChannelFactory) { - this.socketChannelFactory = NioClientSocketChannelFactory.class.cast(oo); + socketChannelFactory = NioClientSocketChannelFactory.class.cast(oo); // cannot allow releasing shared channel factory - this.allowReleaseSocketChannelFactory = false; + allowReleaseSocketChannelFactory = false; } else { ExecutorService e; Object o = providerConfig.getProperty(BOSS_EXECUTOR_SERVICE); @@ -250,9 +253,14 @@ public NettyAsyncHttpProvider(AsyncHttpClientConfig config) { 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; + allowReleaseSocketChannelFactory = true; } } + + allowStopHashedWheelTimer = providerConfig.getHashedWheelTimer() == null; + hashedWheelTimer = allowStopHashedWheelTimer ? new HashedWheelTimer() : providerConfig.getHashedWheelTimer(); + hashedWheelTimer.start(); + plainBootstrap = new ClientBootstrap(socketChannelFactory); secureBootstrap = new ClientBootstrap(socketChannelFactory); webSocketBootstrap = new ClientBootstrap(socketChannelFactory); @@ -264,7 +272,7 @@ public NettyAsyncHttpProvider(AsyncHttpClientConfig config) { // This is dangerous as we can't catch a wrong typed ConnectionsPool ConnectionsPool cp = (ConnectionsPool) config.getConnectionsPool(); if (cp == null && config.getAllowPoolingConnection()) { - cp = new NettyConnectionsPool(this); + cp = new NettyConnectionsPool(this, hashedWheelTimer); } else if (cp == null) { cp = new NonConnectionsPool(); } @@ -279,8 +287,6 @@ public NettyAsyncHttpProvider(AsyncHttpClientConfig config) { useRawUrl = config.isUseRawUrl(); disableZeroCopy = providerConfig.isDisableZeroCopy(); - hashedWheelTimer = new HashedWheelTimer(); - hashedWheelTimer.start(); } @Override @@ -509,7 +515,8 @@ protected final void writeRequest(final Channel channel, final AsyncHttpClie } } - 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. @@ -608,9 +615,9 @@ public void operationComplete(ChannelFuture cf) { int idleConnectionTimeoutInMs = config.getIdleConnectionTimeoutInMs(); if (idleConnectionTimeoutInMs != -1 && idleConnectionTimeoutInMs <= requestTimeoutInMs) { // no need for a idleConnectionTimeout that's less than the requestTimeoutInMs - Timeout idleConnectionTimeout = newTimeoutInMs(new IdleConnectionTimeoutTimerTask(future, this, timeoutsHolder, - requestTimeoutInMs, idleConnectionTimeoutInMs), idleConnectionTimeoutInMs); - timeoutsHolder.idleConnectionTimeout = idleConnectionTimeout; + Timeout idleConnectionTimeout = newTimeoutInMs(new IdleConnectionTimeoutTimerTask(future, this, timeoutsHolder, requestTimeoutInMs, idleConnectionTimeoutInMs), + idleConnectionTimeoutInMs); + timeoutsHolder.idleConnectionTimeout = idleConnectionTimeout; } future.setTimeoutsHolder(timeoutsHolder); @@ -619,7 +626,8 @@ 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)) { @@ -884,7 +892,7 @@ public void close() { } config.executorService().shutdown(); - if (this.allowReleaseSocketChannelFactory) { + if (allowReleaseSocketChannelFactory) { socketChannelFactory.releaseExternalResources(); plainBootstrap.releaseExternalResources(); secureBootstrap.releaseExternalResources(); @@ -892,7 +900,8 @@ public void close() { secureWebSocketBootstrap.releaseExternalResources(); } - hashedWheelTimer.stop(); + if (allowStopHashedWheelTimer) + hashedWheelTimer.stop(); } catch (Throwable t) { log.warn("Unexpected error on close", t); @@ -957,8 +966,9 @@ private NettyResponseFuture buildNettyResponseFutureWithCachedChannel(Req } return null; } - - 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()) { throw new IOException("Closed"); @@ -990,7 +1000,7 @@ private ListenableFuture doConnect(final Request request, final AsyncHand if (connectedFuture != null) { log.debug("\nUsing cached Channel {}\n for request \n{}\n", connectedFuture.channel(), connectedFuture.getNettyRequest()); - + try { writeRequest(connectedFuture.channel(), config, connectedFuture); } catch (Exception ex) { @@ -1198,7 +1208,8 @@ 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(); @@ -1223,18 +1234,13 @@ private Realm kerberosChallenge(List proxyAuth, Request request, ProxySe return null; } } - + private void addNTLMAuthorization(FluentCaseInsensitiveStringsMap headers, String challengeHeader) { headers.add(HttpHeaders.Names.AUTHORIZATION, "NTLM " + challengeHeader); } - private void addType3NTLMAuthorizationHeader( - List auth, - FluentCaseInsensitiveStringsMap headers, - String username, - String password, - String domain, - String workstation) throws NTLMEngineException { + private void addType3NTLMAuthorizationHeader(List auth, FluentCaseInsensitiveStringsMap headers, String username, String password, String domain, String workstation) + throws NTLMEngineException { headers.remove(HttpHeaders.Names.AUTHORIZATION); // Beware of space!, see #462 @@ -1245,7 +1251,8 @@ private void addType3NTLMAuthorizationHeader( } } - 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); @@ -1260,7 +1267,8 @@ private Realm ntlmChallenge(List wwwAuth, Request request, ProxyServer p URI uri = request.getURI(); addNTLMAuthorization(headers, 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 { addType3NTLMAuthorizationHeader(wwwAuth, headers, principal, password, ntlmDomain, ntlmHost); @@ -1280,12 +1288,13 @@ private Realm ntlmChallenge(List wwwAuth, Request request, ProxyServer p 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); - + addType3NTLMAuthorizationHeader(wwwAuth, headers, proxyServer.getPrincipal(), proxyServer.getPassword(), proxyServer.getNtlmDomain(), proxyServer.getHost()); Realm newRealm; - + Realm.RealmBuilder realmBuilder = new Realm.RealmBuilder(); if (realm != null) { realmBuilder = realmBuilder.clone(realm); @@ -1296,11 +1305,11 @@ private Realm ntlmProxyChallenge(List wwwAuth, Request request, ProxySer } private String getPoolKey(NettyResponseFuture future) { - + String serverPart = future.getConnectionPoolKeyStrategy().getKey(future.getURI()); ProxyServer proxy = future.getProxyServer(); - return proxy != null? AsyncHttpProviderUtils.getBaseUrl(proxy.getURI()) + serverPart : serverPart; + return proxy != null ? AsyncHttpProviderUtils.getBaseUrl(proxy.getURI()) + serverPart : serverPart; } private void drainChannel(final ChannelHandlerContext ctx, final NettyResponseFuture future) { @@ -1429,7 +1438,8 @@ public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws future.touch(); if (!config.getIOExceptionFilters().isEmpty()) { - 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()) { @@ -1568,7 +1578,8 @@ public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws 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(); + FilterContext fc = new FilterContext.FilterContextBuilder().asyncHandler(future.getAsyncHandler()).request(future.getRequest()) + .ioException(new IOException("Channel Closed")).build(); fc = handleIoException(fc, future); if (fc.replayRequest()) { @@ -1677,7 +1688,8 @@ protected static boolean abortOnWriteCloseException(Throwable cause) { return false; } - 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,// @@ -1744,7 +1756,8 @@ 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(); @@ -2020,7 +2033,8 @@ 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 { @@ -2069,7 +2083,8 @@ public void handle(final ChannelHandlerContext ctx, final MessageEvent e) throws } 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(); @@ -2170,9 +2185,11 @@ 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()); } @@ -2180,7 +2197,8 @@ public Object call() throws Exception { } } catch (Exception t) { if (t instanceof IOException && !config.getIOExceptionFilters().isEmpty()) { - 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()) { @@ -2410,11 +2428,11 @@ public void onClose(ChannelHandlerContext ctx, ChannelStateEvent e) { } } } - + public boolean isClose() { return isClose.get(); } - + public Timeout newTimeoutInMs(TimerTask task, long delayInMs) { return hashedWheelTimer.newTimeout(task, delayInMs, TimeUnit.MILLISECONDS); } 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 f11bf07af6..748900b95e 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 @@ -16,12 +16,14 @@ */ package com.ning.http.client.providers.netty; -import com.ning.http.client.AsyncHttpProviderConfig; - import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; +import org.jboss.netty.util.HashedWheelTimer; + +import com.ning.http.client.AsyncHttpProviderConfig; + /** * This class can be used to pass Netty's internal configuration options. See Netty documentation for more information. */ @@ -59,7 +61,7 @@ public class NettyAsyncHttpProviderConfig implements AsyncHttpProviderConfig 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; + 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 - * + * * @param name * @return true if removed */ @@ -135,7 +141,7 @@ public Object removeProperty(String name) { /** * Return the curent entry set. - * + * * @return a the curent entry set. */ public Set> propertiesSet() { @@ -149,4 +155,12 @@ public void setDisableZeroCopy(boolean disableZeroCopy) { public boolean isDisableZeroCopy() { return disableZeroCopy; } -} \ No newline at end of file + + public HashedWheelTimer getHashedWheelTimer() { + return hashedWheelTimer; + } + + public void setHashedWheelTimer(HashedWheelTimer hashedWheelTimer) { + this.hashedWheelTimer = hashedWheelTimer; + } +} 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 08acb0bf02..a5b07c1d23 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 @@ -14,20 +14,23 @@ import static com.ning.http.util.DateUtil.millisTime; -import com.ning.http.client.ConnectionsPool; -import org.jboss.netty.channel.Channel; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import java.util.ArrayList; import java.util.List; import java.util.Set; -import java.util.Timer; -import java.util.TimerTask; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; +import org.jboss.netty.channel.Channel; +import org.jboss.netty.util.HashedWheelTimer; +import org.jboss.netty.util.Timeout; +import org.jboss.netty.util.TimerTask; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.ning.http.client.ConnectionsPool; + /** * A simple implementation of {@link com.ning.http.client.ConnectionsPool} based on a {@link java.util.concurrent.ConcurrentHashMap} */ @@ -38,30 +41,35 @@ 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; + private final HashedWheelTimer hashedWheelTimer; 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().getMaxConnectionLifeTimeInMs(),// - provider.getConfig().isSslConnectionPoolEnabled(),// - new Timer(true)); + public NettyConnectionsPool(NettyAsyncHttpProvider provider, HashedWheelTimer hashedWheelTimer) { + this(provider.getConfig().getMaxTotalConnections(),// + provider.getConfig().getMaxConnectionPerHost(),// + provider.getConfig().getIdleConnectionInPoolTimeoutInMs(),// + provider.getConfig().getMaxConnectionLifeTimeInMs(),// + provider.getConfig().isSslConnectionPoolEnabled(),// + hashedWheelTimer); } - public NettyConnectionsPool(int maxTotalConnections, int maxConnectionPerHost, long maxIdleTime, int maxConnectionLifeTimeInMs, boolean sslConnectionPoolEnabled, Timer idleConnectionDetector) { + public NettyConnectionsPool(int maxTotalConnections, int maxConnectionPerHost, long maxIdleTime, int maxConnectionLifeTimeInMs, boolean sslConnectionPoolEnabled, + HashedWheelTimer hashedWheelTimer) { this.maxTotalConnections = maxTotalConnections; this.maxConnectionPerHost = maxConnectionPerHost; this.sslConnectionPoolEnabled = sslConnectionPoolEnabled; this.maxIdleTime = maxIdleTime; this.maxConnectionLifeTimeInMs = maxConnectionLifeTimeInMs; - this.idleConnectionDetector = idleConnectionDetector; - this.idleConnectionDetector.schedule(new IdleChannelDetector(), maxIdleTime, maxIdleTime); + this.hashedWheelTimer = hashedWheelTimer; + scheduleNewIdleChannelDetector(new IdleChannelDetector()); + } + + private void scheduleNewIdleChannelDetector(TimerTask task) { + this.hashedWheelTimer.newTimeout(task, maxIdleTime, TimeUnit.MILLISECONDS); } private static class IdleChannel { @@ -77,12 +85,15 @@ private static class IdleChannel { @Override public boolean equals(Object o) { - if (this == o) return true; - if (!(o instanceof IdleChannel)) return false; + if (this == o) + return true; + if (!(o instanceof IdleChannel)) + return false; IdleChannel that = (IdleChannel) o; - if (channel != null ? !channel.equals(that.channel) : that.channel != null) return false; + if (channel != null ? !channel.equals(that.channel) : that.channel != null) + return false; return true; } @@ -93,11 +104,12 @@ public int hashCode() { } } - private class IdleChannelDetector extends TimerTask { - @Override - public void run() { + private class IdleChannelDetector implements TimerTask { + + public void run(Timeout timeout) throws Exception { try { - if (isClosed.get()) return; + if (isClosed.get()) + return; if (log.isDebugEnabled()) { Set keys = connectionsPool.keySet(); @@ -141,16 +153,18 @@ public void run() { if (log.isTraceEnabled()) { int openChannels = 0; - for (ConcurrentLinkedQueue hostChannels: connectionsPool.values()) { + 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, millisTime() - endConcurrentLoop)); + log.trace(String.format("%d channel open, %d idle channels closed (times: 1st-loop=%d, 2nd-loop=%d).\n", openChannels, channelsInTimeout.size(), + endConcurrentLoop - currentTime, millisTime() - endConcurrentLoop)); } } catch (Throwable t) { log.error("uncaught exception!", t); } + + scheduleNewIdleChannelDetector(timeout.getTask()); } } @@ -158,7 +172,8 @@ public void run() { * {@inheritDoc} */ public boolean offer(String uri, Channel channel) { - if (isClosed.get()) return false; + if (isClosed.get()) + return false; if (!sslConnectionPoolEnabled && uri.startsWith("https")) { return false; @@ -166,10 +181,10 @@ public boolean offer(String uri, Channel channel) { Long createTime = channel2CreationDate.get(channel); if (createTime == null) { - channel2CreationDate.putIfAbsent(channel, millisTime()); + channel2CreationDate.putIfAbsent(channel, millisTime()); } else if (maxConnectionLifeTimeInMs != -1 && (createTime + maxConnectionLifeTimeInMs) < millisTime()) { - log.debug("Channel {} expired", channel); - return false; + log.debug("Channel {} expired", channel); + return false; } log.debug("Adding uri: {} for channel {}", uri, channel); @@ -179,7 +194,8 @@ public boolean offer(String uri, Channel channel) { if (idleConnectionForHost == null) { ConcurrentLinkedQueue newPool = new ConcurrentLinkedQueue(); idleConnectionForHost = connectionsPool.putIfAbsent(uri, newPool); - if (idleConnectionForHost == null) idleConnectionForHost = newPool; + if (idleConnectionForHost == null) + idleConnectionForHost = newPool; } boolean added; @@ -234,7 +250,8 @@ public Channel poll(String uri) { } private boolean remove(IdleChannel pooledChannel) { - if (pooledChannel == null || isClosed.get()) return false; + if (pooledChannel == null || isClosed.get()) + return false; boolean isRemoved = false; ConcurrentLinkedQueue pooledConnectionForHost = connectionsPool.get(pooledChannel.uri); @@ -268,11 +285,8 @@ public boolean canCacheConnection() { * {@inheritDoc} */ public void destroy() { - if (isClosed.getAndSet(true)) return; - - // stop timer - idleConnectionDetector.cancel(); - idleConnectionDetector.purge(); + if (isClosed.getAndSet(true)) + return; for (Channel channel : channel2IdleChannel.keySet()) { close(channel); From 8c7e3108fc51dfbf14953597428f02361268bb2f Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 30 Jan 2014 17:17:21 +0100 Subject: [PATCH 208/701] minor clean up --- .../com/ning/http/client/providers/netty/ResponseBodyPart.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 5abdf8546c..6a914d1bf0 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 @@ -60,7 +60,7 @@ public byte[] getBodyPartBytes() { return bytes.get(); } - byte[] b = ChannelBufferUtil.channelBuffer2bytes(getChannelBuffer()); + byte[] b = ChannelBufferUtil.channelBuffer2bytes(content); bytes.set(b); return b; } From aed562bb8230c0ce18308fde77d350f84f7c5b99 Mon Sep 17 00:00:00 2001 From: jfarcand Date: Thu, 30 Jan 2014 14:43:44 -0500 Subject: [PATCH 209/701] Fixes #131 --- .../netty/NettyAsyncHttpProvider.java | 48 +++++++++++-------- 1 file changed, 27 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 d150ba0c79..4b48850b91 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 @@ -89,9 +89,7 @@ import org.jboss.netty.handler.codec.http.HttpHeaders; import org.jboss.netty.handler.codec.http.HttpMethod; import org.jboss.netty.handler.codec.http.HttpRequest; -import org.jboss.netty.handler.codec.http.HttpRequestEncoder; 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; @@ -166,8 +164,11 @@ public class NettyAsyncHttpProvider extends SimpleChannelUpstreamHandler impleme static { REMOTELY_CLOSED_EXCEPTION.setStackTrace(new StackTraceElement[0]); } - private final static String HTTP_HANDLER = "httpHandler"; - protected final static String SSL_HANDLER = "sslHandler"; + public final static String HTTP_HANDLER = "httpHandler"; + public final static String SSL_HANDLER = "sslHandler"; + public final static String HTTP_PROCESSOR = "httpProcessor"; + public final static String WS_PROCESSOR = "wsProcessor"; + private final static String HTTPS = "https"; private final static String HTTP = "http"; private static final String WEBSOCKET = "ws"; @@ -318,7 +319,7 @@ public ChannelPipeline getPipeline() throws Exception { pipeline.addLast("inflater", new HttpContentDecompressor()); } pipeline.addLast("chunkedWriter", new ChunkedWriteHandler()); - pipeline.addLast("httpProcessor", NettyAsyncHttpProvider.this); + pipeline.addLast(HTTP_PROCESSOR, NettyAsyncHttpProvider.this); return pipeline; } }); @@ -338,9 +339,8 @@ public ChannelPipeline getPipeline() throws Exception { /* @Override */ public ChannelPipeline getPipeline() throws Exception { ChannelPipeline pipeline = pipeline(); - pipeline.addLast("http-decoder", new HttpResponseDecoder()); - pipeline.addLast("http-encoder", new HttpRequestEncoder()); - pipeline.addLast("httpProcessor", NettyAsyncHttpProvider.this); + pipeline.addLast(HTTP_HANDLER, createHttpClientCodec()); + pipeline.addLast(WS_PROCESSOR, NettyAsyncHttpProvider.this); return pipeline; } }); @@ -378,7 +378,7 @@ public ChannelPipeline getPipeline() throws Exception { pipeline.addLast("inflater", new HttpContentDecompressor()); } pipeline.addLast("chunkedWriter", new ChunkedWriteHandler()); - pipeline.addLast("httpProcessor", NettyAsyncHttpProvider.this); + pipeline.addLast(HTTP_PROCESSOR, NettyAsyncHttpProvider.this); return pipeline; } }); @@ -395,9 +395,8 @@ public ChannelPipeline getPipeline() throws Exception { abort(cl.future(), ex); } - pipeline.addLast("http-decoder", new HttpResponseDecoder()); - pipeline.addLast("http-encoder", new HttpRequestEncoder()); - pipeline.addLast("httpProcessor", NettyAsyncHttpProvider.this); + pipeline.addLast(HTTP_HANDLER, createHttpsClientCodec()); + pipeline.addLast(WS_PROCESSOR, NettyAsyncHttpProvider.this); return pipeline; } @@ -665,8 +664,8 @@ else if (uri.getRawQuery() != null) path = uri.getRawPath(); nettyRequest = new DefaultHttpRequest(HttpVersion.HTTP_1_1, m, path); } - boolean webSocket = isWebSocket(uri); - if (webSocket) { + boolean webSocket = isWebSocket(uri.getScheme()); + if (!m.equals(HttpMethod.CONNECT) && webSocket) { 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()); @@ -979,7 +978,9 @@ private ListenableFuture doConnect(final Request request, final AsyncHand } ProxyServer proxyServer = ProxyUtils.getProxyServer(config, request); - boolean useProxy = proxyServer != null; + + boolean resultOfAConnect = f != null && f.getNettyRequest() != null && f.getNettyRequest().getMethod().equals(HttpMethod.CONNECT); + boolean useProxy = proxyServer != null && !resultOfAConnect; URI uri; if (useRawUrl) { @@ -1059,7 +1060,8 @@ private ListenableFuture doConnect(final Request request, final AsyncHand } ChannelFuture channelFuture; - ClientBootstrap bootstrap = request.getUrl().startsWith(WEBSOCKET) ? (useSSl ? secureWebSocketBootstrap : webSocketBootstrap) : (useSSl ? secureBootstrap : plainBootstrap); + ClientBootstrap bootstrap = (request.getUrl().startsWith(WEBSOCKET) && !useProxy) ? + (useSSl ? secureWebSocketBootstrap : webSocketBootstrap) : (useSSl ? secureBootstrap : plainBootstrap); bootstrap.setOption("connectTimeoutMillis", config.getConnectionTimeoutInMs()); // Do no enable this with win. @@ -1204,7 +1206,7 @@ public void messageReceived(final ChannelHandlerContext ctx, MessageEvent e) thr return; } - Protocol p = (ctx.getPipeline().get(HttpClientCodec.class) != null ? httpProtocol : webSocketProtocol); + Protocol p = (ctx.getPipeline().get(HTTP_PROCESSOR) != null ? httpProtocol : webSocketProtocol); p.handle(ctx, e); } @@ -1409,6 +1411,10 @@ private void upgradeProtocol(ChannelPipeline p, String scheme) throws IOExceptio } else { p.addFirst(HTTP_HANDLER, createHttpClientCodec()); } + + if (isWebSocket(scheme)) { + p.replace(HTTP_PROCESSOR, WS_PROCESSOR, NettyAsyncHttpProvider.this); + } } public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { @@ -2315,8 +2321,8 @@ public void handle(ChannelHandlerContext ctx, MessageEvent e) throws Exception { return; } - ctx.getPipeline().replace("http-encoder", "ws-encoder", new WebSocket08FrameEncoder(true)); - ctx.getPipeline().get(HttpResponseDecoder.class).replace("ws-decoder", new WebSocket08FrameDecoder(false, false)); + ctx.getPipeline().replace(HTTP_HANDLER, "ws-encoder", new WebSocket08FrameEncoder(true)); + ctx.getPipeline().addBefore(WS_PROCESSOR, "ws-decoder", new WebSocket08FrameDecoder(false, false)); invokeOnSucces(ctx, h); future.done(); @@ -2437,8 +2443,8 @@ public Timeout newTimeoutInMs(TimerTask task, long delayInMs) { return hashedWheelTimer.newTimeout(task, delayInMs, TimeUnit.MILLISECONDS); } - private static boolean isWebSocket(URI uri) { - return WEBSOCKET.equalsIgnoreCase(uri.getScheme()) || WEBSOCKET_SSL.equalsIgnoreCase(uri.getScheme()); + private static boolean isWebSocket(String scheme) { + return WEBSOCKET.equalsIgnoreCase(scheme) || WEBSOCKET_SSL.equalsIgnoreCase(scheme); } private static boolean isSecure(String scheme) { From 4103ab8eb8c870ed585c84a5b77271ad06984357 Mon Sep 17 00:00:00 2001 From: jfarcand Date: Thu, 30 Jan 2014 14:48:14 -0500 Subject: [PATCH 210/701] Turn the log to TRACE --- .../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 4b48850b91..ec02ec33fd 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 @@ -252,7 +252,7 @@ public NettyAsyncHttpProvider(AsyncHttpClientConfig config) { e = Executors.newCachedThreadPool(); } int numWorkers = config.getIoThreadMultiplier() * Runtime.getRuntime().availableProcessors(); - log.debug("Number of application's worker threads is {}", numWorkers); + log.trace("Number of application's worker threads is {}", numWorkers); socketChannelFactory = new NioClientSocketChannelFactory(e, config.executorService(), numWorkers); allowReleaseSocketChannelFactory = true; } From 7b679f01a6b08144841168f98923efdd1cda4783 Mon Sep 17 00:00:00 2001 From: jfarcand Date: Fri, 31 Jan 2014 09:53:49 -0500 Subject: [PATCH 211/701] [maven-release-plugin] prepare release async-http-client-1.8.0 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index d20cf4d8b9..845f7a8170 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.8.0-SNAPSHOT + 1.8.0 jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From a6476864f6a66940c6a8364b441b6815074d90f2 Mon Sep 17 00:00:00 2001 From: jfarcand Date: Fri, 31 Jan 2014 09:53:52 -0500 Subject: [PATCH 212/701] [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 845f7a8170..43a699c49b 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.8.0 + 1.8.1-SNAPSHOT jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From df33a36ff94086696a2154f41bfd50a67e5c137c Mon Sep 17 00:00:00 2001 From: jfarcand Date: Fri, 31 Jan 2014 10:05:35 -0500 Subject: [PATCH 213/701] Remove dead reaper --- .../http/client/AsyncHttpClientConfig.java | 27 ------------------- 1 file changed, 27 deletions(-) diff --git a/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java b/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java index c5f2e9fffd..8af1daabbb 100644 --- a/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java @@ -30,7 +30,6 @@ import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ThreadFactory; /** @@ -103,7 +102,6 @@ private AsyncHttpClientConfig(int maxTotalConnections, boolean compressionEnabled, String userAgent, boolean keepAlive, - ScheduledExecutorService reaper, ExecutorService applicationThreadPool, ProxyServerSelector proxyServerSelector, SSLContext sslContext, @@ -543,7 +541,6 @@ public static class Builder { 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 ProxyServerSelector proxyServerSelector = null; private SSLContext sslContext; @@ -716,17 +713,6 @@ public Builder setKeepAlive(boolean allowPoolingConnection) { return this; } - /** - * Set the{@link ScheduledExecutorService} used to expire idle connections. - * - * @param reaper the{@link ScheduledExecutorService} used to expire idle connections. - * @return a {@link Builder} - */ - public Builder setScheduledExecutorService(ScheduledExecutorService reaper) { - this.reaper = reaper; - return this; - } - /** * Set the {@link java.util.concurrent.ExecutorService} an {@link AsyncHttpClient} use for handling * asynchronous response. @@ -1107,18 +1093,6 @@ public Builder(AsyncHttpClientConfig prototype) { * @return an {@link AsyncHttpClientConfig} */ 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() { @@ -1156,7 +1130,6 @@ public Thread newThread(Runnable r) { compressionEnabled, userAgent, allowPoolingConnection, - reaper, applicationThreadPool, proxyServerSelector, sslContext, From b8ce3dffb68508073aae5c63d89e6532a68126d4 Mon Sep 17 00:00:00 2001 From: jfarcand Date: Fri, 31 Jan 2014 11:36:58 -0500 Subject: [PATCH 214/701] Fix this class who was broken by the previous commit --- .../java/com/ning/http/client/SimpleAsyncHttpClient.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/main/java/com/ning/http/client/SimpleAsyncHttpClient.java b/src/main/java/com/ning/http/client/SimpleAsyncHttpClient.java index 45eb19794f..7f224b9609 100644 --- a/src/main/java/com/ning/http/client/SimpleAsyncHttpClient.java +++ b/src/main/java/com/ning/http/client/SimpleAsyncHttpClient.java @@ -530,11 +530,6 @@ public Builder setAllowPoolingConnection(boolean allowPoolingConnection) { return this; } - public Builder setScheduledExecutorService(ScheduledExecutorService reaper) { - configBuilder.setScheduledExecutorService(reaper); - return this; - } - public Builder setExecutorService(ExecutorService applicationThreadPool) { configBuilder.setExecutorService(applicationThreadPool); return this; From bf1ad45d0f84c1a5f580df522554cdaba47b37e9 Mon Sep 17 00:00:00 2001 From: jfarcand Date: Fri, 31 Jan 2014 11:40:32 -0500 Subject: [PATCH 215/701] Fix really old cut&paste error --- .../http/client/SimpleAsyncHttpClient.java | 1 - .../netty/NettyAsyncHttpProvider.java | 182 +++++++++--------- 2 files changed, 90 insertions(+), 93 deletions(-) diff --git a/src/main/java/com/ning/http/client/SimpleAsyncHttpClient.java b/src/main/java/com/ning/http/client/SimpleAsyncHttpClient.java index 7f224b9609..aacfb6eb8d 100644 --- a/src/main/java/com/ning/http/client/SimpleAsyncHttpClient.java +++ b/src/main/java/com/ning/http/client/SimpleAsyncHttpClient.java @@ -25,7 +25,6 @@ import java.util.Map; import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; -import java.util.concurrent.ScheduledExecutorService; /** * Simple implementation of {@link AsyncHttpClient} and it's related builders ({@link com.ning.http.client.AsyncHttpClientConfig}, 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 ec02ec33fd..72bf9ac102 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,97 +15,6 @@ */ package com.ning.http.client.providers.netty; -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.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.List; -import java.util.Locale; -import java.util.Map.Entry; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.RejectedExecutionException; -import java.util.concurrent.Semaphore; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; - -import javax.net.ssl.SSLEngine; - -import org.jboss.netty.bootstrap.ClientBootstrap; -import org.jboss.netty.buffer.ChannelBuffer; -import org.jboss.netty.buffer.ChannelBufferOutputStream; -import org.jboss.netty.buffer.ChannelBuffers; -import org.jboss.netty.channel.Channel; -import org.jboss.netty.channel.ChannelFuture; -import org.jboss.netty.channel.ChannelFutureProgressListener; -import org.jboss.netty.channel.ChannelHandlerContext; -import org.jboss.netty.channel.ChannelPipeline; -import org.jboss.netty.channel.ChannelPipelineFactory; -import org.jboss.netty.channel.ChannelStateEvent; -import org.jboss.netty.channel.DefaultChannelFuture; -import org.jboss.netty.channel.ExceptionEvent; -import org.jboss.netty.channel.FileRegion; -import org.jboss.netty.channel.MessageEvent; -import org.jboss.netty.channel.SimpleChannelUpstreamHandler; -import org.jboss.netty.channel.group.ChannelGroup; -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; -import org.jboss.netty.handler.codec.http.HttpChunkTrailer; -import org.jboss.netty.handler.codec.http.HttpClientCodec; -import org.jboss.netty.handler.codec.http.HttpContentDecompressor; -import org.jboss.netty.handler.codec.http.HttpHeaders; -import org.jboss.netty.handler.codec.http.HttpMethod; -import org.jboss.netty.handler.codec.http.HttpRequest; -import org.jboss.netty.handler.codec.http.HttpResponse; -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; -import org.jboss.netty.handler.ssl.SslHandler; -import org.jboss.netty.handler.stream.ChunkedFile; -import org.jboss.netty.handler.stream.ChunkedWriteHandler; -import org.jboss.netty.util.HashedWheelTimer; -import org.jboss.netty.util.Timeout; -import org.jboss.netty.util.TimerTask; -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.AsyncHandlerExtensions; @@ -153,6 +62,95 @@ 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; +import org.jboss.netty.buffer.ChannelBuffers; +import org.jboss.netty.channel.Channel; +import org.jboss.netty.channel.ChannelFuture; +import org.jboss.netty.channel.ChannelFutureProgressListener; +import org.jboss.netty.channel.ChannelHandlerContext; +import org.jboss.netty.channel.ChannelPipeline; +import org.jboss.netty.channel.ChannelPipelineFactory; +import org.jboss.netty.channel.ChannelStateEvent; +import org.jboss.netty.channel.DefaultChannelFuture; +import org.jboss.netty.channel.ExceptionEvent; +import org.jboss.netty.channel.FileRegion; +import org.jboss.netty.channel.MessageEvent; +import org.jboss.netty.channel.SimpleChannelUpstreamHandler; +import org.jboss.netty.channel.group.ChannelGroup; +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; +import org.jboss.netty.handler.codec.http.HttpChunkTrailer; +import org.jboss.netty.handler.codec.http.HttpClientCodec; +import org.jboss.netty.handler.codec.http.HttpContentDecompressor; +import org.jboss.netty.handler.codec.http.HttpHeaders; +import org.jboss.netty.handler.codec.http.HttpMethod; +import org.jboss.netty.handler.codec.http.HttpRequest; +import org.jboss.netty.handler.codec.http.HttpResponse; +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; +import org.jboss.netty.handler.ssl.SslHandler; +import org.jboss.netty.handler.stream.ChunkedFile; +import org.jboss.netty.handler.stream.ChunkedWriteHandler; +import org.jboss.netty.util.HashedWheelTimer; +import org.jboss.netty.util.Timeout; +import org.jboss.netty.util.TimerTask; +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.List; +import java.util.Locale; +import java.util.Map.Entry; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + +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.MiscUtil.isNonEmpty; +import static org.jboss.netty.channel.Channels.pipeline; public class NettyAsyncHttpProvider extends SimpleChannelUpstreamHandler implements AsyncHttpProvider { @@ -1688,7 +1686,7 @@ protected static boolean abortOnWriteCloseException(Throwable cause) { } if (cause.getCause() != null) { - return abortOnReadCloseException(cause.getCause()); + return abortOnWriteCloseException(cause.getCause()); } return false; From 8699ef3f08fc888ecbe2653f920744beb7d0b64c Mon Sep 17 00:00:00 2001 From: jfarcand Date: Fri, 31 Jan 2014 11:50:59 -0500 Subject: [PATCH 216/701] [maven-release-plugin] prepare release async-http-client-1.8.1 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 43a699c49b..8c590a277e 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.8.1-SNAPSHOT + 1.8.1 jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From ad2971ed8144f6926f4199e3d5ac0e593390c5d7 Mon Sep 17 00:00:00 2001 From: jfarcand Date: Fri, 31 Jan 2014 11:51:03 -0500 Subject: [PATCH 217/701] [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 8c590a277e..b1194eb343 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.8.1 + 1.8.2-SNAPSHOT jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From a1397e221253fdf62218b7619867b62a216452c3 Mon Sep 17 00:00:00 2001 From: Chris Perkins Date: Sun, 2 Feb 2014 17:46:20 -0700 Subject: [PATCH 218/701] Fix bug in netty websockets that treated a close frame as text. When the remote server closes a websocket connection, the close frame is treated as a text frame and junk bytes are sent to onTextFragment. --- .../netty/NettyAsyncHttpProvider.java | 2 +- .../client/websocket/TextMessageTest.java | 54 ++++++++++++++++++- 2 files changed, 54 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 72bf9ac102..f3d6551ab3 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 @@ -2366,7 +2366,7 @@ public void setContent(ChannelBuffer content) { if (webSocket != null) { if (pendingOpcode == OPCODE_BINARY) { webSocket.onBinaryFragment(rp.getBodyPartBytes(), frame.isFinalFragment()); - } else { + } else if (pendingOpcode == OPCODE_TEXT) { webSocket.onTextFragment(frame.getBinaryData().toString(UTF8), frame.isFinalFragment()); } 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 000367e43b..dab785b593 100644 --- a/src/test/java/com/ning/http/client/websocket/TextMessageTest.java +++ b/src/test/java/com/ning/http/client/websocket/TextMessageTest.java @@ -45,7 +45,10 @@ public void onClose(int i, String s) { @Override public void onMessage(String s) { try { - connection.sendMessage(s); + if (s.equals("CLOSE")) + connection.close(); + else + connection.sendMessage(s); } catch (IOException e) { try { connection.sendMessage("FAIL"); @@ -401,4 +404,53 @@ public void onError(Throwable t) { c.close(); } } + + @Test(timeOut = 60000) + public void echoTextAndThenClose() throws Throwable { + AsyncHttpClient c = getAsyncHttpClient(null); + try { + final CountDownLatch textLatch = new CountDownLatch(1); + final CountDownLatch closeLatch = new CountDownLatch(1); + final AtomicReference text = new AtomicReference(""); + + final WebSocket websocket = c.prepareGet(getTargetUrl()).execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(new WebSocketTextListener() { + + @Override + public void onMessage(String message) { + text.set(text.get() + message); + textLatch.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) { + closeLatch.countDown(); + } + + @Override + public void onError(Throwable t) { + t.printStackTrace(); + closeLatch.countDown(); + } + }).build()).get(); + + websocket.sendTextMessage("ECHO"); + textLatch.await(); + + websocket.sendTextMessage("CLOSE"); + closeLatch.await(); + + assertEquals(text.get(), "ECHO"); + } finally { + c.close(); + } + } + } From 9212ce918be22e6952ab1c6afd8e019e25836450 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 5 Feb 2014 14:31:47 +0100 Subject: [PATCH 219/701] Backport some cookie parsing improvements from 55f8e7c163524c27648d15748014354361a61551 --- .../java/com/ning/http/client/Cookie.java | 133 ++++++++- .../apache/ApacheAsyncHttpProvider.java | 6 +- .../providers/apache/ApacheResponse.java | 21 +- .../providers/jdk/JDKAsyncHttpProvider.java | 4 +- .../client/providers/jdk/JDKResponse.java | 21 +- .../client/providers/netty/NettyResponse.java | 21 +- .../http/util/AsyncHttpProviderUtils.java | 167 ------------ .../handler/codec/http/CookieDecoder.java | 258 +++++++++--------- .../handler/codec/http/CookieEncoder.java | 16 +- .../handler/codec/http/CookieHeaderNames.java | 12 - .../handler/codec/http/HttpConstants.java | 15 + .../handler/codec/http/CookieDecoderTest.java | 14 +- 12 files changed, 314 insertions(+), 374 deletions(-) diff --git a/src/main/java/com/ning/http/client/Cookie.java b/src/main/java/com/ning/http/client/Cookie.java index b3be657d5a..30aa3b2baf 100644 --- a/src/main/java/com/ning/http/client/Cookie.java +++ b/src/main/java/com/ning/http/client/Cookie.java @@ -45,7 +45,8 @@ public Cookie(String domain, String name, String value, String path, int maxAge, this(domain, name, value, value, path, maxAge, secure, version, false, false, null, null, Collections. emptySet()); } - 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) { + 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"); @@ -207,8 +208,7 @@ 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); + 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) { @@ -266,4 +266,131 @@ public int compareTo(Cookie c) { return 0; } + + public static class CookieBuilder { + + private final String name; + private final String value; + private final String rawValue; + private String domain; + private String path; + private int maxAge = -1; + private boolean secure; + private int version; + private boolean httpOnly; + private boolean discard; + private String comment; + private String commentUrl; + private Set ports; + private boolean domainNotSet = true; + private boolean pathNotSet = true; + private boolean maxAgeNotSet = true; + private boolean secureNotSet = true; + private boolean versionNotSet = true; + private boolean httpOnlyNotSet = true; + private boolean discardNotSet = true; + private boolean commentNotSet = true; + private boolean commentUrlNotSet = true; + private boolean portsNotSet = true; + + public CookieBuilder(String name, String value, String rawValue) { + this.name = name; + this.value = value; + this.rawValue = rawValue; + } + + public Cookie build() { + return new Cookie(domain, name, value, rawValue, path, maxAge, secure, version, httpOnly, discard, comment, commentUrl, ports); + } + + public void setDomain(String domain) { + this.domain = domain; + domainNotSet = false; + } + + public void setPath(String path) { + this.path = path; + pathNotSet = false; + } + + public void setMaxAge(int maxAge) { + this.maxAge = maxAge; + maxAgeNotSet = false; + } + + public void setSecure(boolean secure) { + this.secure = secure; + secureNotSet = false; + } + + public void setVersion(int version) { + this.version = version; + versionNotSet = false; + } + + public void setHttpOnly(boolean httpOnly) { + this.httpOnly = httpOnly; + httpOnlyNotSet = false; + } + + public void setDiscard(boolean discard) { + this.discard = discard; + discardNotSet = false; + } + + public void setComment(String comment) { + this.comment = comment; + commentNotSet = false; + } + + public void setCommentUrl(String commentUrl) { + this.commentUrl = commentUrl; + commentNotSet = false; + } + + public void setPorts(Set ports) { + this.ports = ports; + portsNotSet = false; + } + + public boolean isDomainNotSet() { + return domainNotSet; + } + + public boolean isPathNotSet() { + return pathNotSet; + } + + public boolean isMaxAgeNotSet() { + return maxAgeNotSet; + } + + public boolean isSecureNotSet() { + return secureNotSet; + } + + public boolean isVersionNotSet() { + return versionNotSet; + } + + public boolean isHttpOnlyNotSet() { + return httpOnlyNotSet; + } + + public boolean isDiscardNotSet() { + return discardNotSet; + } + + public boolean isCommentNotSet() { + return commentNotSet; + } + + public boolean isCommentUrlNotSet() { + return commentUrlNotSet; + } + + public boolean isPortsNotSet() { + return portsNotSet; + } + } } 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 0eb710d95e..a38cd5f97f 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 @@ -20,7 +20,6 @@ import com.ning.http.client.AsyncHttpProviderConfig; import com.ning.http.client.Body; import com.ning.http.client.ByteArrayPart; -import com.ning.http.client.Cookie; import com.ning.http.client.FilePart; import com.ning.http.client.HttpResponseBodyPart; import com.ning.http.client.HttpResponseHeaders; @@ -45,6 +44,7 @@ import com.ning.http.util.AsyncHttpProviderUtils; import com.ning.http.util.ProxyUtils; import com.ning.http.util.UTF8UrlEncoder; +import com.ning.org.jboss.netty.handler.codec.http.CookieEncoder; import org.apache.commons.httpclient.CircularRedirectException; import org.apache.commons.httpclient.Credentials; @@ -377,9 +377,7 @@ private HttpMethodBase createMethod(HttpClient client, Request request) throws I method.setFollowRedirects(false); if (isNonEmpty(request.getCookies())) { - for (Cookie cookie : request.getCookies()) { - method.setRequestHeader("Cookie", AsyncHttpProviderUtils.encodeCookies(request.getCookies())); - } + method.setRequestHeader("Cookie", CookieEncoder.encodeClientSide(request.getCookies(), config.isRfc6265CookieEncoding())); } if (request.getHeaders() != null) { 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 988962dbdd..7a55f5799b 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,15 +14,6 @@ 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; -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.IOException; import java.io.InputStream; import java.net.MalformedURLException; @@ -32,7 +23,15 @@ import java.util.Collections; import java.util.List; import java.util.Map; -import java.util.Set; + +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.Response; +import com.ning.http.util.AsyncHttpProviderUtils; +import com.ning.org.jboss.netty.handler.codec.http.CookieDecoder; public class ApacheResponse implements Response { private final static String DEFAULT_CHARSET = "ISO-8859-1"; @@ -171,7 +170,7 @@ public List getCookies() { // TODO: ask for parsed header List v = header.getValue(); for (String value : v) { - Set cookies = CookieDecoder.decode(value); + List cookies = CookieDecoder.decode(value); localCookies.addAll(cookies); } } 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 011884c171..18139e8733 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 com.ning.org.jboss.netty.handler.codec.http.CookieEncoder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -51,6 +52,7 @@ import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLHandshakeException; + import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; @@ -547,7 +549,7 @@ private void configure(URI uri, HttpURLConnection urlConnection, Request request } if (isNonEmpty(request.getCookies())) { - urlConnection.setRequestProperty("Cookie", AsyncHttpProviderUtils.encodeCookies(request.getCookies())); + urlConnection.setRequestProperty("Cookie", CookieEncoder.encodeClientSide(request.getCookies(), config.isRfc6265CookieEncoding())); } String reqType = request.getMethod(); 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 00cae65b0a..631f9cc525 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,15 +14,6 @@ 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; -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; @@ -33,9 +24,17 @@ import java.util.Collections; import java.util.List; import java.util.Map; -import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; +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.Response; +import com.ning.http.util.AsyncHttpProviderUtils; +import com.ning.org.jboss.netty.handler.codec.http.CookieDecoder; + public class JDKResponse implements Response { private final static String DEFAULT_CHARSET = "ISO-8859-1"; @@ -186,7 +185,7 @@ public List getCookies() { // TODO: ask for parsed header List v = header.getValue(); for (String value : v) { - Set cookies = CookieDecoder.decode(value); + List cookies = CookieDecoder.decode(value); localCookies.addAll(cookies); } } 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 787501d3fd..b17af51bcb 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,15 +17,6 @@ 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; -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.IOException; import java.io.InputStream; import java.net.MalformedURLException; @@ -36,12 +27,20 @@ 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; import org.jboss.netty.buffer.ChannelBuffers; +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.Response; +import com.ning.http.util.AsyncHttpProviderUtils; +import com.ning.org.jboss.netty.handler.codec.http.CookieDecoder; + /** * Wrapper around the {@link com.ning.http.client.Response} API. */ @@ -195,7 +194,7 @@ public List getCookies() { // TODO: ask for parsed header List v = header.getValue(); for (String value : v) { - Set cookies = CookieDecoder.decode(value); + List 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 14618143ea..816161d73d 100644 --- a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java +++ b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java @@ -76,72 +76,6 @@ public final static SimpleDateFormat[] get() { return simpleDateFormat.get(); } - - //space ' ' - static final byte SP = 32; - - //tab ' ' - static final byte HT = 9; - - /** - * Carriage return - */ - static final byte CR = 13; - - /** - * Equals '=' - */ - static final byte EQUALS = 61; - - /** - * Line feed character - */ - static final byte LF = 10; - - /** - * carriage return line feed - */ - static final byte[] CRLF = new byte[]{CR, LF}; - - /** - * Colon ':' - */ - static final byte COLON = 58; - - /** - * Semicolon ';' - */ - static final byte SEMICOLON = 59; - - /** - * comma ',' - */ - static final byte COMMA = 44; - - static final byte DOUBLE_QUOTE = '"'; - - 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"; - static final byte[] EMPTY_BYTE_ARRAY = "".getBytes(); public static final void validateSupportedScheme(URI uri) { @@ -354,107 +288,6 @@ private static byte[] doubleUp(byte[] b) { return b2; } - public static String encodeCookies(Collection cookies) { - StringBuilder sb = new StringBuilder(); - - for (Cookie cookie : cookies) { - if (cookie.getVersion() >= 1) { - add(sb, '$' + VERSION, 1); - } - - add(sb, cookie.getName(), cookie.getValue()); - - if (cookie.getPath() != null) { - add(sb, '$' + PATH, cookie.getPath()); - } - - if (cookie.getDomain() != null) { - add(sb, '$' + DOMAIN, cookie.getDomain()); - } - - if (cookie.getVersion() >= 1) { - if (!cookie.getPorts().isEmpty()) { - sb.append('$'); - sb.append(PORT); - sb.append((char) EQUALS); - sb.append((char) DOUBLE_QUOTE); - for (int port : cookie.getPorts()) { - sb.append(port); - sb.append((char) COMMA); - } - sb.setCharAt(sb.length() - 1, (char) DOUBLE_QUOTE); - sb.append((char) SEMICOLON); - } - } - } - - sb.setLength(sb.length() - 1); - return sb.toString(); - } - - 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) EQUALS); - sb.append(val); - sb.append((char) SEMICOLON); - } - - private static void addQuoted(StringBuilder sb, String name, String val) { - if (val == null) { - val = ""; - } - - sb.append(name); - sb.append((char) EQUALS); - sb.append((char) DOUBLE_QUOTE); - sb.append(val.replace("\\", "\\\\").replace("\"", "\\\"")); - sb.append((char) DOUBLE_QUOTE); - sb.append((char) SEMICOLON); - } - - private static void add(StringBuilder sb, String name, int val) { - sb.append(name); - sb.append((char) EQUALS); - sb.append(val); - sb.append((char) SEMICOLON); - } - public static String constructUserAgent(Class httpProvider) { StringBuilder b = new StringBuilder("AsyncHttpClient/1.0") .append(" ") 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 4e4eecb1b8..83ce6dd836 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 @@ -13,29 +13,20 @@ * 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.HashSet; +import java.util.TreeSet; + +import org.jboss.netty.handler.codec.http.HttpRequest; -import com.ning.org.jboss.netty.util.internal.StringUtil; import com.ning.http.client.Cookie; +import com.ning.http.client.Cookie.CookieBuilder; import com.ning.http.util.AsyncHttpProviderUtils; +import com.ning.org.jboss.netty.util.internal.StringUtil; /** * Decodes an HTTP header value into {@link Cookie}s. This decoder can decode the HTTP cookie version 0, 1, and 2. @@ -55,131 +46,125 @@ public class CookieDecoder { private static final char COMMA = ','; - /** - * Creates a new decoder. - */ - private CookieDecoder() { - } + private static class CookiesBuilder { - /** - * 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); - List rawValues = new ArrayList(8); - extractKeyValuePairs(header, names, values, rawValues); - - if (names.isEmpty()) { - return Collections.emptySet(); - } + private int i; + private int version = 0; + private CookieBuilder cookieBuilder; + private List cookies = new ArrayList(); - int i; - int version = 0; + public void addKeyValuePair(String name, String value, String rawValue) { - // $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. + // $Version is the only attribute that can appear before the actual + // cookie name-value pair. + if (i == 0 && name.equalsIgnoreCase(CookieHeaderNames.VERSION)) { + try { + version = Integer.parseInt(value); + } catch (NumberFormatException e) { + // Ignore. + } + + } else if (cookieBuilder == null) { + cookieBuilder = new CookieBuilder(name, value, rawValue); + if (version != 0) + cookieBuilder.setVersion(version); + + } else if (setCookieAttribute(name, value)) { + cookies.add(cookieBuilder.build()); + cookieBuilder = null; } - i = 1; - } else { - i = 0; } - if (names.size() <= i) { - // There's a version attribute, but nothing more. - return Collections.emptySet(); + public List build() { + cookies.add(cookieBuilder.build()); + return cookies; } - 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 = ""; + private boolean setCookieAttribute(String name, String value) { + + if (CookieHeaderNames.DISCARD.equalsIgnoreCase(name)) { + cookieBuilder.setDiscard(true); + + } else if (CookieHeaderNames.SECURE.equalsIgnoreCase(name)) { + cookieBuilder.setSecure(true); + + } else if (CookieHeaderNames.HTTPONLY.equalsIgnoreCase(name)) { + cookieBuilder.setHttpOnly(true); + + } else if (CookieHeaderNames.COMMENT.equalsIgnoreCase(name)) { + cookieBuilder.setComment(value); + + } else if (CookieHeaderNames.COMMENTURL.equalsIgnoreCase(name)) { + cookieBuilder.setCommentUrl(value); + + } else if (CookieHeaderNames.DOMAIN.equalsIgnoreCase(name)) { + cookieBuilder.setDomain(value); + + } else if (CookieHeaderNames.PATH.equalsIgnoreCase(name)) { + cookieBuilder.setPath(value); + + } else if (CookieHeaderNames.EXPIRES.equalsIgnoreCase(name)) { + setCookieExpires(cookieBuilder, value); + + } else if (CookieHeaderNames.MAX_AGE.equalsIgnoreCase(name)) { + cookieBuilder.setMaxAge(Integer.parseInt(value)); + + } else if (CookieHeaderNames.VERSION.equalsIgnoreCase(name)) { + cookieBuilder.setVersion(Integer.parseInt(value)); + + } else if (CookieHeaderNames.PORT.equalsIgnoreCase(name)) { + setCookiePorts(cookieBuilder, value); + + } else { + return true; } - String cookieName = name; - String cookieValue = value; - String cookieRawValue = rawValue; - boolean discard = false; - boolean secure = false; - boolean httpOnly = false; - String comment = null; - String commentURL = null; - String domain = null; - String path = null; - int maxAge = -1; - 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; + return false; + } + + private void setCookieExpires(CookieBuilder cookieBuilder, String value) { + try { + cookieBuilder.setMaxAge(AsyncHttpProviderUtils.convertExpireField(value)); + } catch (Exception e) { + // original behavior, is this correct at all (expires field with max-age semantics)? + try { + cookieBuilder.setMaxAge(Math.max(Integer.valueOf(value), 0)); + } catch (NumberFormatException e1) { + // ignore failure to parse -> treat as session cookie } } + } - Cookie c = new Cookie(domain, cookieName, cookieValue, cookieRawValue, path, maxAge, secure, version, httpOnly, discard, comment, commentURL, ports); - cookies.add(c); + private void setCookiePorts(CookieBuilder cookieBuilder, String value) { + String[] portList = StringUtil.split(value, COMMA); + Set ports = new TreeSet(); + for (String s1 : portList) { + try { + ports.add(Integer.valueOf(s1)); + } catch (NumberFormatException e) { + // Ignore. + } + } + cookieBuilder.setPorts(ports); } + } - return cookies; + private CookieDecoder() { } - private static void extractKeyValuePairs(final String header, final List names, final List values, final List rawValues) { + /** + * Decodes the specified HTTP header value into {@link Cookie}s. + * + * @return the decoded {@link Cookie}s + */ + public static List decode(String header) { final int headerLen = header.length(); + if (headerLen == 0) + return Collections.emptyList(); + + CookiesBuilder cookiesBuilder = new CookiesBuilder(); + loop: for (int i = 0;;) { // Skip spaces and separators. @@ -217,11 +202,11 @@ private static void extractKeyValuePairs(final String header, final List String name; String value; String rawValue; + int names = 0; if (i == headerLen) { name = null; - value = null; - rawValue = null; + value = rawValue = null; } else { int newNameStart = i; keyValLoop: for (;;) { @@ -229,17 +214,17 @@ private static void extractKeyValuePairs(final String header, final List case ';': // NAME; (no value till ';') name = header.substring(newNameStart, i); - value = null; - rawValue = null; + names++; + value = rawValue = null; break keyValLoop; case '=': // NAME=VALUE name = header.substring(newNameStart, i); + names++; i++; if (i == headerLen) { // NAME= (empty value, i.e. nothing after '=') - value = ""; - rawValue = ""; + value = rawValue = ""; break keyValLoop; } @@ -248,21 +233,24 @@ 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); + + int rawValueStart = i; + int rawValueEnd = i; + final char q = c; boolean hadBackslash = false; i++; for (;;) { if (i == headerLen) { value = newValueBuf.toString(); - rawValue = newRawValueBuf.toString(); + // only need to compute raw value for cookie value which is at most in 2nd position + rawValue = names <= 1 ? header.substring(rawValueStart, rawValueEnd) : null; break keyValLoop; } if (hadBackslash) { hadBackslash = false; c = header.charAt(i++); - newRawValueBuf.append(c); + rawValueEnd = i; switch (c) { case '\\': case '"': @@ -276,10 +264,11 @@ private static void extractKeyValuePairs(final String header, final List } } else { c = header.charAt(i++); - newRawValueBuf.append(c); + rawValueEnd = i; if (c == q) { value = newValueBuf.toString(); - rawValue = newRawValueBuf.toString(); + // only need to compute raw value for cookie value which is at most in 2nd position + rawValue = names <= 1 ? header.substring(rawValueStart, rawValueEnd) : null; break keyValLoop; } newValueBuf.append(c); @@ -313,9 +302,8 @@ private static void extractKeyValuePairs(final String header, final List } } - names.add(name); - values.add(value); - rawValues.add(rawValue); + cookiesBuilder.addKeyValuePair(name, value, rawValue); } + return cookiesBuilder.build(); } } 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 a2297f9029..5842e066cc 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 @@ -13,18 +13,6 @@ * 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; @@ -139,6 +127,10 @@ private static void add(StringBuilder sb, String name, String val) { } private static void addUnquoted(StringBuilder sb, String name, String val) { + if (val == null) { + val = ""; + } + sb.append(name); sb.append((char) HttpConstants.EQUALS); sb.append(val); 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 index 5d3e6c9249..6d050c206e 100644 --- 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 @@ -13,18 +13,6 @@ * 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 { 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 index 1880dc4fed..0331bd6faf 100644 --- 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 @@ -1,3 +1,18 @@ +/* + * 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.handler.codec.http; import java.nio.charset.Charset; 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 index 5d2f9cb09b..6e7f35b3ae 100644 --- 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 @@ -12,7 +12,7 @@ */ package com.ning.org.jboss.netty.handler.codec.http; -import java.util.Set; +import java.util.List; import org.testng.Assert; import org.testng.annotations.Test; @@ -23,10 +23,10 @@ public class CookieDecoderTest { @Test(groups = "fast") public void testDecodeUnquoted() { - Set cookies = CookieDecoder.decode("foo=value; domain=/; path=/"); + List cookies = CookieDecoder.decode("foo=value; domain=/; path=/"); Assert.assertEquals(cookies.size(), 1); - Cookie first = cookies.iterator().next(); + Cookie first = cookies.get(0); Assert.assertEquals(first.getValue(), "value"); Assert.assertEquals(first.getDomain(), "/"); Assert.assertEquals(first.getPath(), "/"); @@ -34,19 +34,19 @@ public void testDecodeUnquoted() { @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"); + List cookies = CookieDecoder.decode("ALPHA=\"VALUE1\"; Domain=docs.foo.com; Path=/accounts; Expires=Wed, 05 Feb 2014 07:37:38 GMT; Secure; HttpOnly"); Assert.assertEquals(cookies.size(), 1); - Cookie first = cookies.iterator().next(); + Cookie first = cookies.get(0); 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"); + List cookies = CookieDecoder.decode("ALPHA=\"VALUE1\\\"\"; Domain=docs.foo.com; Path=/accounts; Expires=Wed, 05 Feb 2014 07:37:38 GMT; Secure; HttpOnly"); Assert.assertEquals(cookies.size(), 1); - Cookie first = cookies.iterator().next(); + Cookie first = cookies.get(0); Assert.assertEquals(first.getValue(), "VALUE1\""); } } From 697298545cf8818db33b44cb4a6985891620d51b Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 6 Feb 2014 01:47:15 +0100 Subject: [PATCH 220/701] Make timeout exception messages more constant --- .../netty/timeout/IdleConnectionTimeoutTimerTask.java | 2 +- .../providers/netty/timeout/RequestTimeoutTimerTask.java | 2 +- .../http/client/providers/netty/timeout/TimeoutTimerTask.java | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/timeout/IdleConnectionTimeoutTimerTask.java b/src/main/java/com/ning/http/client/providers/netty/timeout/IdleConnectionTimeoutTimerTask.java index 53eaf739ac..32b0861992 100644 --- a/src/main/java/com/ning/http/client/providers/netty/timeout/IdleConnectionTimeoutTimerTask.java +++ b/src/main/java/com/ning/http/client/providers/netty/timeout/IdleConnectionTimeoutTimerTask.java @@ -50,7 +50,7 @@ public void run(Timeout timeout) throws Exception { if (durationBeforeCurrentIdleConnectionTimeout <= 0L) { // idleConnectionTimeout reached long durationSinceLastTouch = now - nettyResponseFuture.getLastTouch(); - expire("Connection reached idle timeout of " + idleConnectionTimeout + " ms after " + durationSinceLastTouch + " ms"); + expire("Idle connection timeout of " + idleConnectionTimeout + " ms", durationSinceLastTouch); nettyResponseFuture.setIdleConnectionTimeoutReached(); } else if (currentIdleConnectionTimeoutInstant < requestTimeoutInstant) { diff --git a/src/main/java/com/ning/http/client/providers/netty/timeout/RequestTimeoutTimerTask.java b/src/main/java/com/ning/http/client/providers/netty/timeout/RequestTimeoutTimerTask.java index bee7383498..ac8003014c 100644 --- a/src/main/java/com/ning/http/client/providers/netty/timeout/RequestTimeoutTimerTask.java +++ b/src/main/java/com/ning/http/client/providers/netty/timeout/RequestTimeoutTimerTask.java @@ -38,7 +38,7 @@ public void run(Timeout timeout) throws Exception { } if (!nettyResponseFuture.isDone() && !nettyResponseFuture.isCancelled()) { - expire("Request reached timeout of " + nettyResponseFuture.getRequestTimeoutInMs() + " ms after " + (millisTime() - nettyResponseFuture.getStart()) + " ms"); + expire("Request timeout of " + nettyResponseFuture.getRequestTimeoutInMs() + " ms", millisTime() - nettyResponseFuture.getStart()); nettyResponseFuture.setRequestTimeoutReached(); } } diff --git a/src/main/java/com/ning/http/client/providers/netty/timeout/TimeoutTimerTask.java b/src/main/java/com/ning/http/client/providers/netty/timeout/TimeoutTimerTask.java index c14512c5bc..dbabeaa4f1 100644 --- a/src/main/java/com/ning/http/client/providers/netty/timeout/TimeoutTimerTask.java +++ b/src/main/java/com/ning/http/client/providers/netty/timeout/TimeoutTimerTask.java @@ -38,8 +38,8 @@ public TimeoutTimerTask(NettyResponseFuture nettyResponseFuture, NettyAsyncHt this.timeoutsHolder = timeoutsHolder; } - protected void expire(String message) { - LOGGER.debug("{} for {}", message, nettyResponseFuture); + protected void expire(String message, long time) { + LOGGER.debug("{} for {} after {} ms", message, nettyResponseFuture, time); provider.abort(nettyResponseFuture, new TimeoutException(message)); } } From f361e3d4d9a9785133a37351114e06830ca52faf Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 6 Feb 2014 08:06:34 +0100 Subject: [PATCH 221/701] Fix test --- .../http/client/async/netty/NettyPerRequestTimeoutTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 1201a046c4..097a4fcb1a 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 @@ -22,7 +22,7 @@ public class NettyPerRequestTimeoutTest extends PerRequestTimeoutTest { protected void checkTimeoutMessage(String message) { - assertTrue(message.startsWith("Request reached timeout of 100 ms after ")); + assertTrue(message.equals("Request timeout of 100 ms")); } @Override From c041a2d2f0b843b4bb99cf5e6eee71e0755a0e86 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 7 Feb 2014 16:32:43 +0100 Subject: [PATCH 222/701] Backport #476 on 1.8.x --- .../com/ning/http/client/AsyncHttpClient.java | 20 +- .../http/client/AsyncHttpClientConfig.java | 36 +- .../java/com/ning/http/client/Cookie.java | 396 ---------------- .../java/com/ning/http/client/Request.java | 2 + .../com/ning/http/client/RequestBuilder.java | 5 +- .../ning/http/client/RequestBuilderBase.java | 15 +- .../java/com/ning/http/client/Response.java | 2 + .../http/client/SimpleAsyncHttpClient.java | 19 +- .../com/ning/http/client/cookie/Cookie.java | 174 +++++++ .../http/client/cookie/CookieDecoder.java | 175 +++++++ .../http/client/cookie/CookieEncoder.java | 47 ++ .../client/cookie/KeyValuePairsParser.java | 220 +++++++++ .../client/date/CalendarTimeConverter.java | 41 ++ .../ning/http/client/date/RFC2616Date.java | 144 ++++++ .../http/client/date/RFC2616DateParser.java | 434 ++++++++++++++++++ .../ning/http/client/date/TimeConverter.java | 23 + .../apache/ApacheAsyncHttpProvider.java | 4 +- .../providers/apache/ApacheResponse.java | 8 +- .../grizzly/GrizzlyAsyncHttpProvider.java | 130 +++--- .../providers/grizzly/GrizzlyResponse.java | 36 +- .../providers/jdk/JDKAsyncHttpProvider.java | 79 ++-- .../client/providers/jdk/JDKResponse.java | 7 +- .../netty/NettyAsyncHttpProvider.java | 195 ++++---- .../client/providers/netty/NettyResponse.java | 7 +- .../http/client/webdav/WebDavResponse.java | 11 +- .../http/util/AsyncHttpProviderUtils.java | 89 +--- .../handler/codec/http/CookieDecoder.java | 309 ------------- .../handler/codec/http/CookieEncoder.java | 162 ------- .../handler/codec/http/CookieHeaderNames.java | 45 -- .../handler/codec/http/HttpConstants.java | 75 --- .../jboss/netty/util/internal/StringUtil.java | 73 --- .../client/async/AsyncProvidersBasicTest.java | 6 +- .../http/client/async/RemoteSiteTest.java | 26 +- .../http/client/cookie/CookieDecoderTest.java | 47 ++ .../client/date/RFC2616DateParserTest.java | 109 +++++ .../netty/NettyAsyncResponseTest.java | 17 +- .../handler/codec/http/CookieDecoderTest.java | 52 --- 37 files changed, 1741 insertions(+), 1499 deletions(-) delete mode 100644 src/main/java/com/ning/http/client/Cookie.java create mode 100644 src/main/java/com/ning/http/client/cookie/Cookie.java create mode 100644 src/main/java/com/ning/http/client/cookie/CookieDecoder.java create mode 100644 src/main/java/com/ning/http/client/cookie/CookieEncoder.java create mode 100644 src/main/java/com/ning/http/client/cookie/KeyValuePairsParser.java create mode 100644 src/main/java/com/ning/http/client/date/CalendarTimeConverter.java create mode 100644 src/main/java/com/ning/http/client/date/RFC2616Date.java create mode 100644 src/main/java/com/ning/http/client/date/RFC2616DateParser.java create mode 100644 src/main/java/com/ning/http/client/date/TimeConverter.java delete mode 100644 src/main/java/com/ning/org/jboss/netty/handler/codec/http/CookieDecoder.java delete mode 100644 src/main/java/com/ning/org/jboss/netty/handler/codec/http/CookieEncoder.java delete mode 100644 src/main/java/com/ning/org/jboss/netty/handler/codec/http/CookieHeaderNames.java delete mode 100644 src/main/java/com/ning/org/jboss/netty/handler/codec/http/HttpConstants.java delete mode 100644 src/main/java/com/ning/org/jboss/netty/util/internal/StringUtil.java create mode 100644 src/test/java/com/ning/http/client/cookie/CookieDecoderTest.java create mode 100644 src/test/java/com/ning/http/client/date/RFC2616DateParserTest.java delete mode 100644 src/test/java/com/ning/org/jboss/netty/handler/codec/http/CookieDecoderTest.java diff --git a/src/main/java/com/ning/http/client/AsyncHttpClient.java b/src/main/java/com/ning/http/client/AsyncHttpClient.java index e26c4559f6..a2e86d9965 100755 --- a/src/main/java/com/ning/http/client/AsyncHttpClient.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClient.java @@ -16,15 +16,6 @@ */ package com.ning.http.client; -import com.ning.http.client.Request.EntityWriter; -import com.ning.http.client.filter.FilterContext; -import com.ning.http.client.filter.FilterException; -import com.ning.http.client.filter.RequestFilter; -import com.ning.http.client.providers.jdk.JDKAsyncHttpProvider; -import com.ning.http.client.resumable.ResumableAsyncHandler; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import java.io.Closeable; import java.io.IOException; import java.io.InputStream; @@ -36,6 +27,17 @@ import java.util.concurrent.Future; import java.util.concurrent.atomic.AtomicBoolean; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.ning.http.client.Request.EntityWriter; +import com.ning.http.client.cookie.Cookie; +import com.ning.http.client.filter.FilterContext; +import com.ning.http.client.filter.FilterException; +import com.ning.http.client.filter.RequestFilter; +import com.ning.http.client.providers.jdk.JDKAsyncHttpProvider; +import com.ning.http.client.resumable.ResumableAsyncHandler; + /** * This class support asynchronous and synchronous HTTP request. *

    diff --git a/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java b/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java index 8af1daabbb..31ddb60488 100644 --- a/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java @@ -15,6 +15,7 @@ */ package com.ning.http.client; +import com.ning.http.client.date.TimeConverter; import com.ning.http.client.filter.IOExceptionFilter; import com.ning.http.client.filter.RequestFilter; import com.ning.http.client.filter.ResponseFilter; @@ -24,6 +25,7 @@ import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLEngine; + import java.security.GeneralSecurityException; import java.util.Collections; import java.util.LinkedList; @@ -84,7 +86,7 @@ public class AsyncHttpClientConfig { protected boolean strict302Handling; protected boolean useRelativeURIsWithSSLProxies; protected int maxConnectionLifeTimeInMs; - protected boolean rfc6265CookieEncoding; + protected TimeConverter timeConverter; protected AsyncHttpClientConfig() { } @@ -120,7 +122,7 @@ private AsyncHttpClientConfig(int maxTotalConnections, int ioThreadMultiplier, boolean strict302Handling, boolean useRelativeURIsWithSSLProxies, - boolean rfc6265CookieEncoding) { + TimeConverter timeConverter) { this.maxTotalConnections = maxTotalConnections; this.maxConnectionPerHost = maxConnectionPerHost; @@ -151,7 +153,6 @@ private AsyncHttpClientConfig(int maxTotalConnections, this.ioThreadMultiplier = ioThreadMultiplier; this.strict302Handling = strict302Handling; this.useRelativeURIsWithSSLProxies = useRelativeURIsWithSSLProxies; - this.rfc6265CookieEncoding = rfc6265CookieEncoding; if (applicationThreadPool == null) { this.applicationThreadPool = Executors.newCachedThreadPool(); @@ -160,6 +161,7 @@ private AsyncHttpClientConfig(int maxTotalConnections, } this.proxyServerSelector = proxyServerSelector; this.useRawUrl = useRawUrl; + this.timeConverter = timeConverter; } /** @@ -512,13 +514,10 @@ public int getMaxConnectionLifeTimeInMs() { } /** - * @returntrue if AHC should use rfc6265 for encoding client side cookies, - * otherwise false. - * - * @since 1.7.18 + * @return 1.8.2 */ - public boolean isRfc6265CookieEncoding() { - return rfc6265CookieEncoding; + public TimeConverter getTimeConverter() { + return timeConverter; } /** @@ -559,7 +558,7 @@ public static class Builder { private HostnameVerifier hostnameVerifier = new AllowAllHostnameVerifier(); private int ioThreadMultiplier = 2; private boolean strict302Handling; - private boolean rfc6265CookieEncoding; + private TimeConverter timeConverter; public Builder() { } @@ -1029,17 +1028,8 @@ 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; + public void setTimeConverter(TimeConverter timeConverter) { + this.timeConverter = timeConverter; } /** @@ -1084,7 +1074,7 @@ public Builder(AsyncHttpClientConfig prototype) { removeQueryParamOnRedirect = prototype.isRemoveQueryParamOnRedirect(); hostnameVerifier = prototype.getHostnameVerifier(); strict302Handling = prototype.isStrict302Handling(); - rfc6265CookieEncoding = prototype.isRfc6265CookieEncoding(); + timeConverter = prototype.timeConverter; } /** @@ -1149,7 +1139,7 @@ public Thread newThread(Runnable r) { ioThreadMultiplier, strict302Handling, useRelativeURIsWithSSLProxies, - rfc6265CookieEncoding); + timeConverter); } } } diff --git a/src/main/java/com/ning/http/client/Cookie.java b/src/main/java/com/ning/http/client/Cookie.java deleted file mode 100644 index 30aa3b2baf..0000000000 --- a/src/main/java/com/ning/http/client/Cookie.java +++ /dev/null @@ -1,396 +0,0 @@ -/* - * 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.util.Collections; -import java.util.Set; -import java.util.TreeSet; - -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; - 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; - - public Cookie(String domain, String name, String value, String path, int maxAge, boolean secure) { - this(domain, name, value, path, maxAge, secure, 1); - } - - public Cookie(String domain, String name, String value, String path, int maxAge, boolean secure, int version) { - this(domain, name, value, value, path, maxAge, secure, version, false, false, null, null, Collections. emptySet()); - } - - 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"); - } - 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.rawValue = rawValue; - 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() { - return domain; - } - - public String getName() { - return name == null ? "" : name; - } - - public String getValue() { - return value == null ? "" : value; - } - - public String getRawValue() { - return rawValue; - } - - public String getPath() { - return path; - } - - public int getMaxAge() { - return maxAge; - } - - public boolean isSecure() { - return secure; - } - - 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); - } - return unmodifiablePorts; - } - - @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) { - throw new IllegalArgumentException("port out of range: " + p); - } - newPorts.add(Integer.valueOf(p)); - } - if (newPorts.isEmpty()) { - unmodifiablePorts = this.ports = Collections.emptySet(); - } else { - this.ports = newPorts; - unmodifiablePorts = null; - } - } - - @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); - } - - 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; - } - - public static class CookieBuilder { - - private final String name; - private final String value; - private final String rawValue; - private String domain; - private String path; - private int maxAge = -1; - private boolean secure; - private int version; - private boolean httpOnly; - private boolean discard; - private String comment; - private String commentUrl; - private Set ports; - private boolean domainNotSet = true; - private boolean pathNotSet = true; - private boolean maxAgeNotSet = true; - private boolean secureNotSet = true; - private boolean versionNotSet = true; - private boolean httpOnlyNotSet = true; - private boolean discardNotSet = true; - private boolean commentNotSet = true; - private boolean commentUrlNotSet = true; - private boolean portsNotSet = true; - - public CookieBuilder(String name, String value, String rawValue) { - this.name = name; - this.value = value; - this.rawValue = rawValue; - } - - public Cookie build() { - return new Cookie(domain, name, value, rawValue, path, maxAge, secure, version, httpOnly, discard, comment, commentUrl, ports); - } - - public void setDomain(String domain) { - this.domain = domain; - domainNotSet = false; - } - - public void setPath(String path) { - this.path = path; - pathNotSet = false; - } - - public void setMaxAge(int maxAge) { - this.maxAge = maxAge; - maxAgeNotSet = false; - } - - public void setSecure(boolean secure) { - this.secure = secure; - secureNotSet = false; - } - - public void setVersion(int version) { - this.version = version; - versionNotSet = false; - } - - public void setHttpOnly(boolean httpOnly) { - this.httpOnly = httpOnly; - httpOnlyNotSet = false; - } - - public void setDiscard(boolean discard) { - this.discard = discard; - discardNotSet = false; - } - - public void setComment(String comment) { - this.comment = comment; - commentNotSet = false; - } - - public void setCommentUrl(String commentUrl) { - this.commentUrl = commentUrl; - commentNotSet = false; - } - - public void setPorts(Set ports) { - this.ports = ports; - portsNotSet = false; - } - - public boolean isDomainNotSet() { - return domainNotSet; - } - - public boolean isPathNotSet() { - return pathNotSet; - } - - public boolean isMaxAgeNotSet() { - return maxAgeNotSet; - } - - public boolean isSecureNotSet() { - return secureNotSet; - } - - public boolean isVersionNotSet() { - return versionNotSet; - } - - public boolean isHttpOnlyNotSet() { - return httpOnlyNotSet; - } - - public boolean isDiscardNotSet() { - return discardNotSet; - } - - public boolean isCommentNotSet() { - return commentNotSet; - } - - public boolean isCommentUrlNotSet() { - return commentUrlNotSet; - } - - public boolean isPortsNotSet() { - return portsNotSet; - } - } -} diff --git a/src/main/java/com/ning/http/client/Request.java b/src/main/java/com/ning/http/client/Request.java index 8871dd6cc8..90b4d88074 100644 --- a/src/main/java/com/ning/http/client/Request.java +++ b/src/main/java/com/ning/http/client/Request.java @@ -25,6 +25,8 @@ import java.util.Collection; import java.util.List; +import com.ning.http.client.cookie.Cookie; + /** * The Request class can be used to construct HTTP request: *

    diff --git a/src/main/java/com/ning/http/client/RequestBuilder.java b/src/main/java/com/ning/http/client/RequestBuilder.java
    index 7bf55ee1a5..32d8ef5357 100644
    --- a/src/main/java/com/ning/http/client/RequestBuilder.java
    +++ b/src/main/java/com/ning/http/client/RequestBuilder.java
    @@ -15,12 +15,13 @@
      */
     package com.ning.http.client;
     
    -import com.ning.http.client.Request.EntityWriter;
    -
     import java.io.InputStream;
     import java.util.Collection;
     import java.util.Map;
     
    +import com.ning.http.client.Request.EntityWriter;
    +import com.ning.http.client.cookie.Cookie;
    +
     /**
      * Builder for a {@link Request}.
      * Warning: mutable and not thread-safe! Beware that it holds a reference on the Request instance it builds,
    diff --git a/src/main/java/com/ning/http/client/RequestBuilderBase.java b/src/main/java/com/ning/http/client/RequestBuilderBase.java
    index 71d3171b85..4fc7ebc4ab 100644
    --- a/src/main/java/com/ning/http/client/RequestBuilderBase.java
    +++ b/src/main/java/com/ning/http/client/RequestBuilderBase.java
    @@ -17,13 +17,6 @@
     
     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;
    -
     import java.io.File;
     import java.io.InputStream;
     import java.io.UnsupportedEncodingException;
    @@ -38,6 +31,14 @@
     import java.util.Map;
     import java.util.Map.Entry;
     
    +import org.slf4j.Logger;
    +import org.slf4j.LoggerFactory;
    +
    +import com.ning.http.client.Request.EntityWriter;
    +import com.ning.http.client.cookie.Cookie;
    +import com.ning.http.util.AsyncHttpProviderUtils;
    +import com.ning.http.util.UTF8UrlEncoder;
    +
     /**
      * Builder for {@link Request}
      * 
    diff --git a/src/main/java/com/ning/http/client/Response.java b/src/main/java/com/ning/http/client/Response.java
    index 458e6ad254..4d355e156c 100644
    --- a/src/main/java/com/ning/http/client/Response.java
    +++ b/src/main/java/com/ning/http/client/Response.java
    @@ -25,6 +25,8 @@
     import java.util.Collections;
     import java.util.List;
     
    +import com.ning.http.client.cookie.Cookie;
    +
     /**
      * Represents the asynchronous HTTP response callback for an {@link com.ning.http.client.AsyncCompletionHandler}
      */
    diff --git a/src/main/java/com/ning/http/client/SimpleAsyncHttpClient.java b/src/main/java/com/ning/http/client/SimpleAsyncHttpClient.java
    index aacfb6eb8d..711dbdf269 100644
    --- a/src/main/java/com/ning/http/client/SimpleAsyncHttpClient.java
    +++ b/src/main/java/com/ning/http/client/SimpleAsyncHttpClient.java
    @@ -12,20 +12,23 @@
      */
     package com.ning.http.client;
     
    -import com.ning.http.client.resumable.ResumableAsyncHandler;
    -import com.ning.http.client.resumable.ResumableIOExceptionFilter;
    -import com.ning.http.client.simple.HeaderMap;
    -import com.ning.http.client.simple.SimpleAHCTransferListener;
    -import org.slf4j.Logger;
    -import org.slf4j.LoggerFactory;
    -
    -import javax.net.ssl.SSLContext;
     import java.io.IOException;
     import java.util.Collection;
     import java.util.Map;
     import java.util.concurrent.ExecutorService;
     import java.util.concurrent.Future;
     
    +import javax.net.ssl.SSLContext;
    +
    +import org.slf4j.Logger;
    +import org.slf4j.LoggerFactory;
    +
    +import com.ning.http.client.cookie.Cookie;
    +import com.ning.http.client.resumable.ResumableAsyncHandler;
    +import com.ning.http.client.resumable.ResumableIOExceptionFilter;
    +import com.ning.http.client.simple.HeaderMap;
    +import com.ning.http.client.simple.SimpleAHCTransferListener;
    +
     /**
      * Simple implementation of {@link AsyncHttpClient} and it's related builders ({@link com.ning.http.client.AsyncHttpClientConfig},
      * {@link Realm}, {@link com.ning.http.client.ProxyServer} and {@link com.ning.http.client.AsyncHandler}. You can
    diff --git a/src/main/java/com/ning/http/client/cookie/Cookie.java b/src/main/java/com/ning/http/client/cookie/Cookie.java
    new file mode 100644
    index 0000000000..80679e13a0
    --- /dev/null
    +++ b/src/main/java/com/ning/http/client/cookie/Cookie.java
    @@ -0,0 +1,174 @@
    +/*
    + * Copyright (c) 2014 AsyncHttpClient Project. 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.cookie;
    +
    +public class Cookie {
    +
    +    public static Cookie newValidCookie(String domain, String name, String value, String rawValue, String path, long expires, int maxAge, boolean secure, boolean httpOnly) {
    +
    +        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");
    +        }
    +
    +        domain = validateValue("domain", domain);
    +        path = validateValue("path", path);
    +
    +        return new Cookie(domain, name, value, rawValue, path, expires, maxAge, secure, httpOnly);
    +    }
    +
    +    private static 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;
    +    }
    +
    +    private final String domain;
    +    private final String name;
    +    private final String value;
    +    private final String rawValue;
    +    private final String path;
    +    private long expires;
    +    private final int maxAge;
    +    private final boolean secure;
    +    private final boolean httpOnly;
    +
    +    public Cookie(String domain, String name, String value, String rawValue, String path, long expires, int maxAge, boolean secure, boolean httpOnly) {
    +        this.domain = domain;
    +        this.name = name;
    +        this.value = value;
    +        this.rawValue = rawValue;
    +        this.path = path;
    +        this.expires = expires;
    +        this.maxAge = maxAge;
    +        this.secure = secure;
    +        this.httpOnly = httpOnly;
    +    }
    +
    +    public String getDomain() {
    +        return domain;
    +    }
    +
    +    public String getName() {
    +        return name;
    +    }
    +
    +    public String getValue() {
    +        return value;
    +    }
    +
    +    public String getRawValue() {
    +        return rawValue;
    +    }
    +
    +    public String getPath() {
    +        return path;
    +    }
    +
    +    public long getExpires() {
    +        return expires;
    +    }
    +    
    +    public int getMaxAge() {
    +        return maxAge;
    +    }
    +
    +    public boolean isSecure() {
    +        return secure;
    +    }
    +
    +    public boolean isHttpOnly() {
    +        return httpOnly;
    +    }
    +
    +    @Override
    +    public String toString() {
    +        StringBuilder buf = new StringBuilder();
    +        buf.append(name);
    +        buf.append("=");
    +        buf.append(rawValue);
    +        if (domain != null) {
    +            buf.append("; domain=");
    +            buf.append(domain);
    +        }
    +        if (path != null) {
    +            buf.append("; path=");
    +            buf.append(path);
    +        }
    +        if (expires >= 0) {
    +            buf.append("; expires=");
    +            buf.append(expires);
    +        }
    +        if (maxAge >= 0) {
    +            buf.append("; maxAge=");
    +            buf.append(maxAge);
    +            buf.append("s");
    +        }
    +        if (secure) {
    +            buf.append("; secure");
    +        }
    +        if (httpOnly) {
    +            buf.append("; HTTPOnly");
    +        }
    +        return buf.toString();
    +    }
    +}
    diff --git a/src/main/java/com/ning/http/client/cookie/CookieDecoder.java b/src/main/java/com/ning/http/client/cookie/CookieDecoder.java
    new file mode 100644
    index 0000000000..1be72981e1
    --- /dev/null
    +++ b/src/main/java/com/ning/http/client/cookie/CookieDecoder.java
    @@ -0,0 +1,175 @@
    +/*
    + * Copyright (c) 2014 AsyncHttpClient Project. 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.cookie;
    +
    +import com.ning.http.client.date.CalendarTimeConverter;
    +import com.ning.http.client.date.TimeConverter;
    +
    +public class CookieDecoder {
    +
    +    public static final TimeConverter DEFAULT_TIME_CONVERTER = new CalendarTimeConverter();
    +
    +    public static Cookie decode(String header) {
    +        return decode(header, DEFAULT_TIME_CONVERTER);
    +    }
    +
    +    /**
    +     * Decodes the specified HTTP header value into {@link Cookie}.
    +     * 
    +     * @return the decoded {@link Cookie}
    +     */
    +    public static Cookie decode(String header, TimeConverter timeConverter) {
    +
    +        if (timeConverter == null)
    +            timeConverter = DEFAULT_TIME_CONVERTER;
    +
    +        if (header.length() == 0)
    +            return null;
    +
    +        KeyValuePairsParser pairsParser = new KeyValuePairsParser(timeConverter);
    +
    +        final int headerLen = header.length();
    +        loop: for (int i = 0;;) {
    +
    +            // Skip spaces and separators.
    +            for (;;) {
    +                if (i == headerLen) {
    +                    break loop;
    +                }
    +                char c = header.charAt(i);
    +                if (c == ',') {
    +                    // Having multiple cookies in a single Set-Cookie header is
    +                    // deprecated, modern browsers only parse the first one
    +                    break loop;
    +
    +                } else if (c == '\t' || c == '\n' || c == 0x0b || c == '\f' || c == '\r' || c == ' ' || c == ';') {
    +                    i++;
    +                    continue;
    +                }
    +                break;
    +            }
    +
    +            int newNameStart = i;
    +            int newNameEnd = i;
    +            String value;
    +            String rawValue;
    +            boolean first = true;
    +
    +            if (i == headerLen) {
    +                value = rawValue = null;
    +            } else {
    +                keyValLoop: for (;;) {
    +
    +                    char curChar = header.charAt(i);
    +                    if (curChar == ';') {
    +                        // NAME; (no value till ';')
    +                        newNameEnd = i;
    +                        value = rawValue = null;
    +                        first = false;
    +                        break keyValLoop;
    +                    } else if (curChar == '=') {
    +                        // NAME=VALUE
    +                        newNameEnd = i;
    +                        i++;
    +                        if (i == headerLen) {
    +                            // NAME= (empty value, i.e. nothing after '=')
    +                            value = rawValue = "";
    +                            first = false;
    +                            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);
    +
    +                            int rawValueStart = i;
    +                            int rawValueEnd = i;
    +
    +                            final char q = c;
    +                            boolean hadBackslash = false;
    +                            i++;
    +                            for (;;) {
    +                                if (i == headerLen) {
    +                                    value = newValueBuf.toString();
    +                                    // only need to compute raw value for cookie
    +                                    // value which is at most in 2nd position
    +                                    rawValue = first ? header.substring(rawValueStart, rawValueEnd) : null;
    +                                    first = false;
    +                                    break keyValLoop;
    +                                }
    +                                if (hadBackslash) {
    +                                    hadBackslash = false;
    +                                    c = header.charAt(i++);
    +                                    rawValueEnd = 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++);
    +                                    rawValueEnd = i;
    +                                    if (c == q) {
    +                                        value = newValueBuf.toString();
    +                                        // only need to compute raw value for
    +                                        // cookie value which is at most in 2nd
    +                                        // position
    +                                        rawValue = first ? header.substring(rawValueStart, rawValueEnd) : null;
    +                                        first = false;
    +                                        break keyValLoop;
    +                                    }
    +                                    newValueBuf.append(c);
    +                                    if (c == '\\') {
    +                                        hadBackslash = true;
    +                                    }
    +                                }
    +                            }
    +                        } else {
    +                            // NAME=VALUE;
    +                            int semiPos = header.indexOf(';', i);
    +                            if (semiPos > 0) {
    +                                value = rawValue = header.substring(newValueStart, semiPos);
    +                                i = semiPos;
    +                            } else {
    +                                value = rawValue = header.substring(newValueStart);
    +                                i = headerLen;
    +                            }
    +                        }
    +                        break keyValLoop;
    +                    } else {
    +                        i++;
    +                    }
    +
    +                    if (i == headerLen) {
    +                        // NAME (no value till the end of string)
    +                        newNameEnd = headerLen;
    +                        first = false;
    +                        value = rawValue = null;
    +                        break;
    +                    }
    +                }
    +            }
    +
    +            pairsParser.parseKeyValuePair(header, newNameStart, newNameEnd, value, rawValue);
    +        }
    +        return pairsParser.cookie();
    +    }
    +}
    diff --git a/src/main/java/com/ning/http/client/cookie/CookieEncoder.java b/src/main/java/com/ning/http/client/cookie/CookieEncoder.java
    new file mode 100644
    index 0000000000..3003fd90c4
    --- /dev/null
    +++ b/src/main/java/com/ning/http/client/cookie/CookieEncoder.java
    @@ -0,0 +1,47 @@
    +/*
    + * Copyright (c) 2014 AsyncHttpClient Project. 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.cookie;
    +
    +import java.util.Collection;
    +
    +public final class CookieEncoder {
    +
    +    private CookieEncoder() {
    +    }
    +
    +    public static String encode(Collection cookies) {
    +        StringBuilder sb = new StringBuilder();
    +
    +        for (Cookie cookie : cookies) {
    +            add(sb, cookie.getName(), cookie.getRawValue());
    +        }
    +
    +        if (sb.length() > 0) {
    +            sb.setLength(sb.length() - 2);
    +        }
    +        return sb.toString();
    +    }
    +
    +    private static void add(StringBuilder sb, String name, String val) {
    +
    +        if (val == null) {
    +            val = "";
    +        }
    +
    +        sb.append(name);
    +        sb.append('=');
    +        sb.append(val);
    +        sb.append(';');
    +        sb.append(' ');
    +    }
    +}
    diff --git a/src/main/java/com/ning/http/client/cookie/KeyValuePairsParser.java b/src/main/java/com/ning/http/client/cookie/KeyValuePairsParser.java
    new file mode 100644
    index 0000000000..f01b97e1a0
    --- /dev/null
    +++ b/src/main/java/com/ning/http/client/cookie/KeyValuePairsParser.java
    @@ -0,0 +1,220 @@
    +/*
    + * Copyright (c) 2014 AsyncHttpClient Project. 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.cookie;
    +
    +import com.ning.http.client.date.RFC2616Date;
    +import com.ning.http.client.date.RFC2616DateParser;
    +import com.ning.http.client.date.TimeConverter;
    +
    +/**
    + * A companion for CookieDecoder that parses key-value pairs (cookie name/value
    + * and attributes).
    + * 
    + * @author slandelle
    + */
    +class KeyValuePairsParser {
    +
    +    private final TimeConverter timeBuilder;
    +    private String name;
    +    private String value;
    +    private String rawValue;
    +    private String domain;
    +    private String path;
    +    private long expires = -1L;
    +    private int maxAge = -1;
    +    private boolean secure;
    +    private boolean httpOnly;
    +
    +    /**
    +     * @param timeBuilder used for parsing expires attribute
    +     */
    +    public KeyValuePairsParser(TimeConverter timeBuilder) {
    +        this.timeBuilder = timeBuilder;
    +    }
    +
    +    public Cookie cookie() {
    +        return name != null ? new Cookie(domain, name, value, rawValue, path, expires, maxAge, secure, httpOnly) : null;
    +    }
    +
    +    /**
    +     * Parse and store a key-value pair. First one is considered to be the
    +     * cookie name/value. Unknown attribute names are silently discarded.
    +     * 
    +     * @param header the HTTP header
    +     * @param keyStart where the key starts in the header
    +     * @param keyEnd where the key ends in the header
    +     * @param value the decoded value
    +     * @param rawValue the raw value (only non null for cookie value)
    +     */
    +    public void parseKeyValuePair(String header, int keyStart, int keyEnd, String value, String rawValue) {
    +
    +        if (name == null)
    +            setCookieNameValue(header, keyStart, keyEnd, value, rawValue);
    +        else
    +            setCookieAttribute(header, keyStart, keyEnd, value);
    +    }
    +
    +    private void setCookieNameValue(String header, int keyStart, int keyEnd, String value, String rawValue) {
    +        name = header.substring(keyStart, keyEnd);
    +        this.value = value;
    +        this.rawValue = rawValue;
    +    }
    +
    +    private void setCookieAttribute(String header, int keyStart, int keyEnd, String value) {
    +
    +        int length = keyEnd - keyStart;
    +
    +        if (length == 4)
    +            parse4(header, keyStart, value);
    +        else if (length == 6)
    +            parse6(header, keyStart, value);
    +        else if (length == 7)
    +            parse7(header, keyStart, value);
    +        else if (length == 8)
    +            parse8(header, keyStart, value);
    +    }
    +
    +    private boolean isPath(char c0, char c1, char c2, char c3) {
    +        return (c0 == 'P' || c0 == 'p') && //
    +                (c1 == 'a' || c1 == 'A') && //
    +                (c2 == 't' || c2 == 'T') && //
    +                (c3 == 'h' || c3 == 'H');
    +    }
    +
    +    private void parse4(String header, int nameStart, String value) {
    +
    +        char c0 = header.charAt(nameStart);
    +        char c1 = header.charAt(nameStart + 1);
    +        char c2 = header.charAt(nameStart + 2);
    +        char c3 = header.charAt(nameStart + 3);
    +
    +        if (isPath(c0, c1, c2, c3))
    +            path = value;
    +    }
    +
    +    private boolean isDomain(char c0, char c1, char c2, char c3, char c4, char c5) {
    +        return (c0 == 'D' || c0 == 'd') && //
    +                (c1 == 'o' || c1 == 'O') && //
    +                (c2 == 'm' || c2 == 'M') && //
    +                (c3 == 'a' || c3 == 'A') && //
    +                (c4 == 'i' || c4 == 'I') && //
    +                (c5 == 'n' || c5 == 'N');
    +    }
    +
    +    private boolean isSecure(char c0, char c1, char c2, char c3, char c4, char c5) {
    +        return (c0 == 'S' || c0 == 's') && //
    +                (c1 == 'e' || c1 == 'E') && //
    +                (c2 == 'c' || c2 == 'C') && //
    +                (c3 == 'u' || c3 == 'U') && //
    +                (c4 == 'r' || c4 == 'R') && //
    +                (c5 == 'e' || c5 == 'E');
    +    }
    +
    +    private void parse6(String header, int nameStart, String value) {
    +
    +        char c0 = header.charAt(nameStart);
    +        char c1 = header.charAt(nameStart + 1);
    +        char c2 = header.charAt(nameStart + 2);
    +        char c3 = header.charAt(nameStart + 3);
    +        char c4 = header.charAt(nameStart + 4);
    +        char c5 = header.charAt(nameStart + 5);
    +
    +        if (isDomain(c0, c1, c2, c3, c4, c5))
    +            domain = value;
    +        else if (isSecure(c0, c1, c2, c3, c4, c5))
    +            secure = true;
    +    }
    +
    +    private boolean isExpires(char c0, char c1, char c2, char c3, char c4, char c5, char c6) {
    +        return (c0 == 'E' || c0 == 'e') && //
    +                (c1 == 'x' || c1 == 'X') && //
    +                (c2 == 'p' || c2 == 'P') && //
    +                (c3 == 'i' || c3 == 'I') && //
    +                (c4 == 'r' || c4 == 'R') && //
    +                (c5 == 'e' || c5 == 'E') && //
    +                (c6 == 's' || c6 == 'S');
    +    }
    +
    +    private boolean isMaxAge(char c0, char c1, char c2, char c3, char c4, char c5, char c6) {
    +        return (c0 == 'M' || c0 == 'm') && //
    +                (c1 == 'a' || c1 == 'A') && //
    +                (c2 == 'x' || c2 == 'X') && //
    +                (c3 == '-') && //
    +                (c4 == 'A' || c4 == 'a') && //
    +                (c5 == 'g' || c5 == 'G') && //
    +                (c6 == 'e' || c6 == 'E');
    +    }
    +
    +    private void setExpire(String value) {
    +
    +        RFC2616Date dateElements = new RFC2616DateParser(value).parse();
    +        if (dateElements != null) {
    +            try {
    +                expires = timeBuilder.toTime(dateElements);
    +            } catch (Exception e1) {
    +                // ignore failure to parse -> treat as session cookie
    +            }
    +        }
    +    }
    +
    +    private void setMaxAge(String value) {
    +        try {
    +            maxAge = Math.max(Integer.valueOf(value), 0);
    +        } catch (NumberFormatException e1) {
    +            // ignore failure to parse -> treat as session cookie
    +        }
    +    }
    +
    +    private void parse7(String header, int nameStart, String value) {
    +
    +        char c0 = header.charAt(nameStart);
    +        char c1 = header.charAt(nameStart + 1);
    +        char c2 = header.charAt(nameStart + 2);
    +        char c3 = header.charAt(nameStart + 3);
    +        char c4 = header.charAt(nameStart + 4);
    +        char c5 = header.charAt(nameStart + 5);
    +        char c6 = header.charAt(nameStart + 6);
    +
    +        if (isExpires(c0, c1, c2, c3, c4, c5, c6))
    +            setExpire(value);
    +
    +        else if (isMaxAge(c0, c1, c2, c3, c4, c5, c6))
    +            setMaxAge(value);
    +    }
    +
    +    private boolean isHttpOnly(char c0, char c1, char c2, char c3, char c4, char c5, char c6, char c7) {
    +        return (c0 == 'H' || c0 == 'h') && //
    +                (c1 == 't' || c1 == 'T') && //
    +                (c2 == 't' || c2 == 'T') && //
    +                (c3 == 'p' || c3 == 'P') && //
    +                (c4 == 'O' || c4 == 'o') && //
    +                (c5 == 'n' || c5 == 'N') && //
    +                (c6 == 'l' || c6 == 'L') && //
    +                (c7 == 'y' || c7 == 'Y');
    +    }
    +
    +    private void parse8(String header, int nameStart, String value) {
    +
    +        char c0 = header.charAt(nameStart);
    +        char c1 = header.charAt(nameStart + 1);
    +        char c2 = header.charAt(nameStart + 2);
    +        char c3 = header.charAt(nameStart + 3);
    +        char c4 = header.charAt(nameStart + 4);
    +        char c5 = header.charAt(nameStart + 5);
    +        char c6 = header.charAt(nameStart + 6);
    +        char c7 = header.charAt(nameStart + 7);
    +
    +        if (isHttpOnly(c0, c1, c2, c3, c4, c5, c6, c7))
    +            httpOnly = true;
    +    }
    +}
    diff --git a/src/main/java/com/ning/http/client/date/CalendarTimeConverter.java b/src/main/java/com/ning/http/client/date/CalendarTimeConverter.java
    new file mode 100644
    index 0000000000..270c6d9ecd
    --- /dev/null
    +++ b/src/main/java/com/ning/http/client/date/CalendarTimeConverter.java
    @@ -0,0 +1,41 @@
    +/*
    + * Copyright (c) 2010-2014 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.date;
    +
    +import java.util.Calendar;
    +import java.util.GregorianCalendar;
    +import java.util.TimeZone;
    +
    +/**
    + * Calendar based TimeConverter.
    + * Note that a Joda-Time or DateTime based implementation would be more efficient, but AHC doesn't have a dependency to JodaTime.
    + * 
    + * @author slandelle
    + */
    +public class CalendarTimeConverter implements TimeConverter {
    +
    +    public static final TimeZone GMT = TimeZone.getTimeZone("GMT");
    +
    +    public long toTime(RFC2616Date dateElements) {
    +
    +        Calendar calendar = new GregorianCalendar(//
    +                dateElements.year(), //
    +                dateElements.month() - 1, // beware, Calendar use months from 0 to 11
    +                dateElements.dayOfMonth(), //
    +                dateElements.hour(), //
    +                dateElements.minute(), //
    +                dateElements.second());
    +        calendar.setTimeZone(GMT);
    +        return calendar.getTimeInMillis();
    +    }
    +}
    diff --git a/src/main/java/com/ning/http/client/date/RFC2616Date.java b/src/main/java/com/ning/http/client/date/RFC2616Date.java
    new file mode 100644
    index 0000000000..7a977c1b78
    --- /dev/null
    +++ b/src/main/java/com/ning/http/client/date/RFC2616Date.java
    @@ -0,0 +1,144 @@
    +/*
    + * Copyright (c) 2010-2014 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.date;
    +
    +/**
    + * A placeholder for RFC2616 date elements
    + * 
    + * @author slandelle
    + */
    +public final class RFC2616Date {
    +
    +    private final int year;
    +    // 1 to 12
    +    private final int month;
    +    private final int dayOfMonth;
    +    private final int hour;
    +    private final int minute;
    +    private final int second;
    +
    +    public RFC2616Date(int year, int month, int dayOfMonth, int hour, int minute, int second) {
    +        this.year = year;
    +        this.month = month;
    +        this.dayOfMonth = dayOfMonth;
    +        this.hour = hour;
    +        this.minute = minute;
    +        this.second = second;
    +    }
    +
    +    public int year() {
    +        return year;
    +    }
    +
    +    public int month() {
    +        return month;
    +    }
    +
    +    public int dayOfMonth() {
    +        return dayOfMonth;
    +    }
    +
    +    public int hour() {
    +        return hour;
    +    }
    +
    +    public int minute() {
    +        return minute;
    +    }
    +
    +    public int second() {
    +        return second;
    +    }
    +
    +    public static final class Builder {
    +
    +        private int dayOfMonth;
    +        private int month;
    +        private int year;
    +        private int hour;
    +        private int minute;
    +        private int second;
    +
    +        public void setDayOfMonth(int dayOfMonth) {
    +            this.dayOfMonth = dayOfMonth;
    +        }
    +
    +        public void setJanuary() {
    +            month = 1;
    +        }
    +
    +        public void setFebruary() {
    +            month = 2;
    +        }
    +
    +        public void setMarch() {
    +            month = 3;
    +        }
    +
    +        public void setApril() {
    +            month = 4;
    +        }
    +
    +        public void setMay() {
    +            month = 5;
    +        }
    +
    +        public void setJune() {
    +            month = 6;
    +        }
    +
    +        public void setJuly() {
    +            month = 7;
    +        }
    +
    +        public void setAugust() {
    +            month = 8;
    +        }
    +
    +        public void setSeptember() {
    +            month = 9;
    +        }
    +
    +        public void setOctobre() {
    +            month = 10;
    +        }
    +
    +        public void setNovembre() {
    +            month = 11;
    +        }
    +
    +        public void setDecember() {
    +            month = 12;
    +        }
    +
    +        public void setYear(int year) {
    +            this.year = year;
    +        }
    +
    +        public void setHour(int hour) {
    +            this.hour = hour;
    +        }
    +
    +        public void setMinute(int minute) {
    +            this.minute = minute;
    +        }
    +
    +        public void setSecond(int second) {
    +            this.second = second;
    +        }
    +
    +        public RFC2616Date build() {
    +            return new RFC2616Date(year, month, dayOfMonth, hour, minute, second);
    +        }
    +    }
    +}
    diff --git a/src/main/java/com/ning/http/client/date/RFC2616DateParser.java b/src/main/java/com/ning/http/client/date/RFC2616DateParser.java
    new file mode 100644
    index 0000000000..e04638fb8e
    --- /dev/null
    +++ b/src/main/java/com/ning/http/client/date/RFC2616DateParser.java
    @@ -0,0 +1,434 @@
    +/*
    + * Copyright (c) 2014 AsyncHttpClient Project. 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.date;
    +
    +import com.ning.http.client.date.RFC2616Date.Builder;
    +
    +/**
    + * A parser for RFC2616
    + * Date format.
    + * 
    + * @author slandelle
    + */
    +public class RFC2616DateParser {
    +
    +    private final String string;
    +    private final int offset;
    +    private final int length;
    +
    +    /**
    +     * @param string a string that will be fully parsed
    +     */
    +    public RFC2616DateParser(String string) {
    +        this(string, 0, string.length());
    +    }
    +
    +    /**
    +     * @param string the string to be parsed
    +     * @param offset the offset where to start parsing
    +     * @param length the number of chars to parse
    +     */
    +    public RFC2616DateParser(String string, int offset, int length) {
    +
    +        if (string.length() + offset < length)
    +            throw new IllegalArgumentException("String length doesn't match offset and length");
    +
    +        this.string = string;
    +        this.offset = offset;
    +        this.length = length;
    +    }
    +
    +    private static class Tokens {
    +        public final int[] starts;
    +        public final int[] ends;
    +        public final int length;
    +
    +        public Tokens(int[] starts, int[] ends, int length) {
    +            this.starts = starts;
    +            this.ends = ends;
    +            this.length = length;
    +        }
    +    }
    +
    +    private Tokens tokenize() {
    +
    +        int[] starts = new int[8];
    +        int[] ends = new int[8];
    +        boolean inToken = false;
    +        int tokenCount = 0;
    +
    +        int end = offset + length;
    +        for (int i = offset; i < end; i++) {
    +
    +            char c = string.charAt(i);
    +            if (c == ' ' || c == ',' || c == '-' || c == ':') {
    +                if (inToken) {
    +                    ends[tokenCount++] = i;
    +                    inToken = false;
    +                }
    +            } else if (!inToken) {
    +                starts[tokenCount] = i;
    +                inToken = true;
    +            }
    +        }
    +
    +        // finish lastToken
    +        if (inToken = true)
    +            ends[tokenCount++] = end;
    +
    +        return new Tokens(starts, ends, tokenCount);
    +    }
    +
    +    /**
    +     * @param validate if validation is to be enabled of non-critical elements,
    +     *            such as day of week and timezone
    +     * @return null is the string is not a valid RFC2616 date
    +     */
    +    public RFC2616Date parse() {
    +
    +        Tokens tokens = tokenize();
    +
    +        if (tokens.length != 7 && tokens.length != 8)
    +            return null;
    +
    +        // 1st token is ignored: ignore day of week
    +        // 8th token is ignored: supposed to always be GMT
    +
    +        if (isDigit(string.charAt(tokens.starts[1])))
    +            return buildDate(tokens);
    +        else
    +            return buildANSICDate(tokens);
    +    }
    +
    +    private RFC2616Date buildDate(Tokens tokens) {
    +
    +        // Sun, 06 Nov 1994 08:49:37 GMT
    +
    +        Builder dateBuilder = new Builder();
    +
    +        if (isValidDayOfMonth(tokens.starts[1], tokens.ends[1], dateBuilder) && //
    +                isValidMonth(tokens.starts[2], tokens.ends[2], dateBuilder) && //
    +                isValidYear(tokens.starts[3], tokens.ends[3], dateBuilder) && //
    +                isValidHour(tokens.starts[4], tokens.ends[4], dateBuilder) && //
    +                isValidMinuteSecond(tokens.starts[5], tokens.ends[5], dateBuilder, true) && //
    +                isValidMinuteSecond(tokens.starts[6], tokens.ends[6], dateBuilder, false)) {
    +            return dateBuilder.build();
    +        }
    +
    +        return null;
    +    }
    +
    +    private RFC2616Date buildANSICDate(Tokens tokens) {
    +
    +        // Sun Nov 6 08:49:37 1994
    +
    +        Builder dateBuilder = new Builder();
    +
    +        if (isValidMonth(tokens.starts[1], tokens.ends[1], dateBuilder) && //
    +                isValidDayOfMonth(tokens.starts[2], tokens.ends[2], dateBuilder) && //
    +                isValidHour(tokens.starts[3], tokens.ends[3], dateBuilder) && //
    +                isValidMinuteSecond(tokens.starts[4], tokens.ends[4], dateBuilder, true) && //
    +                isValidMinuteSecond(tokens.starts[5], tokens.ends[5], dateBuilder, false) && //
    +                isValidYear(tokens.starts[6], tokens.ends[6], dateBuilder)) {
    +            return dateBuilder.build();
    +        }
    +
    +        return null;
    +    }
    +
    +    private boolean isValid1DigitDayOfMonth(char c0, Builder dateBuilder) {
    +        if (isDigit(c0)) {
    +            dateBuilder.setDayOfMonth(getNumericValue(c0));
    +            return true;
    +        }
    +        return false;
    +    }
    +
    +    private boolean isValid2DigitsDayOfMonth(char c0, char c1, Builder dateBuilder) {
    +        if (isDigit(c0) && isDigit(c1)) {
    +            int i0 = getNumericValue(c0);
    +            int i1 = getNumericValue(c1);
    +            int day = i0 * 10 + i1;
    +            if (day <= 31) {
    +                dateBuilder.setDayOfMonth(day);
    +                return true;
    +            }
    +        }
    +        return false;
    +    }
    +
    +    private boolean isValidDayOfMonth(int start, int end, Builder dateBuilder) {
    +
    +        int tokenLength = end - start;
    +
    +        if (tokenLength == 1) {
    +            char c0 = string.charAt(start);
    +            return isValid1DigitDayOfMonth(c0, dateBuilder);
    +
    +        } else if (tokenLength == 2) {
    +            char c0 = string.charAt(start);
    +            char c1 = string.charAt(start + 1);
    +            return isValid2DigitsDayOfMonth(c0, c1, dateBuilder);
    +        }
    +        return false;
    +    }
    +
    +    private boolean isValidJanuaryJuneJuly(char c0, char c1, char c2, Builder dateBuilder) {
    +        if (c0 == 'J' || c0 == 'j')
    +            if (c1 == 'a' || c1 == 'A') {
    +                if (c2 == 'n' || c2 == 'N') {
    +                    dateBuilder.setJanuary();
    +                    return true;
    +                }
    +            } else if (c1 == 'u' || c1 == 'U') {
    +                if (c2 == 'n' || c2 == 'N') {
    +                    dateBuilder.setJune();
    +                    return true;
    +                } else if (c2 == 'l' || c2 == 'L') {
    +                    dateBuilder.setJuly();
    +                    return true;
    +                }
    +            }
    +        return false;
    +    }
    +
    +    private boolean isValidFebruary(char c0, char c1, char c2, Builder dateBuilder) {
    +        if ((c0 == 'F' || c0 == 'f') && (c1 == 'e' || c1 == 'E') && (c2 == 'b' || c2 == 'B')) {
    +            dateBuilder.setFebruary();
    +            return true;
    +        }
    +        return false;
    +    }
    +
    +    private boolean isValidMarchMay(char c0, char c1, char c2, Builder dateBuilder) {
    +        if ((c0 == 'M' || c0 == 'm') && (c1 == 'a' || c1 == 'A')) {
    +            if (c2 == 'r' || c2 == 'R') {
    +                dateBuilder.setMarch();
    +                return true;
    +            } else if (c2 == 'y' || c2 == 'M') {
    +                dateBuilder.setMay();
    +                return true;
    +            }
    +        }
    +        return false;
    +    }
    +
    +    private boolean isValidAprilAugust(char c0, char c1, char c2, Builder dateBuilder) {
    +        if (c0 == 'A' || c0 == 'a')
    +            if ((c1 == 'p' || c1 == 'P') && (c2 == 'r' || c2 == 'R')) {
    +                dateBuilder.setApril();
    +                return true;
    +            } else if ((c1 == 'u' || c1 == 'U') && (c2 == 'g' || c2 == 'G')) {
    +                dateBuilder.setAugust();
    +                return true;
    +            }
    +        return false;
    +    }
    +
    +    private boolean isValidSeptember(char c0, char c1, char c2, Builder dateBuilder) {
    +        if ((c0 == 'S' || c0 == 's') && (c1 == 'e' || c1 == 'E') && (c2 == 'p' || c2 == 'P')) {
    +            dateBuilder.setSeptember();
    +            return true;
    +        }
    +        return false;
    +    }
    +
    +    private boolean isValidOctober(char c0, char c1, char c2, Builder dateBuilder) {
    +        if ((c0 == 'O' || c0 == 'o') && (c1 == 'c' || c1 == 'C') && (c2 == 't' || c2 == 'T')) {
    +            dateBuilder.setOctobre();
    +            return true;
    +        }
    +        return false;
    +    }
    +
    +    private boolean isValidNovember(char c0, char c1, char c2, Builder dateBuilder) {
    +        if ((c0 == 'N' || c0 == 'n') && (c1 == 'o' || c1 == 'O') && (c2 == 'v' || c2 == 'V')) {
    +            dateBuilder.setNovembre();
    +            return true;
    +        }
    +        return false;
    +    }
    +
    +    private boolean isValidDecember(char c0, char c1, char c2, Builder dateBuilder) {
    +        if (c0 == 'D' || c0 == 'd')
    +            if (c1 == 'e' || c1 == 'E') {
    +                if (c2 == 'c' || c2 == 'C') {
    +                    dateBuilder.setDecember();
    +                    return true;
    +                }
    +            }
    +        return false;
    +    }
    +
    +    private boolean isValidMonth(int start, int end, Builder dateBuilder) {
    +
    +        if (end - start != 3)
    +            return false;
    +
    +        char c0 = string.charAt(start);
    +        char c1 = string.charAt(start + 1);
    +        char c2 = string.charAt(start + 2);
    +
    +        return isValidJanuaryJuneJuly(c0, c1, c2, dateBuilder) || //
    +                isValidFebruary(c0, c1, c2, dateBuilder) || //
    +                isValidMarchMay(c0, c1, c2, dateBuilder) || //
    +                isValidAprilAugust(c0, c1, c2, dateBuilder) || //
    +                isValidSeptember(c0, c1, c2, dateBuilder) || //
    +                isValidOctober(c0, c1, c2, dateBuilder) || //
    +                isValidNovember(c0, c1, c2, dateBuilder) || //
    +                isValidDecember(c0, c1, c2, dateBuilder);
    +    }
    +
    +    private boolean isValid2DigitsYear(char c0, char c1, Builder dateBuilder) {
    +        if (isDigit(c0) && isDigit(c1)) {
    +            int i0 = getNumericValue(c0);
    +            int i1 = getNumericValue(c1);
    +            int year = i0 * 10 + i1;
    +            year = year < 70 ? year + 2000 : year + 1900;
    +
    +            return setValidYear(year, dateBuilder);
    +        }
    +        return false;
    +    }
    +
    +    private boolean isValid4DigitsYear(char c0, char c1, char c2, char c3, Builder dateBuilder) {
    +        if (isDigit(c0) && isDigit(c1) && isDigit(c2) && isDigit(c3)) {
    +            int i0 = getNumericValue(c0);
    +            int i1 = getNumericValue(c1);
    +            int i2 = getNumericValue(c2);
    +            int i3 = getNumericValue(c3);
    +            int year = i0 * 1000 + i1 * 100 + i2 * 10 + i3;
    +
    +            return setValidYear(year, dateBuilder);
    +        }
    +        return false;
    +    }
    +
    +    private boolean setValidYear(int year, Builder dateBuilder) {
    +        if (year >= 1601) {
    +            dateBuilder.setYear(year);
    +            return true;
    +        }
    +        return false;
    +    }
    +
    +    private boolean isValidYear(int start, int end, Builder dateBuilder) {
    +
    +        int length = end - start;
    +
    +        if (length == 2) {
    +            char c0 = string.charAt(start);
    +            char c1 = string.charAt(start + 1);
    +            return isValid2DigitsYear(c0, c1, dateBuilder);
    +
    +        } else if (length == 4) {
    +            char c0 = string.charAt(start);
    +            char c1 = string.charAt(start + 1);
    +            char c2 = string.charAt(start + 2);
    +            char c3 = string.charAt(start + 3);
    +            return isValid4DigitsYear(c0, c1, c2, c3, dateBuilder);
    +        }
    +
    +        return false;
    +    }
    +
    +    private boolean isValid1DigitHour(char c0, Builder dateBuilder) {
    +        if (isDigit(c0)) {
    +            int hour = getNumericValue(c0);
    +            dateBuilder.setHour(hour);
    +            return true;
    +        }
    +        return false;
    +    }
    +
    +    private boolean isValid2DigitsHour(char c0, char c1, Builder dateBuilder) {
    +        if (isDigit(c0) && isDigit(c1)) {
    +            int i0 = getNumericValue(c0);
    +            int i1 = getNumericValue(c1);
    +            int hour = i0 * 10 + i1;
    +            if (hour <= 24) {
    +                dateBuilder.setHour(hour);
    +                return true;
    +            }
    +        }
    +        return false;
    +    }
    +
    +    private boolean isValidHour(int start, int end, Builder dateBuilder) {
    +
    +        int length = end - start;
    +
    +        if (length == 1) {
    +            char c0 = string.charAt(start);
    +            return isValid1DigitHour(c0, dateBuilder);
    +
    +        } else if (length == 2) {
    +            char c0 = string.charAt(start);
    +            char c1 = string.charAt(start + 1);
    +            return isValid2DigitsHour(c0, c1, dateBuilder);
    +        }
    +        return false;
    +    }
    +
    +    private boolean isValid1DigitMinuteSecond(char c0, Builder dateBuilder, boolean minuteOrSecond) {
    +        if (isDigit(c0)) {
    +            int value = getNumericValue(c0);
    +            if (minuteOrSecond)
    +                dateBuilder.setMinute(value);
    +            else
    +                dateBuilder.setSecond(value);
    +            return true;
    +        }
    +        return false;
    +    }
    +
    +    private boolean isValid2DigitsMinuteSecond(char c0, char c1, Builder dateBuilder, boolean minuteOrSecond) {
    +        if (isDigit(c0) && isDigit(c1)) {
    +            int i0 = getNumericValue(c0);
    +            int i1 = getNumericValue(c1);
    +            int value = i0 * 10 + i1;
    +            if (value <= 60) {
    +                if (minuteOrSecond)
    +                    dateBuilder.setMinute(value);
    +                else
    +                    dateBuilder.setSecond(value);
    +                return true;
    +            }
    +        }
    +        return false;
    +    }
    +
    +    private boolean isValidMinuteSecond(int start, int end, Builder dateBuilder, boolean minuteOrSecond) {
    +
    +        int length = end - start;
    +
    +        if (length == 1) {
    +            char c0 = string.charAt(start);
    +            return isValid1DigitMinuteSecond(c0, dateBuilder, minuteOrSecond);
    +
    +        } else if (length == 2) {
    +            char c0 = string.charAt(start);
    +            char c1 = string.charAt(start + 1);
    +            return isValid2DigitsMinuteSecond(c0, c1, dateBuilder, minuteOrSecond);
    +        }
    +        return false;
    +    }
    +
    +    private boolean isDigit(char c) {
    +        return c >= '0' && c <= '9';
    +    }
    +
    +    private int getNumericValue(char c) {
    +        return (int) c - 48;
    +    }
    +}
    diff --git a/src/main/java/com/ning/http/client/date/TimeConverter.java b/src/main/java/com/ning/http/client/date/TimeConverter.java
    new file mode 100644
    index 0000000000..d42f48599a
    --- /dev/null
    +++ b/src/main/java/com/ning/http/client/date/TimeConverter.java
    @@ -0,0 +1,23 @@
    +/*
    + * Copyright (c) 2010-2014 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.date;
    +
    +/**
    + * Converts a RFC2616Date to time in millis
    + * 
    + * @author slandelle
    + */
    +public interface TimeConverter {
    +
    +    long toTime(RFC2616Date dateElements);
    +}
    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 a38cd5f97f..319deac4d3 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
    @@ -35,6 +35,7 @@
     import com.ning.http.client.RequestBuilder;
     import com.ning.http.client.Response;
     import com.ning.http.client.StringPart;
    +import com.ning.http.client.cookie.CookieEncoder;
     import com.ning.http.client.filter.FilterContext;
     import com.ning.http.client.filter.FilterException;
     import com.ning.http.client.filter.IOExceptionFilter;
    @@ -44,7 +45,6 @@
     import com.ning.http.util.AsyncHttpProviderUtils;
     import com.ning.http.util.ProxyUtils;
     import com.ning.http.util.UTF8UrlEncoder;
    -import com.ning.org.jboss.netty.handler.codec.http.CookieEncoder;
     
     import org.apache.commons.httpclient.CircularRedirectException;
     import org.apache.commons.httpclient.Credentials;
    @@ -377,7 +377,7 @@ private HttpMethodBase createMethod(HttpClient client, Request request) throws I
     
             method.setFollowRedirects(false);
             if (isNonEmpty(request.getCookies())) {
    -            method.setRequestHeader("Cookie", CookieEncoder.encodeClientSide(request.getCookies(), config.isRfc6265CookieEncoding()));
    +            method.setRequestHeader("Cookie", CookieEncoder.encode(request.getCookies()));
             }
     
             if (request.getHeaders() != null) {
    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 7a55f5799b..1f73128fd7 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,14 +24,14 @@
     import java.util.List;
     import java.util.Map;
     
    -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.Response;
    +import com.ning.http.client.cookie.Cookie;
    +import com.ning.http.client.cookie.CookieDecoder;
     import com.ning.http.util.AsyncHttpProviderUtils;
    -import com.ning.org.jboss.netty.handler.codec.http.CookieDecoder;
     
     public class ApacheResponse implements Response {
         private final static String DEFAULT_CHARSET = "ISO-8859-1";
    @@ -170,8 +170,8 @@ public List getCookies() {
                         // TODO: ask for parsed header
                         List v = header.getValue();
                         for (String value : v) {
    -                        List cookies = CookieDecoder.decode(value);
    -                        localCookies.addAll(cookies);
    +                        Cookie cookie = CookieDecoder.decode(value);
    +                        localCookies.add(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 990bedf5e3..9203377c9a 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,27 +13,39 @@
     
     package com.ning.http.client.providers.grizzly;
     
    +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;
     import static com.ning.http.util.MiscUtil.isNonEmpty;
     
    -import com.ning.http.client.*;
    -import com.ning.http.multipart.MultipartBody;
    -import com.ning.org.jboss.netty.handler.codec.http.CookieDecoder;
    -import com.ning.http.client.filter.FilterContext;
    -import com.ning.http.client.filter.ResponseFilter;
    -import com.ning.http.client.listener.TransferCompletionHandler;
    -import com.ning.http.client.websocket.WebSocket;
    -import com.ning.http.client.websocket.WebSocketByteListener;
    -import com.ning.http.client.websocket.WebSocketCloseCodeReasonListener;
    -import com.ning.http.client.websocket.WebSocketListener;
    -import com.ning.http.client.websocket.WebSocketPingListener;
    -import com.ning.http.client.websocket.WebSocketPongListener;
    -import com.ning.http.client.websocket.WebSocketTextListener;
    -import com.ning.http.client.websocket.WebSocketUpgradeHandler;
    -import com.ning.http.multipart.MultipartRequestEntity;
    -import com.ning.http.util.AsyncHttpProviderUtils;
    -import com.ning.http.util.AuthenticatorUtils;
    -import com.ning.http.util.ProxyUtils;
    -import com.ning.http.util.SslUtils;
    +import java.io.ByteArrayOutputStream;
    +import java.io.EOFException;
    +import java.io.File;
    +import java.io.FileInputStream;
    +import java.io.IOException;
    +import java.io.InputStream;
    +import java.io.UnsupportedEncodingException;
    +import java.net.InetSocketAddress;
    +import java.net.URI;
    +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;
    +import java.util.Locale;
    +import java.util.Map;
    +import java.util.concurrent.ExecutionException;
    +import java.util.concurrent.ExecutorService;
    +import java.util.concurrent.Semaphore;
    +import java.util.concurrent.TimeUnit;
    +import java.util.concurrent.TimeoutException;
    +import java.util.concurrent.atomic.AtomicInteger;
    +import java.util.concurrent.atomic.AtomicLong;
    +
    +import javax.net.ssl.SSLContext;
    +
     import org.glassfish.grizzly.Buffer;
     import org.glassfish.grizzly.CompletionHandler;
     import org.glassfish.grizzly.Connection;
    @@ -85,7 +97,6 @@
     import org.glassfish.grizzly.websockets.ClosingFrame;
     import org.glassfish.grizzly.websockets.DataFrame;
     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;
    @@ -94,36 +105,49 @@
     import org.slf4j.Logger;
     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;
    -import java.io.IOException;
    -import java.io.InputStream;
    -import java.io.UnsupportedEncodingException;
    -import java.net.InetSocketAddress;
    -import java.net.URI;
    -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;
    -import java.util.Locale;
    -import java.util.Map;
    -import java.util.concurrent.ExecutionException;
    -import java.util.concurrent.ExecutorService;
    -import java.util.concurrent.Semaphore;
    -import java.util.concurrent.TimeUnit;
    -import java.util.concurrent.TimeoutException;
    -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;
    +import com.ning.http.client.AsyncHandler;
    +import com.ning.http.client.AsyncHandlerExtensions;
    +import com.ning.http.client.AsyncHttpClient;
    +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.ConnectionsPool;
    +import com.ning.http.client.FluentCaseInsensitiveStringsMap;
    +import com.ning.http.client.FluentStringsMap;
    +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.Part;
    +import com.ning.http.client.PerRequestConfig;
    +import com.ning.http.client.ProxyServer;
    +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.UpgradeHandler;
    +import com.ning.http.client.cookie.Cookie;
    +import com.ning.http.client.cookie.CookieDecoder;
    +import com.ning.http.client.filter.FilterContext;
    +import com.ning.http.client.filter.ResponseFilter;
    +import com.ning.http.client.listener.TransferCompletionHandler;
    +import com.ning.http.client.websocket.WebSocket;
    +import com.ning.http.client.websocket.WebSocketByteListener;
    +import com.ning.http.client.websocket.WebSocketCloseCodeReasonListener;
    +import com.ning.http.client.websocket.WebSocketListener;
    +import com.ning.http.client.websocket.WebSocketPingListener;
    +import com.ning.http.client.websocket.WebSocketPongListener;
    +import com.ning.http.client.websocket.WebSocketTextListener;
    +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.ProxyUtils;
    +import com.ning.http.util.SslUtils;
     
     /**
      * A Grizzly 2.0-based implementation of {@link AsyncHttpProvider}.
    @@ -983,7 +1007,7 @@ private void convertCookies(final Collection cookies,
                             new org.glassfish.grizzly.http.Cookie(cookie.getName(), cookie.getValue());
                     gCookie.setDomain(cookie.getDomain());
                     gCookie.setPath(cookie.getPath());
    -                gCookie.setVersion(cookie.getVersion());
    +                gCookie.setVersion(1);
                     gCookie.setMaxAge(cookie.getMaxAge());
                     gCookie.setSecure(cookie.isSecure());
                     gCookies[idx] = gCookie;
    @@ -1666,9 +1690,7 @@ private static Request newRequest(final URI uri,
                     builder.setQueryParameters(null);
                 }
                 for (String cookieStr : response.getHeaders().values(Header.Cookie)) {
    -                for (Cookie c : CookieDecoder.decode(cookieStr)) {
    -                    builder.addOrReplaceCookie(c);
    -                }
    +                builder.addOrReplaceCookie(CookieDecoder.decode(cookieStr));
                 }
                 return builder.build();
     
    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 8df137e885..469327752f 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
    @@ -15,22 +15,6 @@
     
     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;
    -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 org.glassfish.grizzly.Buffer;
    -import org.glassfish.grizzly.http.Cookies;
    -import org.glassfish.grizzly.http.CookiesBuilder;
    -import org.glassfish.grizzly.utils.Charsets;
    -import org.glassfish.grizzly.memory.Buffers;
    -import org.glassfish.grizzly.memory.MemoryManager;
    -import org.glassfish.grizzly.utils.BufferInputStream;
    -
     import java.io.IOException;
     import java.io.InputStream;
     import java.net.MalformedURLException;
    @@ -42,6 +26,22 @@
     import java.util.Collections;
     import java.util.List;
     
    +import org.glassfish.grizzly.Buffer;
    +import org.glassfish.grizzly.http.Cookies;
    +import org.glassfish.grizzly.http.CookiesBuilder;
    +import org.glassfish.grizzly.memory.Buffers;
    +import org.glassfish.grizzly.memory.MemoryManager;
    +import org.glassfish.grizzly.utils.BufferInputStream;
    +import org.glassfish.grizzly.utils.Charsets;
    +
    +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.Response;
    +import com.ning.http.client.cookie.Cookie;
    +import com.ning.http.util.AsyncHttpProviderUtils;
    +
     /**
      * {@link com.ning.http.client.HttpResponseBodyPart} implementation using the Grizzly 2.0 HTTP client
      * codec.
    @@ -324,10 +324,12 @@ private List convertCookies(Cookies cookies) {
                 convertedCookies.add(new Cookie(gCookie.getDomain(),
                                        gCookie.getName(),
                                        gCookie.getValue(),
    +                                   gCookie.getValue(),
                                        gCookie.getPath(),
    +                                   -1L,
                                        gCookie.getMaxAge(),
                                        gCookie.isSecure(),
    -                                   gCookie.getVersion()));
    +                                   false));
             }
             return Collections.unmodifiableList(convertedCookies);
     
    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 18139e8733..eb665e5ede 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,8 +12,45 @@
      */
     package com.ning.http.client.providers.jdk;
     
    +import static com.ning.http.util.AsyncHttpProviderUtils.DEFAULT_CHARSET;
     import static com.ning.http.util.MiscUtil.isNonEmpty;
     
    +import java.io.ByteArrayInputStream;
    +import java.io.File;
    +import java.io.FileInputStream;
    +import java.io.IOException;
    +import java.io.InputStream;
    +import java.io.OutputStream;
    +import java.lang.reflect.Field;
    +import java.net.Authenticator;
    +import java.net.ConnectException;
    +import java.net.HttpURLConnection;
    +import java.net.InetSocketAddress;
    +import java.net.PasswordAuthentication;
    +import java.net.Proxy;
    +import java.net.SocketAddress;
    +import java.net.SocketTimeoutException;
    +import java.net.URI;
    +import java.net.UnknownHostException;
    +import java.nio.ByteBuffer;
    +import java.security.GeneralSecurityException;
    +import java.security.NoSuchAlgorithmException;
    +import java.util.List;
    +import java.util.Map;
    +import java.util.concurrent.Callable;
    +import java.util.concurrent.TimeoutException;
    +import java.util.concurrent.atomic.AtomicBoolean;
    +import java.util.concurrent.atomic.AtomicInteger;
    +import java.util.zip.GZIPInputStream;
    +
    +import javax.naming.AuthenticationException;
    +import javax.net.ssl.HttpsURLConnection;
    +import javax.net.ssl.SSLContext;
    +import javax.net.ssl.SSLHandshakeException;
    +
    +import org.slf4j.Logger;
    +import org.slf4j.LoggerFactory;
    +
     import com.ning.http.client.AsyncHandler;
     import com.ning.http.client.AsyncHttpClientConfig;
     import com.ning.http.client.AsyncHttpProvider;
    @@ -32,6 +69,7 @@
     import com.ning.http.client.Request;
     import com.ning.http.client.RequestBuilder;
     import com.ning.http.client.Response;
    +import com.ning.http.client.cookie.CookieEncoder;
     import com.ning.http.client.filter.FilterContext;
     import com.ning.http.client.filter.FilterException;
     import com.ning.http.client.filter.IOExceptionFilter;
    @@ -43,45 +81,6 @@
     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.CookieEncoder;
    -
    -import org.slf4j.Logger;
    -import org.slf4j.LoggerFactory;
    -
    -import javax.naming.AuthenticationException;
    -import javax.net.ssl.HttpsURLConnection;
    -import javax.net.ssl.SSLContext;
    -import javax.net.ssl.SSLHandshakeException;
    -
    -import java.io.ByteArrayInputStream;
    -import java.io.File;
    -import java.io.FileInputStream;
    -import java.io.IOException;
    -import java.io.InputStream;
    -import java.io.OutputStream;
    -import java.lang.reflect.Field;
    -import java.net.Authenticator;
    -import java.net.ConnectException;
    -import java.net.HttpURLConnection;
    -import java.net.InetSocketAddress;
    -import java.net.PasswordAuthentication;
    -import java.net.Proxy;
    -import java.net.SocketAddress;
    -import java.net.SocketTimeoutException;
    -import java.net.URI;
    -import java.net.UnknownHostException;
    -import java.nio.ByteBuffer;
    -import java.security.GeneralSecurityException;
    -import java.security.NoSuchAlgorithmException;
    -import java.util.List;
    -import java.util.Map;
    -import java.util.concurrent.Callable;
    -import java.util.concurrent.TimeoutException;
    -import java.util.concurrent.atomic.AtomicBoolean;
    -import java.util.concurrent.atomic.AtomicInteger;
    -import java.util.zip.GZIPInputStream;
    -
    -import static com.ning.http.util.AsyncHttpProviderUtils.DEFAULT_CHARSET;
     
     public class JDKAsyncHttpProvider implements AsyncHttpProvider {
         private final static Logger logger = LoggerFactory.getLogger(JDKAsyncHttpProvider.class);
    @@ -549,7 +548,7 @@ private void configure(URI uri, HttpURLConnection urlConnection, Request request
                 }
     
                 if (isNonEmpty(request.getCookies())) {
    -                urlConnection.setRequestProperty("Cookie", CookieEncoder.encodeClientSide(request.getCookies(), config.isRfc6265CookieEncoding()));
    +                urlConnection.setRequestProperty("Cookie", CookieEncoder.encode(request.getCookies()));
                 }
     
                 String reqType = request.getMethod();
    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 631f9cc525..9a4bd687f1 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
    @@ -26,14 +26,14 @@
     import java.util.Map;
     import java.util.concurrent.atomic.AtomicBoolean;
     
    -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.Response;
    +import com.ning.http.client.cookie.Cookie;
    +import com.ning.http.client.cookie.CookieDecoder;
     import com.ning.http.util.AsyncHttpProviderUtils;
    -import com.ning.org.jboss.netty.handler.codec.http.CookieDecoder;
     
     
     public class JDKResponse implements Response {
    @@ -185,8 +185,7 @@ public List getCookies() {
                         // TODO: ask for parsed header
                         List v = header.getValue();
                         for (String value : v) {
    -                        List cookies = CookieDecoder.decode(value);
    -                        localCookies.addAll(cookies);
    +                        localCookies.add(CookieDecoder.decode(value));
                         }
                     }
                 }
    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 f3d6551ab3..96386b25eb 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,53 +15,50 @@
      */
     package com.ning.http.client.providers.netty;
     
    -import com.ning.http.client.AsyncHandler;
    -import com.ning.http.client.AsyncHandler.STATE;
    -import com.ning.http.client.AsyncHandlerExtensions;
    -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.providers.netty.timeout.IdleConnectionTimeoutTimerTask;
    -import com.ning.http.client.providers.netty.timeout.RequestTimeoutTimerTask;
    -import com.ning.http.client.providers.netty.timeout.TimeoutsHolder;
    -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 com.ning.org.jboss.netty.handler.codec.http.CookieEncoder;
    +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.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.List;
    +import java.util.Locale;
    +import java.util.Map.Entry;
    +import java.util.concurrent.Callable;
    +import java.util.concurrent.ExecutorService;
    +import java.util.concurrent.Executors;
    +import java.util.concurrent.RejectedExecutionException;
    +import java.util.concurrent.Semaphore;
    +import java.util.concurrent.TimeUnit;
    +import java.util.concurrent.atomic.AtomicBoolean;
    +
    +import javax.net.ssl.SSLEngine;
    +
     import org.jboss.netty.bootstrap.ClientBootstrap;
     import org.jboss.netty.buffer.ChannelBuffer;
     import org.jboss.netty.buffer.ChannelBufferOutputStream;
    @@ -109,48 +106,53 @@
     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.List;
    -import java.util.Locale;
    -import java.util.Map.Entry;
    -import java.util.concurrent.Callable;
    -import java.util.concurrent.ExecutorService;
    -import java.util.concurrent.Executors;
    -import java.util.concurrent.RejectedExecutionException;
    -import java.util.concurrent.Semaphore;
    -import java.util.concurrent.TimeUnit;
    -import java.util.concurrent.atomic.AtomicBoolean;
    -
    -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.MiscUtil.isNonEmpty;
    -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.AsyncHandlerExtensions;
    +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.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.cookie.Cookie;
    +import com.ning.http.client.cookie.CookieDecoder;
    +import com.ning.http.client.cookie.CookieEncoder;
    +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.providers.netty.timeout.IdleConnectionTimeoutTimerTask;
    +import com.ning.http.client.providers.netty.timeout.RequestTimeoutTimerTask;
    +import com.ning.http.client.providers.netty.timeout.TimeoutsHolder;
    +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;
     
     public class NettyAsyncHttpProvider extends SimpleChannelUpstreamHandler implements AsyncHttpProvider {
     
    @@ -801,7 +803,7 @@ else if (uri.getRawQuery() != null)
     
             if (!m.equals(HttpMethod.CONNECT)) {
                 if (isNonEmpty(request.getCookies())) {
    -                nettyRequest.setHeader(HttpHeaders.Names.COOKIE, CookieEncoder.encodeClientSide(request.getCookies(), config.isRfc6265CookieEncoding()));
    +                nettyRequest.setHeader(HttpHeaders.Names.COOKIE, CookieEncoder.encode(request.getCookies()));
                 }
     
                 String bodyCharset = request.getBodyEncoding() == null ? DEFAULT_CHARSET : request.getBodyEncoding();
    @@ -1963,16 +1965,13 @@ private boolean redirect(Request request, NettyResponseFuture future, HttpRes
                         }
     
                         log.debug("Redirecting to {}", newUrl);
    -                    for (String cookieStr : future.getHttpResponse().getHeaders(HttpHeaders.Names.SET_COOKIE)) {
    -                        for (Cookie c : CookieDecoder.decode(cookieStr)) {
    -                            nBuilder.addOrReplaceCookie(c);
    -                        }
    +                    List setCookieHeaders = future.getHttpResponse().getHeaders(HttpHeaders.Names.SET_COOKIE2);
    +                    if (!isNonEmpty(setCookieHeaders)) {
    +                        setCookieHeaders = future.getHttpResponse().getHeaders(HttpHeaders.Names.SET_COOKIE);
                         }
     
    -                    for (String cookieStr : future.getHttpResponse().getHeaders(HttpHeaders.Names.SET_COOKIE2)) {
    -                        for (Cookie c : CookieDecoder.decode(cookieStr)) {
    -                            nBuilder.addOrReplaceCookie(c);
    -                        }
    +                    for (String cookieStr : setCookieHeaders) {
    +                        nBuilder.addOrReplaceCookie(CookieDecoder.decode(cookieStr));
                         }
     
                         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 b17af51bcb..3720683b47 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
    @@ -32,14 +32,14 @@
     import org.jboss.netty.buffer.ChannelBufferInputStream;
     import org.jboss.netty.buffer.ChannelBuffers;
     
    -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.Response;
    +import com.ning.http.client.cookie.Cookie;
    +import com.ning.http.client.cookie.CookieDecoder;
     import com.ning.http.util.AsyncHttpProviderUtils;
    -import com.ning.org.jboss.netty.handler.codec.http.CookieDecoder;
     
     /**
      * Wrapper around the {@link com.ning.http.client.Response} API.
    @@ -194,8 +194,7 @@ public List getCookies() {
                         // TODO: ask for parsed header
                         List v = header.getValue();
                         for (String value : v) {
    -                        List cookies = CookieDecoder.decode(value);
    -                        localCookies.addAll(cookies);
    +                        localCookies.add(CookieDecoder.decode(value));
                         }
                     }
                 }
    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 3a16fc4f00..fb8fdb2b9e 100644
    --- a/src/main/java/com/ning/http/client/webdav/WebDavResponse.java
    +++ b/src/main/java/com/ning/http/client/webdav/WebDavResponse.java
    @@ -12,11 +12,6 @@
      */
     package com.ning.http.client.webdav;
     
    -import com.ning.http.client.Cookie;
    -import com.ning.http.client.FluentCaseInsensitiveStringsMap;
    -import com.ning.http.client.Response;
    -import org.w3c.dom.Document;
    -
     import java.io.IOException;
     import java.io.InputStream;
     import java.net.MalformedURLException;
    @@ -24,6 +19,12 @@
     import java.nio.ByteBuffer;
     import java.util.List;
     
    +import org.w3c.dom.Document;
    +
    +import com.ning.http.client.FluentCaseInsensitiveStringsMap;
    +import com.ning.http.client.Response;
    +import com.ning.http.client.cookie.Cookie;
    +
     /**
      * Customized {@link Response} which add support for getting the response's body as an XML document (@link WebDavResponse#getBodyAsXML}
      */
    diff --git a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java
    index 816161d73d..39c9dc30f9 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.MiscUtil.isNonEmpty;
    +
     import java.io.ByteArrayInputStream;
     import java.io.FileNotFoundException;
     import java.io.IOException;
    @@ -19,17 +21,11 @@
     import java.io.UnsupportedEncodingException;
     import java.net.URI;
     import java.net.URISyntaxException;
    -import java.text.ParsePosition;
    -import java.text.SimpleDateFormat;
    -import java.util.Collection;
    -import java.util.Date;
     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;
     import com.ning.http.client.FilePart;
     import com.ning.http.client.FluentCaseInsensitiveStringsMap;
     import com.ning.http.client.HttpResponseBodyPart;
    @@ -40,9 +36,6 @@
     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;
    -
    -import static com.ning.http.util.MiscUtil.isNonEmpty;
     
     /**
      * {@link com.ning.http.client.AsyncHttpProvider} common utilities.
    @@ -53,29 +46,6 @@ public class AsyncHttpProviderUtils {
     
         public final static String DEFAULT_CHARSET = "ISO-8859-1";
     
    -    private final static String BODY_NOT_COMPUTED = "Response's body hasn't been computed by your AsyncHandler.";
    -
    -
    -    protected final static ThreadLocal simpleDateFormat = new ThreadLocal() {
    -        protected SimpleDateFormat[] initialValue() {
    -
    -            return new SimpleDateFormat[]
    -                    {
    -                            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)
    -                    };
    -        }
    -    };
    -
    -    public final static SimpleDateFormat[] get() {
    -        return simpleDateFormat.get();
    -    }
    -
         static final byte[] EMPTY_BYTE_ARRAY = "".getBytes();
         
         public static final void validateSupportedScheme(URI uri) {
    @@ -324,61 +294,6 @@ public static String parseCharset(String contentType) {
             return null;
         }
     
    -    @Deprecated
    -    public static Cookie parseCookie(String value) {
    -        return CookieDecoder.decode(value).iterator().next();
    -    }
    -
    -    public static int convertExpireField(String timestring) {
    -        String trimmedTimeString = removeQuotes(timestring.trim());
    -        long now = System.currentTimeMillis();
    -        Date date = null;
    -
    -        for (SimpleDateFormat sdf : simpleDateFormat.get()) {
    -            date = sdf.parse(trimmedTimeString, new ParsePosition(0));
    -            if (date != null)
    -                break;
    -        }
    -
    -        if (date != null) {
    -            long maxAgeMillis = date.getTime() - now;
    -            return (int) (maxAgeMillis / 1000) + (maxAgeMillis % 1000 != 0? 1 : 0);
    -        } else
    -            throw new IllegalArgumentException("Not a valid expire field " + trimmedTimeString);
    -    }
    -
    -    public final static String removeQuotes(String s) {
    -        if (MiscUtil.isNonEmpty(s)) {
    -            int start = 0;
    -            int end = s.length();
    -            boolean changed = false;
    -
    -            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;
    -    }
    -
    -    public static void checkBodyParts(int statusCode, Collection bodyParts) {
    -        if (bodyParts == null || bodyParts.size() == 0) {
    -
    -            // We allow empty body on 204
    -            if (statusCode == 204) return;
    -
    -            throw new IllegalStateException(BODY_NOT_COMPUTED);
    -        }
    -    }
    -
         public static String keepAliveHeaderValue(AsyncHttpClientConfig config) {
             return config.getAllowPoolingConnection() ? "keep-alive" : "close";
         }
    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
    deleted file mode 100644
    index 83ce6dd836..0000000000
    --- a/src/main/java/com/ning/org/jboss/netty/handler/codec/http/CookieDecoder.java
    +++ /dev/null
    @@ -1,309 +0,0 @@
    -/*
    - * 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.handler.codec.http;
    -
    -import java.util.ArrayList;
    -import java.util.Collections;
    -import java.util.List;
    -import java.util.Set;
    -import java.util.TreeSet;
    -
    -import org.jboss.netty.handler.codec.http.HttpRequest;
    -
    -import com.ning.http.client.Cookie;
    -import com.ning.http.client.Cookie.CookieBuilder;
    -import com.ning.http.util.AsyncHttpProviderUtils;
    -import com.ning.org.jboss.netty.util.internal.StringUtil;
    -
    -/**
    - * 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 = ','; - - private static class CookiesBuilder { - - private int i; - private int version = 0; - private CookieBuilder cookieBuilder; - private List cookies = new ArrayList(); - - public void addKeyValuePair(String name, String value, String rawValue) { - - // $Version is the only attribute that can appear before the actual - // cookie name-value pair. - if (i == 0 && name.equalsIgnoreCase(CookieHeaderNames.VERSION)) { - try { - version = Integer.parseInt(value); - } catch (NumberFormatException e) { - // Ignore. - } - - } else if (cookieBuilder == null) { - cookieBuilder = new CookieBuilder(name, value, rawValue); - if (version != 0) - cookieBuilder.setVersion(version); - - } else if (setCookieAttribute(name, value)) { - cookies.add(cookieBuilder.build()); - cookieBuilder = null; - } - } - - public List build() { - cookies.add(cookieBuilder.build()); - return cookies; - } - - private boolean setCookieAttribute(String name, String value) { - - if (CookieHeaderNames.DISCARD.equalsIgnoreCase(name)) { - cookieBuilder.setDiscard(true); - - } else if (CookieHeaderNames.SECURE.equalsIgnoreCase(name)) { - cookieBuilder.setSecure(true); - - } else if (CookieHeaderNames.HTTPONLY.equalsIgnoreCase(name)) { - cookieBuilder.setHttpOnly(true); - - } else if (CookieHeaderNames.COMMENT.equalsIgnoreCase(name)) { - cookieBuilder.setComment(value); - - } else if (CookieHeaderNames.COMMENTURL.equalsIgnoreCase(name)) { - cookieBuilder.setCommentUrl(value); - - } else if (CookieHeaderNames.DOMAIN.equalsIgnoreCase(name)) { - cookieBuilder.setDomain(value); - - } else if (CookieHeaderNames.PATH.equalsIgnoreCase(name)) { - cookieBuilder.setPath(value); - - } else if (CookieHeaderNames.EXPIRES.equalsIgnoreCase(name)) { - setCookieExpires(cookieBuilder, value); - - } else if (CookieHeaderNames.MAX_AGE.equalsIgnoreCase(name)) { - cookieBuilder.setMaxAge(Integer.parseInt(value)); - - } else if (CookieHeaderNames.VERSION.equalsIgnoreCase(name)) { - cookieBuilder.setVersion(Integer.parseInt(value)); - - } else if (CookieHeaderNames.PORT.equalsIgnoreCase(name)) { - setCookiePorts(cookieBuilder, value); - - } else { - return true; - } - - return false; - } - - private void setCookieExpires(CookieBuilder cookieBuilder, String value) { - try { - cookieBuilder.setMaxAge(AsyncHttpProviderUtils.convertExpireField(value)); - } catch (Exception e) { - // original behavior, is this correct at all (expires field with max-age semantics)? - try { - cookieBuilder.setMaxAge(Math.max(Integer.valueOf(value), 0)); - } catch (NumberFormatException e1) { - // ignore failure to parse -> treat as session cookie - } - } - } - - private void setCookiePorts(CookieBuilder cookieBuilder, String value) { - String[] portList = StringUtil.split(value, COMMA); - Set ports = new TreeSet(); - for (String s1 : portList) { - try { - ports.add(Integer.valueOf(s1)); - } catch (NumberFormatException e) { - // Ignore. - } - } - cookieBuilder.setPorts(ports); - } - } - - private CookieDecoder() { - } - - /** - * Decodes the specified HTTP header value into {@link Cookie}s. - * - * @return the decoded {@link Cookie}s - */ - public static List decode(String header) { - - final int headerLen = header.length(); - if (headerLen == 0) - return Collections.emptyList(); - - CookiesBuilder cookiesBuilder = new CookiesBuilder(); - - 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; - String rawValue; - int names = 0; - - if (i == headerLen) { - name = null; - value = rawValue = null; - } else { - int newNameStart = i; - keyValLoop: for (;;) { - switch (header.charAt(i)) { - case ';': - // NAME; (no value till ';') - name = header.substring(newNameStart, i); - names++; - value = rawValue = null; - break keyValLoop; - case '=': - // NAME=VALUE - name = header.substring(newNameStart, i); - names++; - i++; - if (i == headerLen) { - // NAME= (empty value, i.e. nothing after '=') - value = rawValue = ""; - 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); - - int rawValueStart = i; - int rawValueEnd = i; - - final char q = c; - boolean hadBackslash = false; - i++; - for (;;) { - if (i == headerLen) { - value = newValueBuf.toString(); - // only need to compute raw value for cookie value which is at most in 2nd position - rawValue = names <= 1 ? header.substring(rawValueStart, rawValueEnd) : null; - break keyValLoop; - } - if (hadBackslash) { - hadBackslash = false; - c = header.charAt(i++); - rawValueEnd = 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++); - rawValueEnd = i; - if (c == q) { - value = newValueBuf.toString(); - // only need to compute raw value for cookie value which is at most in 2nd position - rawValue = names <= 1 ? header.substring(rawValueStart, rawValueEnd) : null; - break keyValLoop; - } - newValueBuf.append(c); - if (c == '\\') { - hadBackslash = true; - } - } - } - } else { - // NAME=VALUE; - int semiPos = header.indexOf(';', i); - if (semiPos > 0) { - value = rawValue = header.substring(newValueStart, semiPos); - i = semiPos; - } else { - value = rawValue = 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 = rawValue = null; - break; - } - } - } - - cookiesBuilder.addKeyValuePair(name, value, rawValue); - } - return cookiesBuilder.build(); - } -} 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 deleted file mode 100644 index 5842e066cc..0000000000 --- a/src/main/java/com/ning/org/jboss/netty/handler/codec/http/CookieEncoder.java +++ /dev/null @@ -1,162 +0,0 @@ -/* - * 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.handler.codec.http; - -import java.util.Collection; - -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) { - if (val == null) { - 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/CookieHeaderNames.java b/src/main/java/com/ning/org/jboss/netty/handler/codec/http/CookieHeaderNames.java deleted file mode 100644 index 6d050c206e..0000000000 --- a/src/main/java/com/ning/org/jboss/netty/handler/codec/http/CookieHeaderNames.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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.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/handler/codec/http/HttpConstants.java b/src/main/java/com/ning/org/jboss/netty/handler/codec/http/HttpConstants.java deleted file mode 100644 index 0331bd6faf..0000000000 --- a/src/main/java/com/ning/org/jboss/netty/handler/codec/http/HttpConstants.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * 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.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 - } -} 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 deleted file mode 100644 index b7e55976eb..0000000000 --- a/src/main/java/com/ning/org/jboss/netty/util/internal/StringUtil.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * 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/http/client/async/AsyncProvidersBasicTest.java b/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java index c660beb0b6..257f75554d 100755 --- a/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java +++ b/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java @@ -53,7 +53,6 @@ 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; @@ -62,6 +61,7 @@ import com.ning.http.client.RequestBuilder; import com.ning.http.client.Response; import com.ning.http.client.StringPart; +import com.ning.http.client.cookie.Cookie; public abstract class AsyncProvidersBasicTest extends AbstractBasicTest { private static final String UTF_8 = "text/html;charset=UTF-8"; @@ -478,7 +478,7 @@ public void asyncDoGetCookieTest() throws Throwable { h.add("Test4", "Test4"); h.add("Test5", "Test5"); - final Cookie coo = new Cookie("/", "foo", "value", "/", -1, false); + final Cookie coo = new Cookie("/", "foo", "value", "value", "/", -1L, -1, false, false); client.prepareGet(getTargetUrl()).setHeaders(h).addCookie(coo).execute(new AsyncCompletionHandlerAdapter() { @Override @@ -487,7 +487,7 @@ public Response onCompleted(Response response) throws Exception { assertEquals(response.getStatusCode(), 200); List cookies = response.getCookies(); assertEquals(cookies.size(), 1); - assertEquals(cookies.get(0).toString(), coo.toString()); + assertEquals(cookies.get(0).toString(), "foo=value"); } finally { l.countDown(); } 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 43f4a498b4..51fb798756 100644 --- a/src/test/java/com/ning/http/client/async/RemoteSiteTest.java +++ b/src/test/java/com/ning/http/client/async/RemoteSiteTest.java @@ -15,6 +15,18 @@ */ package com.ning.http.client.async; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.AssertJUnit.assertTrue; + +import java.io.InputStream; +import java.net.URLEncoder; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import org.testng.Assert; +import org.testng.annotations.Test; + import com.ning.http.client.AsyncHandler; import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClientConfig; @@ -24,18 +36,8 @@ import com.ning.http.client.Request; import com.ning.http.client.RequestBuilder; import com.ning.http.client.Response; +import com.ning.http.client.cookie.Cookie; import com.ning.http.util.AsyncHttpProviderUtils; -import org.testng.Assert; -import org.testng.annotations.Test; - -import java.io.InputStream; -import java.net.URLEncoder; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertNotNull; -import static org.testng.AssertJUnit.assertTrue; /** * Unit tests for remote site. @@ -247,7 +249,7 @@ public void evilCoookieTest() throws Throwable { 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)); + builder2.addCookie(new Cookie(".google.com", "evilcookie", "test", "test", "/", -1L, 10, false, false)); com.ning.http.client.Request request2 = builder2.build(); Response response = c.executeRequest(request2).get(); diff --git a/src/test/java/com/ning/http/client/cookie/CookieDecoderTest.java b/src/test/java/com/ning/http/client/cookie/CookieDecoderTest.java new file mode 100644 index 0000000000..6191580613 --- /dev/null +++ b/src/test/java/com/ning/http/client/cookie/CookieDecoderTest.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2014 AsyncHttpClient Project. 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.cookie; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; + +import org.testng.annotations.Test; + +public class CookieDecoderTest { + + @Test(groups = "fast") + public void testDecodeUnquoted() { + Cookie cookie = CookieDecoder.decode("foo=value; domain=/; path=/"); + assertNotNull(cookie); + assertEquals(cookie.getValue(), "value"); + assertEquals(cookie.getRawValue(), "value"); + assertEquals(cookie.getDomain(), "/"); + assertEquals(cookie.getPath(), "/"); + } + + @Test(groups = "fast") + public void testDecodeQuoted() { + Cookie cookie = CookieDecoder.decode("ALPHA=\"VALUE1\"; Domain=docs.foo.com; Path=/accounts; Expires=Wed, 05 Feb 2014 07:37:38 GMT; Secure; HttpOnly"); + assertNotNull(cookie); + assertEquals(cookie.getValue(), "VALUE1"); + assertEquals(cookie.getRawValue(), "\"VALUE1\""); + } + + @Test(groups = "fast") + public void testDecodeQuotedContainingEscapedQuote() { + Cookie cookie = CookieDecoder.decode("ALPHA=\"VALUE1\\\"\"; Domain=docs.foo.com; Path=/accounts; Expires=Wed, 05 Feb 2014 07:37:38 GMT; Secure; HttpOnly"); + assertNotNull(cookie); + assertEquals(cookie.getValue(), "VALUE1\""); + assertEquals(cookie.getRawValue(), "\"VALUE1\\\"\""); + } +} diff --git a/src/test/java/com/ning/http/client/date/RFC2616DateParserTest.java b/src/test/java/com/ning/http/client/date/RFC2616DateParserTest.java new file mode 100644 index 0000000000..d6b1aafaaf --- /dev/null +++ b/src/test/java/com/ning/http/client/date/RFC2616DateParserTest.java @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2014 AsyncHttpClient Project. 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.date; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; + +import org.testng.annotations.Test; + +/** + * See http://tools.ietf.org/html/rfc2616#section-3.3 + * + * @author slandelle + */ +public class RFC2616DateParserTest { + + @Test(groups = "fast") + public void testRFC822() { + RFC2616Date date = new RFC2616DateParser("Sun, 06 Nov 1994 08:49:37 GMT").parse(); + assertNotNull(date); + assertEquals(date.dayOfMonth(), 6); + assertEquals(date.month(), 11); + assertEquals(date.year(), 1994); + assertEquals(date.hour(), 8); + assertEquals(date.minute(), 49); + assertEquals(date.second(), 37); + } + + @Test(groups = "fast") + public void testRFC822SingleDigitDayOfMonth() { + RFC2616Date date = new RFC2616DateParser("Sun, 6 Nov 1994 08:49:37 GMT").parse(); + assertNotNull(date); + assertEquals(date.dayOfMonth(), 6); + } + + @Test(groups = "fast") + public void testRFC822TwoDigitsYear() { + RFC2616Date date = new RFC2616DateParser("Sun, 6 Nov 94 08:49:37 GMT").parse(); + assertNotNull(date); + assertEquals(date.year(), 1994); + } + + @Test(groups = "fast") + public void testRFC822SingleDigitHour() { + RFC2616Date date = new RFC2616DateParser("Sun, 6 Nov 1994 8:49:37 GMT").parse(); + assertNotNull(date); + assertEquals(date.hour(), 8); + } + + @Test(groups = "fast") + public void testRFC822SingleDigitMinute() { + RFC2616Date date = new RFC2616DateParser("Sun, 6 Nov 1994 08:9:37 GMT").parse(); + assertNotNull(date); + assertEquals(date.minute(), 9); + } + + @Test(groups = "fast") + public void testRFC822SingleDigitSecond() { + RFC2616Date date = new RFC2616DateParser("Sun, 6 Nov 1994 08:49:7 GMT").parse(); + assertNotNull(date); + assertEquals(date.second(), 7); + } + + @Test(groups = "fast") + public void testRFC6265() { + RFC2616Date date = new RFC2616DateParser("Sun, 06 Nov 1994 08:49:37").parse(); + assertNotNull(date); + assertEquals(date.dayOfMonth(), 6); + assertEquals(date.month(), 11); + assertEquals(date.year(), 1994); + assertEquals(date.hour(), 8); + assertEquals(date.minute(), 49); + assertEquals(date.second(), 37); + } + + @Test(groups = "fast") + public void testRFC850() { + RFC2616Date date = new RFC2616DateParser("Sunday, 06-Nov-94 08:49:37 GMT").parse(); + assertNotNull(date); + assertEquals(date.dayOfMonth(), 6); + assertEquals(date.month(), 11); + assertEquals(date.year(), 1994); + assertEquals(date.hour(), 8); + assertEquals(date.minute(), 49); + assertEquals(date.second(), 37); + } + + @Test(groups = "fast") + public void testANSIC() { + RFC2616Date date = new RFC2616DateParser("Sun Nov 6 08:49:37 1994").parse(); + assertNotNull(date); + assertEquals(date.dayOfMonth(), 6); + assertEquals(date.month(), 11); + assertEquals(date.year(), 1994); + assertEquals(date.hour(), 8); + assertEquals(date.minute(), 49); + assertEquals(date.second(), 37); + } +} 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..135e13fe0e 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,10 +13,7 @@ package com.ning.http.client.providers.netty; -import com.ning.http.client.Cookie; -import com.ning.http.client.FluentCaseInsensitiveStringsMap; -import com.ning.http.client.HttpResponseHeaders; -import org.testng.annotations.Test; +import static org.testng.Assert.assertEquals; import java.text.SimpleDateFormat; import java.util.Date; @@ -24,8 +21,11 @@ import java.util.Locale; import java.util.TimeZone; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertTrue; +import org.testng.annotations.Test; + +import com.ning.http.client.FluentCaseInsensitiveStringsMap; +import com.ning.http.client.HttpResponseHeaders; +import com.ning.http.client.cookie.Cookie; /** * @author Benjamin Hanzelmann @@ -52,7 +52,8 @@ public FluentCaseInsensitiveStringsMap getHeaders() { assertEquals(cookies.size(), 1); Cookie cookie = cookies.get(0); - assertTrue(cookie.getMaxAge() > 55 && cookie.getMaxAge() < 61, ""); + long originalDateWith1SecPrecision = date.getTime() / 1000 * 1000; + assertEquals(cookie.getExpires(), originalDateWith1SecPrecision); } @Test(groups = "standalone") @@ -85,7 +86,7 @@ public FluentCaseInsensitiveStringsMap getHeaders() { assertEquals(cookies.size(), 1); Cookie cookie = cookies.get(0); - assertEquals(cookie.getMaxAge(), 60); + assertEquals(cookie.getExpires(), -1L); } } 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 deleted file mode 100644 index 6e7f35b3ae..0000000000 --- a/src/test/java/com/ning/org/jboss/netty/handler/codec/http/CookieDecoderTest.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * 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.List; - -import org.testng.Assert; -import org.testng.annotations.Test; - -import com.ning.http.client.Cookie; - -public class CookieDecoderTest { - - @Test(groups = "fast") - public void testDecodeUnquoted() { - List cookies = CookieDecoder.decode("foo=value; domain=/; path=/"); - Assert.assertEquals(cookies.size(), 1); - - Cookie first = cookies.get(0); - Assert.assertEquals(first.getValue(), "value"); - Assert.assertEquals(first.getDomain(), "/"); - Assert.assertEquals(first.getPath(), "/"); - } - - @Test(groups = "fast") - public void testDecodeQuoted() { - List cookies = CookieDecoder.decode("ALPHA=\"VALUE1\"; Domain=docs.foo.com; Path=/accounts; Expires=Wed, 05 Feb 2014 07:37:38 GMT; Secure; HttpOnly"); - Assert.assertEquals(cookies.size(), 1); - - Cookie first = cookies.get(0); - Assert.assertEquals(first.getValue(), "VALUE1"); - } - - @Test(groups = "fast") - public void testDecodeQuotedContainingEscapedQuote() { - List cookies = CookieDecoder.decode("ALPHA=\"VALUE1\\\"\"; Domain=docs.foo.com; Path=/accounts; Expires=Wed, 05 Feb 2014 07:37:38 GMT; Secure; HttpOnly"); - Assert.assertEquals(cookies.size(), 1); - - Cookie first = cookies.get(0); - Assert.assertEquals(first.getValue(), "VALUE1\""); - } -} From d9790c2b387fe3a7f51f45867bbb7ba95c747a30 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 7 Feb 2014 16:40:58 +0100 Subject: [PATCH 223/701] Abort and cancel should set cancelled early, close #477 --- .../http/client/providers/netty/NettyResponseFuture.java | 8 +++----- 1 file changed, 3 insertions(+), 5 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 00a3132fa0..ff6413aafd 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 @@ -163,7 +163,7 @@ void setAsyncHandler(AsyncHandler asyncHandler) { public boolean cancel(boolean force) { cancelTimeouts(); - if (isCancelled.get()) + if (isCancelled.getAndSet(true)) return false; try { @@ -180,7 +180,6 @@ public boolean cancel(boolean force) { } } latch.countDown(); - isCancelled.set(true); runListeners(); return true; } @@ -335,17 +334,16 @@ public final void done() { public final void abort(final Throwable t) { cancelTimeouts(); - if (isDone.get() || isCancelled.get()) + if (isDone.get() || isCancelled.getAndSet(true)) return; + isCancelled.set(true); exEx.compareAndSet(null, new ExecutionException(t)); if (onThrowableCalled.compareAndSet(false, true)) { try { asyncHandler.onThrowable(t); } catch (Throwable te) { logger.debug("asyncHandler.onThrowable", te); - } finally { - isCancelled.set(true); } } latch.countDown(); From 4fb442bde4893b00eb779910e572a21edd3b71a2 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 7 Feb 2014 16:55:41 +0100 Subject: [PATCH 224/701] Reorganize Cookie constructor parameters order, close #478 --- src/main/java/com/ning/http/client/cookie/Cookie.java | 10 +++++----- .../ning/http/client/cookie/KeyValuePairsParser.java | 2 +- .../http/client/providers/grizzly/GrizzlyResponse.java | 4 ++-- .../http/client/async/AsyncProvidersBasicTest.java | 2 +- .../com/ning/http/client/async/RemoteSiteTest.java | 2 +- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/ning/http/client/cookie/Cookie.java b/src/main/java/com/ning/http/client/cookie/Cookie.java index 80679e13a0..469f5e482b 100644 --- a/src/main/java/com/ning/http/client/cookie/Cookie.java +++ b/src/main/java/com/ning/http/client/cookie/Cookie.java @@ -14,7 +14,7 @@ public class Cookie { - public static Cookie newValidCookie(String domain, String name, String value, String rawValue, String path, long expires, int maxAge, boolean secure, boolean httpOnly) { + public static Cookie newValidCookie(String name, String value, String domain, String rawValue, String path, long expires, int maxAge, boolean secure, boolean httpOnly) { if (name == null) { throw new NullPointerException("name"); @@ -56,7 +56,7 @@ public static Cookie newValidCookie(String domain, String name, String value, St domain = validateValue("domain", domain); path = validateValue("path", path); - return new Cookie(domain, name, value, rawValue, path, expires, maxAge, secure, httpOnly); + return new Cookie(name, value, rawValue, domain, path, expires, maxAge, secure, httpOnly); } private static String validateValue(String name, String value) { @@ -82,21 +82,21 @@ private static String validateValue(String name, String value) { return value; } - private final String domain; private final String name; private final String value; private final String rawValue; + private final String domain; private final String path; private long expires; private final int maxAge; private final boolean secure; private final boolean httpOnly; - public Cookie(String domain, String name, String value, String rawValue, String path, long expires, int maxAge, boolean secure, boolean httpOnly) { - this.domain = domain; + public Cookie(String name, String value, String rawValue, String domain, String path, long expires, int maxAge, boolean secure, boolean httpOnly) { this.name = name; this.value = value; this.rawValue = rawValue; + this.domain = domain; this.path = path; this.expires = expires; this.maxAge = maxAge; diff --git a/src/main/java/com/ning/http/client/cookie/KeyValuePairsParser.java b/src/main/java/com/ning/http/client/cookie/KeyValuePairsParser.java index f01b97e1a0..4dbc5223ca 100644 --- a/src/main/java/com/ning/http/client/cookie/KeyValuePairsParser.java +++ b/src/main/java/com/ning/http/client/cookie/KeyValuePairsParser.java @@ -43,7 +43,7 @@ public KeyValuePairsParser(TimeConverter timeBuilder) { } public Cookie cookie() { - return name != null ? new Cookie(domain, name, value, rawValue, path, expires, maxAge, secure, httpOnly) : null; + return name != null ? new Cookie(name, value, rawValue, domain, path, expires, maxAge, secure, httpOnly) : null; } /** 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 469327752f..f9eecf49cc 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 @@ -321,10 +321,10 @@ private List convertCookies(Cookies cookies) { final org.glassfish.grizzly.http.Cookie[] grizzlyCookies = cookies.get(); List convertedCookies = new ArrayList(grizzlyCookies.length); for (org.glassfish.grizzly.http.Cookie gCookie : grizzlyCookies) { - convertedCookies.add(new Cookie(gCookie.getDomain(), - gCookie.getName(), + convertedCookies.add(new Cookie(gCookie.getName(), gCookie.getValue(), gCookie.getValue(), + gCookie.getDomain(), gCookie.getPath(), -1L, gCookie.getMaxAge(), 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 257f75554d..b181a447ef 100755 --- a/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java +++ b/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java @@ -478,7 +478,7 @@ public void asyncDoGetCookieTest() throws Throwable { h.add("Test4", "Test4"); h.add("Test5", "Test5"); - final Cookie coo = new Cookie("/", "foo", "value", "value", "/", -1L, -1, false, false); + final Cookie coo = new Cookie("foo", "value", "value", "/", "/", -1L, -1, false, false); client.prepareGet(getTargetUrl()).setHeaders(h).addCookie(coo).execute(new AsyncCompletionHandlerAdapter() { @Override 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 51fb798756..52157c03de 100644 --- a/src/test/java/com/ning/http/client/async/RemoteSiteTest.java +++ b/src/test/java/com/ning/http/client/async/RemoteSiteTest.java @@ -249,7 +249,7 @@ public void evilCoookieTest() throws Throwable { builder2.setFollowRedirects(true); builder2.setUrl("http://www.google.com/"); builder2.addHeader("Content-Type", "text/plain"); - builder2.addCookie(new Cookie(".google.com", "evilcookie", "test", "test", "/", -1L, 10, false, false)); + builder2.addCookie(new Cookie("evilcookie", "test", "test", ".google.com", "/", -1L, 10, false, false)); com.ning.http.client.Request request2 = builder2.build(); Response response = c.executeRequest(request2).get(); From c87ff4221ae8bfa53cc1de8af9f1fb478ffed775 Mon Sep 17 00:00:00 2001 From: jfarcand Date: Fri, 7 Feb 2014 11:20:48 -0500 Subject: [PATCH 225/701] [maven-release-plugin] prepare release async-http-client-1.8.2 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index b1194eb343..2a99bf767d 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.8.2-SNAPSHOT + 1.8.2 jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From b88bacae71e282d53bb83a94f9a94831d0646e95 Mon Sep 17 00:00:00 2001 From: jfarcand Date: Fri, 7 Feb 2014 11:20:51 -0500 Subject: [PATCH 226/701] [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 2a99bf767d..ea29765cc5 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.8.2 + 1.8.3-SNAPSHOT jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From 53103d14edc9459b597e70c28b2e5c4c46b6ea91 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 7 Feb 2014 18:08:33 +0100 Subject: [PATCH 227/701] setTimeConverter should return the builder --- src/main/java/com/ning/http/client/AsyncHttpClientConfig.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java b/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java index 31ddb60488..974f19694a 100644 --- a/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java @@ -1028,8 +1028,9 @@ public Builder setMaxConnectionLifeTimeInMs(int maxConnectionLifeTimeInMs) { return this; } - public void setTimeConverter(TimeConverter timeConverter) { + public Builder setTimeConverter(TimeConverter timeConverter) { this.timeConverter = timeConverter; + return this; } /** From 6660dc7c9856cce905c530bb679d2d806941b26f Mon Sep 17 00:00:00 2001 From: Ryan Lubke Date: Fri, 7 Feb 2014 12:26:11 -0800 Subject: [PATCH 228/701] Ensure the proper Request URI is associated with the response headers. --- .../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 9203377c9a..b4030b2a71 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 @@ -1254,7 +1254,7 @@ protected void onHttpHeadersParsed(HttpHeader httpHeader, final AsyncHandler handler = context.handler; final List filters = context.provider.clientConfig.getResponseFilters(); final GrizzlyResponseHeaders responseHeaders = new GrizzlyResponseHeaders((HttpResponsePacket) httpHeader, - null, + context.request.getURI(), provider); if (!filters.isEmpty()) { FilterContext fc = new FilterContext.FilterContextBuilder() From 065b8271f3f33c088f72e895d751c90b6243d557 Mon Sep 17 00:00:00 2001 From: jfarcand Date: Mon, 10 Feb 2014 15:21:22 -0500 Subject: [PATCH 229/701] [maven-release-plugin] prepare release async-http-client-1.8.3 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index ea29765cc5..ba8122a3b4 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.8.3-SNAPSHOT + 1.8.3 jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From d264daef79a3b439086993fd2eaf2ed25c62e0f4 Mon Sep 17 00:00:00 2001 From: jfarcand Date: Mon, 10 Feb 2014 15:21:25 -0500 Subject: [PATCH 230/701] [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 ba8122a3b4..ad80a4a2f0 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.8.3 + 1.8.4-SNAPSHOT jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From eda2baed8b9fe459f6d4b9590a1bb4c03fa0f2c6 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 18 Feb 2014 10:29:31 +0100 Subject: [PATCH 231/701] Enable setting Netty SslHandler handshake timeout, close #481 --- .../providers/netty/NettyAsyncHttpProvider.java | 15 +++++++++++---- .../netty/NettyAsyncHttpProviderConfig.java | 10 ++++++++++ 2 files changed, 21 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 96386b25eb..228d6fbf43 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 @@ -30,6 +30,7 @@ import static com.ning.http.util.AsyncHttpProviderUtils.DEFAULT_CHARSET; import static com.ning.http.util.MiscUtil.isNonEmpty; import static org.jboss.netty.channel.Channels.pipeline; +import static org.jboss.netty.handler.ssl.SslHandler.getDefaultBufferPool; import java.io.File; import java.io.FileInputStream; @@ -97,6 +98,7 @@ 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; +import org.jboss.netty.handler.ssl.ImmediateExecutor; import org.jboss.netty.handler.ssl.SslHandler; import org.jboss.netty.handler.stream.ChunkedFile; import org.jboss.netty.handler.stream.ChunkedWriteHandler; @@ -129,7 +131,6 @@ import com.ning.http.client.Request; import com.ning.http.client.RequestBuilder; import com.ning.http.client.Response; -import com.ning.http.client.cookie.Cookie; import com.ning.http.client.cookie.CookieDecoder; import com.ning.http.client.cookie.CookieEncoder; import com.ning.http.client.filter.FilterContext; @@ -215,6 +216,7 @@ public boolean remove(Object o) { private final Protocol webSocketProtocol = new WebSocketProtocol(); private final boolean allowStopHashedWheelTimer; private final HashedWheelTimer hashedWheelTimer; + private final long handshakeTimeoutInMillis; private static boolean isNTLM(List auth) { return isNonEmpty(auth) && auth.get(0).startsWith("NTLM"); @@ -262,6 +264,8 @@ public NettyAsyncHttpProvider(AsyncHttpClientConfig config) { hashedWheelTimer = allowStopHashedWheelTimer ? new HashedWheelTimer() : providerConfig.getHashedWheelTimer(); hashedWheelTimer.start(); + handshakeTimeoutInMillis = providerConfig.getHandshakeTimeoutInMillis(); + plainBootstrap = new ClientBootstrap(socketChannelFactory); secureBootstrap = new ClientBootstrap(socketChannelFactory); webSocketBootstrap = new ClientBootstrap(socketChannelFactory); @@ -367,7 +371,10 @@ public ChannelPipeline getPipeline() throws Exception { ChannelPipeline pipeline = pipeline(); try { - pipeline.addLast(SSL_HANDLER, new SslHandler(createSSLEngine())); + SSLEngine sslEngine = createSSLEngine(); + SslHandler sslHandler = handshakeTimeoutInMillis > 0 ? new SslHandler(sslEngine, getDefaultBufferPool(), false, ImmediateExecutor.INSTANCE, hashedWheelTimer, + handshakeTimeoutInMillis) : new SslHandler(sslEngine); + pipeline.addLast(SSL_HANDLER, sslHandler); } catch (Throwable ex) { abort(cl.future(), ex); } @@ -1060,8 +1067,8 @@ private ListenableFuture doConnect(final Request request, final AsyncHand } ChannelFuture channelFuture; - ClientBootstrap bootstrap = (request.getUrl().startsWith(WEBSOCKET) && !useProxy) ? - (useSSl ? secureWebSocketBootstrap : webSocketBootstrap) : (useSSl ? secureBootstrap : plainBootstrap); + ClientBootstrap bootstrap = (request.getUrl().startsWith(WEBSOCKET) && !useProxy) ? (useSSl ? secureWebSocketBootstrap : webSocketBootstrap) : (useSSl ? secureBootstrap + : plainBootstrap); bootstrap.setOption("connectTimeoutMillis", config.getConnectionTimeoutInMs()); // Do no enable this with win. 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 748900b95e..e287e97977 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 @@ -86,6 +86,8 @@ public class NettyAsyncHttpProviderConfig implements AsyncHttpProviderConfig Date: Tue, 18 Feb 2014 11:13:41 +0100 Subject: [PATCH 232/701] Add a test about the server replying 401 while the client uploads a big file --- .../async/FastUnauthorizedUploadTest.java | 67 +++++++++++++++++++ .../client/async/FilePartLargeFileTest.java | 12 +--- .../NettyFastUnauthorizedUploadTest.java | 28 ++++++++ 3 files changed, 97 insertions(+), 10 deletions(-) create mode 100644 src/test/java/com/ning/http/client/async/FastUnauthorizedUploadTest.java create mode 100644 src/test/java/com/ning/http/client/async/netty/NettyFastUnauthorizedUploadTest.java diff --git a/src/test/java/com/ning/http/client/async/FastUnauthorizedUploadTest.java b/src/test/java/com/ning/http/client/async/FastUnauthorizedUploadTest.java new file mode 100644 index 0000000000..8d59a47bdf --- /dev/null +++ b/src/test/java/com/ning/http/client/async/FastUnauthorizedUploadTest.java @@ -0,0 +1,67 @@ +/* + * 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; + +import java.io.File; +import java.io.IOException; + +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.Assert; +import org.testng.annotations.Test; + +import com.ning.http.client.AsyncHttpClient; +import com.ning.http.client.AsyncHttpClient.BoundRequestBuilder; +import com.ning.http.client.FilePart; +import com.ning.http.client.Response; + +public abstract class FastUnauthorizedUploadTest extends AbstractBasicTest { + + @Override + public AbstractHandler configureHandler() throws Exception { + return new AbstractHandler() { + + public void handle(String target, Request baseRequest, HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException { + + resp.setStatus(401); + resp.getOutputStream().flush(); + resp.getOutputStream().close(); + + baseRequest.setHandled(true); + } + }; + } + + @Test(groups = { "standalone", "default_provider" }, enabled = true) + public void testUnauthorizedWhileUploading() throws Exception { + byte[] bytes = "RatherLargeFileRatherLargeFileRatherLargeFileRatherLargeFile".getBytes("UTF-16"); + long repeats = (1024 * 1024 / bytes.length) + 1; + File largeFile = FilePartLargeFileTest.createTempFile(bytes, (int) repeats); + + AsyncHttpClient client = getAsyncHttpClient(null); + try { + BoundRequestBuilder rb = client.preparePut(getTargetUrl()); + + rb.addBodyPart(new FilePart("test", largeFile, "application/octet-stream", "UTF-8")); + + Response response = rb.execute().get(); + Assert.assertEquals(401, response.getStatusCode()); + } finally { + client.close(); + } + } +} 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 49af5aa4c6..3ecaad9d0c 100644 --- a/src/test/java/com/ning/http/client/async/FilePartLargeFileTest.java +++ b/src/test/java/com/ning/http/client/async/FilePartLargeFileTest.java @@ -28,7 +28,6 @@ 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; @@ -39,11 +38,9 @@ public abstract class FilePartLargeFileTest extends AbstractBasicTest { - private File largeFile; - @Test(groups = { "standalone", "default_provider" }, enabled = true) public void testPutImageFile() throws Exception { - largeFile = getTestFile(); + File largeFile = getTestFile(); AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder().setRequestTimeoutInMs(100 * 6000).build(); AsyncHttpClient client = getAsyncHttpClient(config); try { @@ -62,7 +59,7 @@ public void testPutImageFile() throws Exception { public void testPutLargeTextFile() throws Exception { byte[] bytes = "RatherLargeFileRatherLargeFileRatherLargeFileRatherLargeFile".getBytes("UTF-16"); long repeats = (1024 * 1024 / bytes.length) + 1; - largeFile = createTempFile(bytes, (int) repeats); + File largeFile = createTempFile(bytes, (int) repeats); AsyncHttpClient client = getAsyncHttpClient(null); try { @@ -93,11 +90,6 @@ private static File getTestFile() { return testResource1File; } - @AfterMethod - public void after() { - largeFile.delete(); - } - @Override public AbstractHandler configureHandler() throws Exception { return new AbstractHandler() { diff --git a/src/test/java/com/ning/http/client/async/netty/NettyFastUnauthorizedUploadTest.java b/src/test/java/com/ning/http/client/async/netty/NettyFastUnauthorizedUploadTest.java new file mode 100644 index 0000000000..c77130d54d --- /dev/null +++ b/src/test/java/com/ning/http/client/async/netty/NettyFastUnauthorizedUploadTest.java @@ -0,0 +1,28 @@ +/* + * 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 org.testng.annotations.Test; + +import com.ning.http.client.AsyncHttpClient; +import com.ning.http.client.AsyncHttpClientConfig; +import com.ning.http.client.async.FastUnauthorizedUploadTest; +import com.ning.http.client.async.ProviderUtil; + +@Test +public class NettyFastUnauthorizedUploadTest extends FastUnauthorizedUploadTest { + @Override + public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { + return ProviderUtil.nettyProvider(config); + } +} From 3e73df6ee84a5cdaf42cdc131ba1dfddb3854156 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 18 Feb 2014 11:13:49 +0100 Subject: [PATCH 233/701] minor clean up --- .../java/com/ning/http/client/async/PostRedirectGetTest.java | 2 -- 1 file changed, 2 deletions(-) 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 e581b9f8ab..19407a095d 100644 --- a/src/test/java/com/ning/http/client/async/PostRedirectGetTest.java +++ b/src/test/java/com/ning/http/client/async/PostRedirectGetTest.java @@ -73,7 +73,6 @@ public void postRedirectGet307Test() throws Exception { 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 @@ -108,7 +107,6 @@ public void onThrowable(Throwable t) { 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 From 51f088faf1cb52550088d058de4dc76ffda62da1 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 18 Feb 2014 11:31:02 +0100 Subject: [PATCH 234/701] Disable failing test on Grizzly provider --- .../client/async/grizzly/GrizzlyAsyncProviderBasicTest.java | 5 +++++ 1 file changed, 5 insertions(+) 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 739bb8f4f1..4b8ae23d1c 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 @@ -57,4 +57,9 @@ public void customize(TCPNIOTransport transport, FilterChainBuilder builder) { @Test(groups = { "standalone", "default_provider", "async" }, enabled = false) public void asyncDoPostBasicGZIPTest() throws Throwable { } + + @Test(groups = { "standalone", "default_provider", "async" }, enabled = false) + public void asyncDoGetCookieTest() throws Throwable { + // FIXME server replies with a foo=bar cookie and yet Grizzly decodes it into foo=value; domain=/; path=/ + } } From 28ce378dd957b33a258198a2374be7e6ef806f1f Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 19 Feb 2014 12:14:30 +0100 Subject: [PATCH 235/701] typo --- .../{ProxyyTunnellingTest.java => ProxyTunnellingTest.java} | 2 +- .../http/client/async/grizzly/GrizzlyProxyTunnelingTest.java | 4 ++-- .../http/client/async/netty/NettyProxyTunnellingTest.java | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) rename src/test/java/com/ning/http/client/async/{ProxyyTunnellingTest.java => ProxyTunnellingTest.java} (99%) diff --git a/src/test/java/com/ning/http/client/async/ProxyyTunnellingTest.java b/src/test/java/com/ning/http/client/async/ProxyTunnellingTest.java similarity index 99% rename from src/test/java/com/ning/http/client/async/ProxyyTunnellingTest.java rename to src/test/java/com/ning/http/client/async/ProxyTunnellingTest.java index da2a0756f3..e2c2c134cf 100644 --- a/src/test/java/com/ning/http/client/async/ProxyyTunnellingTest.java +++ b/src/test/java/com/ning/http/client/async/ProxyTunnellingTest.java @@ -43,7 +43,7 @@ /** * Proxy usage tests. */ -public abstract class ProxyyTunnellingTest extends AbstractBasicTest { +public abstract class ProxyTunnellingTest extends AbstractBasicTest { private Server server2; 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 8f112b2af0..f7e4c919b7 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 @@ -16,9 +16,9 @@ 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.async.ProxyTunnellingTest; -public class GrizzlyProxyTunnelingTest extends ProxyyTunnellingTest { +public class GrizzlyProxyTunnelingTest extends ProxyTunnellingTest { @Override public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { diff --git a/src/test/java/com/ning/http/client/async/netty/NettyProxyTunnellingTest.java b/src/test/java/com/ning/http/client/async/netty/NettyProxyTunnellingTest.java index b0a8f6fa1d..a07028b865 100644 --- a/src/test/java/com/ning/http/client/async/netty/NettyProxyTunnellingTest.java +++ b/src/test/java/com/ning/http/client/async/netty/NettyProxyTunnellingTest.java @@ -15,9 +15,9 @@ 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.async.ProxyTunnellingTest; -public class NettyProxyTunnellingTest extends ProxyyTunnellingTest { +public class NettyProxyTunnellingTest extends ProxyTunnellingTest { @Override public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { return ProviderUtil.nettyProvider(config); From dde2652255a945d65e1edb9da663924c3715c0bd Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 19 Feb 2014 17:23:09 +0100 Subject: [PATCH 236/701] Backport test for wss proxy tunneling: both providers are fine on this branch --- .../client/websocket/ProxyTunnellingTest.java | 153 ++++++++++++++++++ .../grizzly/GrizzlyProxyTunnellingTest.java | 29 ++++ .../netty/NettyProxyTunnellingTest.java | 29 ++++ 3 files changed, 211 insertions(+) create mode 100644 src/test/java/com/ning/http/client/websocket/ProxyTunnellingTest.java create mode 100644 src/test/java/com/ning/http/client/websocket/grizzly/GrizzlyProxyTunnellingTest.java create mode 100644 src/test/java/com/ning/http/client/websocket/netty/NettyProxyTunnellingTest.java diff --git a/src/test/java/com/ning/http/client/websocket/ProxyTunnellingTest.java b/src/test/java/com/ning/http/client/websocket/ProxyTunnellingTest.java new file mode 100644 index 0000000000..90e22d98a0 --- /dev/null +++ b/src/test/java/com/ning/http/client/websocket/ProxyTunnellingTest.java @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2014 AsyncHttpClient Project. 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.websocket; + +import static org.testng.Assert.assertEquals; + +import java.io.File; +import java.net.URL; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicReference; + +import javax.servlet.http.HttpServletRequest; + +import org.eclipse.jetty.server.Connector; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.handler.AbstractHandler; +import org.eclipse.jetty.server.handler.ProxyHandler; +import org.eclipse.jetty.server.nio.SelectChannelConnector; +import org.eclipse.jetty.server.ssl.SslSelectChannelConnector; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; + +import com.ning.http.client.AsyncHttpClient; +import com.ning.http.client.AsyncHttpClientConfig; +import com.ning.http.client.ProxyServer; +import com.ning.http.client.websocket.TextMessageTest.EchoTextWebSocket; + +/** + * Proxy usage tests. + */ +public abstract class ProxyTunnellingTest extends AbstractBasicTest { + + int port2; + private Server server2; + + public AbstractHandler configureHandler() throws Exception { + ProxyHandler proxy = new ProxyHandler(); + return proxy; + } + + @BeforeClass(alwaysRun = true) + public void setUpGlobal() throws Exception { + server2 = new Server(); + + port1 = findFreePort(); + port2 = findFreePort(); + + Connector listener = new SelectChannelConnector(); + + listener.setHost("127.0.0.1"); + listener.setPort(port1); + + addConnector(listener); + + SslSelectChannelConnector connector = new SslSelectChannelConnector(); + connector.setHost("127.0.0.1"); + connector.setPort(port2); + + ClassLoader cl = getClass().getClassLoader(); + URL keystoreUrl = cl.getResource("ssltest-keystore.jks"); + String keyStoreFile = new File(keystoreUrl.toURI()).getAbsolutePath(); + connector.setKeystore(keyStoreFile); + connector.setKeyPassword("changeit"); + connector.setKeystoreType("JKS"); + + server2.addConnector(connector); + + setHandler(configureHandler()); + start(); + + server2.setHandler(getWebSocketHandler()); + server2.start(); + log.info("Local HTTP server started successfully"); + } + + @Override + public WebSocketHandler getWebSocketHandler() { + return new WebSocketHandler() { + @Override + public org.eclipse.jetty.websocket.WebSocket doWebSocketConnect(HttpServletRequest httpServletRequest, String s) { + return new EchoTextWebSocket(); + } + }; + } + + @AfterClass(alwaysRun = true) + public void tearDownGlobal() throws Exception { + stop(); + server2.stop(); + } + + protected String getTargetUrl() { + return String.format("wss://127.0.0.1:%d/", port2); + } + + @Test(timeOut = 60000) + public void echoText() throws Exception { + + ProxyServer ps = new ProxyServer(ProxyServer.Protocol.HTTPS, "127.0.0.1", port1); + AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder().setProxyServer(ps).build(); + AsyncHttpClient asyncHttpClient = getAsyncHttpClient(config); + try { + final CountDownLatch latch = new CountDownLatch(1); + final AtomicReference text = new AtomicReference(""); + + WebSocket websocket = asyncHttpClient.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(WebSocket websocket) { + } + + @Override + public void onClose(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 { + asyncHttpClient.close(); + } + } +} diff --git a/src/test/java/com/ning/http/client/websocket/grizzly/GrizzlyProxyTunnellingTest.java b/src/test/java/com/ning/http/client/websocket/grizzly/GrizzlyProxyTunnellingTest.java new file mode 100644 index 0000000000..d76c131944 --- /dev/null +++ b/src/test/java/com/ning/http/client/websocket/grizzly/GrizzlyProxyTunnellingTest.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2014 AsyncHttpClient Project. 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.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.websocket.ProxyTunnellingTest; + +@Test +public class GrizzlyProxyTunnellingTest extends ProxyTunnellingTest { + + @Override + public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { + return ProviderUtil.grizzlyProvider(config); + } +} diff --git a/src/test/java/com/ning/http/client/websocket/netty/NettyProxyTunnellingTest.java b/src/test/java/com/ning/http/client/websocket/netty/NettyProxyTunnellingTest.java new file mode 100644 index 0000000000..538a516895 --- /dev/null +++ b/src/test/java/com/ning/http/client/websocket/netty/NettyProxyTunnellingTest.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2014 AsyncHttpClient Project. 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.websocket.netty; + +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.websocket.ProxyTunnellingTest; + +@Test +public class NettyProxyTunnellingTest extends ProxyTunnellingTest { + + @Override + public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { + return ProviderUtil.nettyProvider(config); + } +} From cfaa079f1a09cb9f362631e9d178eb10294728af Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 19 Feb 2014 20:51:02 +0100 Subject: [PATCH 237/701] ProxyHandler is deprecated in favor of ConnectHandler --- .../http/client/websocket/ProxyTunnellingTest.java | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/test/java/com/ning/http/client/websocket/ProxyTunnellingTest.java b/src/test/java/com/ning/http/client/websocket/ProxyTunnellingTest.java index 90e22d98a0..932fcaf20c 100644 --- a/src/test/java/com/ning/http/client/websocket/ProxyTunnellingTest.java +++ b/src/test/java/com/ning/http/client/websocket/ProxyTunnellingTest.java @@ -23,8 +23,7 @@ import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.server.handler.AbstractHandler; -import org.eclipse.jetty.server.handler.ProxyHandler; +import org.eclipse.jetty.server.handler.ConnectHandler; import org.eclipse.jetty.server.nio.SelectChannelConnector; import org.eclipse.jetty.server.ssl.SslSelectChannelConnector; import org.testng.annotations.AfterClass; @@ -44,11 +43,6 @@ public abstract class ProxyTunnellingTest extends AbstractBasicTest { int port2; private Server server2; - public AbstractHandler configureHandler() throws Exception { - ProxyHandler proxy = new ProxyHandler(); - return proxy; - } - @BeforeClass(alwaysRun = true) public void setUpGlobal() throws Exception { server2 = new Server(); @@ -76,7 +70,7 @@ public void setUpGlobal() throws Exception { server2.addConnector(connector); - setHandler(configureHandler()); + setHandler(new ConnectHandler()); start(); server2.setHandler(getWebSocketHandler()); From 3cff8623bcf5e454f6f4f7bfa4aed88a63426a19 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 19 Feb 2014 21:17:43 +0100 Subject: [PATCH 238/701] Default 10sec SSL handshake timeout, close #483 --- .../client/providers/netty/NettyAsyncHttpProviderConfig.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 e287e97977..d57090f170 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 @@ -87,7 +87,7 @@ public class NettyAsyncHttpProviderConfig implements AsyncHttpProviderConfig Date: Thu, 20 Feb 2014 17:39:43 +0100 Subject: [PATCH 239/701] Minor clean up --- src/main/java/com/ning/http/client/Realm.java | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/ning/http/client/Realm.java b/src/main/java/com/ning/http/client/Realm.java index 2d7899bbdb..95b2255357 100644 --- a/src/main/java/com/ning/http/client/Realm.java +++ b/src/main/java/com/ning/http/client/Realm.java @@ -18,13 +18,12 @@ import static com.ning.http.util.MiscUtil.isNonEmpty; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import java.io.UnsupportedEncodingException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; +import com.ning.http.util.MiscUtil; + /** * This class is required when authentication is needed. The class support DIGEST and BASIC. */ @@ -260,8 +259,6 @@ public int hashCode() { */ public static class RealmBuilder { - private static final Logger logger = LoggerFactory.getLogger(RealmBuilder.class); - // // Portions of code (newCnonce, newResponse) are highly inspired be Jetty 6 BasicAuthentication.java class. // This code is already Apache licenced. @@ -439,7 +436,7 @@ public RealmBuilder parseWWWAuthenticateHeader(String headerLine) { setAlgorithm(match(headerLine, "algorithm")); setOpaque(match(headerLine, "opaque")); setQop(match(headerLine, "qop")); - if (getNonce() != null && !getNonce().equalsIgnoreCase("")) { + if (isNonEmpty(getNonce())) { setScheme(AuthScheme.DIGEST); } else { setScheme(AuthScheme.BASIC); From aafd735584e6a4e59a0c86fb13e0b865f337b4ab Mon Sep 17 00:00:00 2001 From: dominictootell Date: Sun, 23 Feb 2014 10:55:15 +0000 Subject: [PATCH 240/701] free semaphore permit is future is cancelled or done before channel is added to cleanup group --- .../netty/NettyAsyncHttpProvider.java | 4 ++ .../async/netty/NettyConnectionPoolTest.java | 38 ++++++++++++++++++- 2 files changed, 41 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 228d6fbf43..384c1a16a3 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 @@ -1136,6 +1136,10 @@ private ListenableFuture doConnect(final Request request, final AsyncHand if (!c.future().isCancelled() || !c.future().isDone()) { openChannels.add(channelFuture.getChannel()); c.future().attachChannel(channelFuture.getChannel(), false); + } else { + if (acquiredConnection) { + freeConnections.release(); + } } return c.future(); } diff --git a/src/test/java/com/ning/http/client/async/netty/NettyConnectionPoolTest.java b/src/test/java/com/ning/http/client/async/netty/NettyConnectionPoolTest.java index b1e08a0252..ac2333ddf5 100644 --- a/src/test/java/com/ning/http/client/async/netty/NettyConnectionPoolTest.java +++ b/src/test/java/com/ning/http/client/async/netty/NettyConnectionPoolTest.java @@ -15,9 +15,13 @@ import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertNull; - +import static org.testng.Assert.assertTrue; +import static org.testng.Assert.fail; +import java.net.ConnectException; import java.util.concurrent.TimeUnit; +import com.ning.http.client.Response; +import com.ning.http.client.providers.netty.NettyAsyncHttpProviderConfig; import org.jboss.netty.channel.Channel; import org.testng.annotations.Test; @@ -116,4 +120,36 @@ public void destroy() { client.close(); } } + + @Test + public void testHostNotContactable() { + NettyAsyncHttpProviderConfig conf = new NettyAsyncHttpProviderConfig(); + conf.addProperty(NettyAsyncHttpProviderConfig.EXECUTE_ASYNC_CONNECT,false); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setAsyncHttpClientProviderConfig(conf) + .setAllowPoolingConnection(true).setMaximumConnectionsTotal(1).build()); + try { + String url = null; + try { + url = "http://127.0.0.1:" + findFreePort(); + } catch (Exception e) { + fail("unable to find free port to simulate downed host"); + } + int i; + for (i = 0; i < 2; i++) { + try { + log.info("{} requesting url [{}]...", i, url); + Response response = client.prepareGet(url).execute().get(); + log.info("{} response [{}].", i, response); + } catch (Exception ex) { + assertNotNull(ex.getCause()); + Throwable cause = ex.getCause(); + assertTrue(cause instanceof ConnectException); + } + } + } finally { + client.close(); + } + } + + } From 88ac2d9cf2b873d69be306bd2e4ccd74d5a9d05b Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 27 Feb 2014 11:19:52 +0100 Subject: [PATCH 241/701] Backport #492 --- .../com/ning/http/client/resumable/ResumableAsyncHandler.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) 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 53ebec5cdb..ac023a28c2 100644 --- a/src/main/java/com/ning/http/client/resumable/ResumableAsyncHandler.java +++ b/src/main/java/com/ning/http/client/resumable/ResumableAsyncHandler.java @@ -41,7 +41,6 @@ public class ResumableAsyncHandler implements AsyncHandler { private final static Logger logger = LoggerFactory.getLogger(TransferCompletionHandler.class); private final AtomicLong byteTransferred; - private Integer contentLength; private String url; private final ResumableProcessor resumableProcessor; private final AsyncHandler decoratedAsyncHandler; @@ -179,8 +178,7 @@ public AsyncHandler.STATE onHeadersReceived(HttpResponseHeaders headers) throws responseBuilder.accumulate(headers); String contentLengthHeader = headers.getHeaders().getFirstValue("Content-Length"); if (contentLengthHeader != null) { - contentLength = Integer.valueOf(contentLengthHeader); - if (contentLength == null || contentLength == -1) { + if (Long.parseLong(contentLengthHeader) == -1L) { return AsyncHandler.STATE.ABORT; } } From 01611a0a6ab0d8b74b97882f290150bc48f2fbef Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 7 Mar 2014 15:28:52 +0100 Subject: [PATCH 242/701] Back SpnegoEngine thread safety fix from #95, close #94 --- .../client/providers/netty/spnego/SpnegoEngine.java | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/spnego/SpnegoEngine.java b/src/main/java/com/ning/http/client/providers/netty/spnego/SpnegoEngine.java index ef777569a5..58417958be 100644 --- a/src/main/java/com/ning/http/client/providers/netty/spnego/SpnegoEngine.java +++ b/src/main/java/com/ning/http/client/providers/netty/spnego/SpnegoEngine.java @@ -62,15 +62,6 @@ public class SpnegoEngine { private final SpnegoTokenGenerator spnegoGenerator; - private GSSContext gssContext = null; - - /** - * base64 decoded challenge * - */ - private byte[] token; - - private Oid negotiationOid = null; - public SpnegoEngine(final SpnegoTokenGenerator spnegoGenerator) { this.spnegoGenerator = spnegoGenerator; } @@ -97,6 +88,10 @@ public String generateToken(String server) throws Throwable { * Unfortunately SPNEGO is JRE >=1.6. */ + GSSContext gssContext = null; + byte[] token = null; // base64 decoded challenge + Oid negotiationOid = null; + /** Try SPNEGO by default, fall back to Kerberos later if error */ negotiationOid = new Oid(SPNEGO_OID); From 8aabac41ee8712dc704d99fe1287a898193b7354 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 7 Mar 2014 16:15:38 +0100 Subject: [PATCH 243/701] MS, can't you fix your DNS, honestly? --- .../java/com/ning/http/client/async/RemoteSiteTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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 52157c03de..8eb3615299 100644 --- a/src/test/java/com/ning/http/client/async/RemoteSiteTest.java +++ b/src/test/java/com/ning/http/client/async/RemoteSiteTest.java @@ -74,7 +74,7 @@ public void testMailGoogleCom() throws Throwable { } } - @Test(groups = { "online", "default_provider" }) + @Test(groups = { "online", "default_provider" }, enabled = false) public void testMicrosoftCom() throws Throwable { AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeoutInMs(10000).build()); try { @@ -86,7 +86,7 @@ public void testMicrosoftCom() throws Throwable { } } - @Test(groups = { "online", "default_provider" }) + @Test(groups = { "online", "default_provider" }, enabled = false) public void testWwwMicrosoftCom() throws Throwable { AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeoutInMs(10000).build()); try { @@ -98,7 +98,7 @@ public void testWwwMicrosoftCom() throws Throwable { } } - @Test(groups = { "online", "default_provider" }) + @Test(groups = { "online", "default_provider" }, enabled = false) public void testUpdateMicrosoftCom() throws Throwable { AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeoutInMs(10000).build()); try { From 90b67d9d566676a4b30fe145af6133e43a3fc3ad Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 19 Mar 2014 10:53:27 +0100 Subject: [PATCH 244/701] Backport RFC2616DateParser fix, close #505 --- src/main/java/com/ning/http/client/date/RFC2616DateParser.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/ning/http/client/date/RFC2616DateParser.java b/src/main/java/com/ning/http/client/date/RFC2616DateParser.java index e04638fb8e..6807737620 100644 --- a/src/main/java/com/ning/http/client/date/RFC2616DateParser.java +++ b/src/main/java/com/ning/http/client/date/RFC2616DateParser.java @@ -83,7 +83,7 @@ private Tokens tokenize() { } // finish lastToken - if (inToken = true) + if (inToken) ends[tokenCount++] = end; return new Tokens(starts, ends, tokenCount); From 9725d77e1d162437d2612e1fdc5f13e9b550ede6 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 19 Mar 2014 10:55:37 +0100 Subject: [PATCH 245/701] Backport OAuthSignatureCalculator fix, close #506 --- .../ning/http/client/oauth/OAuthSignatureCalculator.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) 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 4e363745e0..bc36b19892 100644 --- a/src/main/java/com/ning/http/client/oauth/OAuthSignatureCalculator.java +++ b/src/main/java/com/ning/http/client/oauth/OAuthSignatureCalculator.java @@ -127,7 +127,9 @@ public String calculateSignature(String method, String baseURL, long oauthTimest allParameters.add(KEY_OAUTH_NONCE, nonce); allParameters.add(KEY_OAUTH_SIGNATURE_METHOD, OAUTH_SIGNATURE_METHOD); allParameters.add(KEY_OAUTH_TIMESTAMP, String.valueOf(oauthTimestamp)); - allParameters.add(KEY_OAUTH_TOKEN, userAuth.getKey()); + if (userAuth.getKey() != null) { + allParameters.add(KEY_OAUTH_TOKEN, userAuth.getKey()); + } allParameters.add(KEY_OAUTH_VERSION, OAUTH_VERSION_1_0); if (formParams != null) { @@ -165,7 +167,9 @@ public String constructAuthHeader(String signature, String nonce, long oauthTime StringBuilder sb = new StringBuilder(200); sb.append("OAuth "); sb.append(KEY_OAUTH_CONSUMER_KEY).append("=\"").append(consumerAuth.getKey()).append("\", "); - sb.append(KEY_OAUTH_TOKEN).append("=\"").append(userAuth.getKey()).append("\", "); + if (userAuth.getKey() != null) { + sb.append(KEY_OAUTH_TOKEN).append("=\"").append(userAuth.getKey()).append("\", "); + } sb.append(KEY_OAUTH_SIGNATURE_METHOD).append("=\"").append(OAUTH_SIGNATURE_METHOD).append("\", "); // careful: base64 has chars that need URL encoding: From d850e4eacd5ef43fb5f4aca027ca3dcb431a8fb5 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 19 Mar 2014 10:58:00 +0100 Subject: [PATCH 246/701] Backport ProxyUtils clean up, close #507 --- src/main/java/com/ning/http/util/ProxyUtils.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/ning/http/util/ProxyUtils.java b/src/main/java/com/ning/http/util/ProxyUtils.java index b4caab5149..a9c8f7b0cd 100644 --- a/src/main/java/com/ning/http/util/ProxyUtils.java +++ b/src/main/java/com/ning/http/util/ProxyUtils.java @@ -205,6 +205,7 @@ public ProxyServer select(URI uri) { case HTTP: if (!(proxy.address() instanceof InetSocketAddress)) { log.warn("Don't know how to connect to address " + proxy.address()); + return null; } else { InetSocketAddress address = (InetSocketAddress) proxy.address(); return new ProxyServer(Protocol.HTTP, address.getHostName(), address.getPort()); From 6b90b0a2360c52960296aba1fbf37269e63a32aa Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 19 Mar 2014 11:58:58 +0100 Subject: [PATCH 247/701] Pool key is not properly computed when proxy is defined, close #508 --- .../providers/netty/NettyAsyncHttpProvider.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 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 384c1a16a3..a2e6c60c82 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 @@ -417,8 +417,8 @@ public ChannelPipeline getPipeline() throws Exception { } } - private Channel lookupInCache(URI uri, ConnectionPoolKeyStrategy connectionPoolKeyStrategy) { - final Channel channel = connectionsPool.poll(connectionPoolKeyStrategy.getKey(uri)); + private Channel lookupInCache(URI uri, ProxyServer proxy, ConnectionPoolKeyStrategy strategy) { + final Channel channel = connectionsPool.poll(getPoolKey(uri, proxy, strategy)); if (channel != null) { log.debug("Using cached Channel {}\n for uri {}\n", channel, uri); @@ -942,8 +942,7 @@ private NettyResponseFuture buildNettyResponseFutureWithCachedChannel(Req if (f != null && f.reuseChannel() && f.channel() != null) { channel = f.channel(); } else { - URI connectionKeyUri = proxyServer != null ? proxyServer.getURI() : uri; - channel = lookupInCache(connectionKeyUri, request.getConnectionPoolKeyStrategy()); + channel = lookupInCache(uri, proxyServer, request.getConnectionPoolKeyStrategy()); } if (channel == null) @@ -1318,10 +1317,11 @@ private Realm ntlmProxyChallenge(List wwwAuth, Request request, ProxySer } private String getPoolKey(NettyResponseFuture future) { - - String serverPart = future.getConnectionPoolKeyStrategy().getKey(future.getURI()); - - ProxyServer proxy = future.getProxyServer(); + return getPoolKey(future.getURI(), future.getProxyServer(), future.getConnectionPoolKeyStrategy()); + } + + private String getPoolKey(URI uri, ProxyServer proxy, ConnectionPoolKeyStrategy strategy) { + String serverPart = strategy.getKey(uri); return proxy != null ? AsyncHttpProviderUtils.getBaseUrl(proxy.getURI()) + serverPart : serverPart; } From 5287a196f2fe0c06fe4c76a41fa050161735fbff Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 20 Mar 2014 14:43:14 +0100 Subject: [PATCH 248/701] [maven-release-plugin] prepare release async-http-client-1.8.4 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index ad80a4a2f0..6c2b0d5bb0 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.8.4-SNAPSHOT + 1.8.4 jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From 20e6a182073ce842cc154d3912bd49d1607dd881 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 20 Mar 2014 14:43:19 +0100 Subject: [PATCH 249/701] [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 6c2b0d5bb0..581b864813 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.8.4 + 1.8.5-SNAPSHOT jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From 6901b9f64ec9326cec9688654644d9f11094f1cc Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 21 Mar 2014 18:46:38 +0100 Subject: [PATCH 250/701] When talking to a SSL proxy, AHC should use relative URIs by default, close #509 --- .../java/com/ning/http/client/AsyncHttpClientConfig.java | 4 +++- src/main/java/com/ning/http/util/MiscUtil.java | 7 ++++++- 2 files changed, 9 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 974f19694a..700309d35f 100644 --- a/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java @@ -15,6 +15,8 @@ */ package com.ning.http.client; +import static com.ning.http.util.MiscUtil.getBoolean; + import com.ning.http.client.date.TimeConverter; import com.ning.http.client.filter.IOExceptionFilter; import com.ning.http.client.filter.RequestFilter; @@ -539,7 +541,7 @@ public static class Builder { 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 boolean useRelativeURIsWithSSLProxies = getBoolean(ASYNC_CLIENT + "useRelativeURIsWithSSLProxies", true); private ExecutorService applicationThreadPool; private ProxyServerSelector proxyServerSelector = null; private SSLContext sslContext; diff --git a/src/main/java/com/ning/http/util/MiscUtil.java b/src/main/java/com/ning/http/util/MiscUtil.java index 26e1859685..e30082eb6c 100644 --- a/src/main/java/com/ning/http/util/MiscUtil.java +++ b/src/main/java/com/ning/http/util/MiscUtil.java @@ -23,7 +23,7 @@ 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; } @@ -39,4 +39,9 @@ public static boolean isNonEmpty(Collection collection) { public static boolean isNonEmpty(Map map) { return map != null && !map.isEmpty(); } + + public static boolean getBoolean(String systemPropName, boolean defaultValue) { + String systemPropValue = System.getProperty(systemPropName); + return systemPropValue != null ? systemPropValue.equalsIgnoreCase("true") : defaultValue; + } } From 9ad209b91938082aaeebb7fc0376db2f6b5bd780 Mon Sep 17 00:00:00 2001 From: Aki Yoshida Date: Wed, 26 Mar 2014 17:36:39 +0100 Subject: [PATCH 251/701] 511: 1.8.x GrizzlyAsyncHttpProvider not honoring usePreemtiveAuth --- .../grizzly/GrizzlyAsyncHttpProvider.java | 33 +++++++++++++++++ .../ning/http/client/async/BasicAuthTest.java | 35 +++++++++++++++++-- 2 files changed, 65 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 b4030b2a71..9371ae0458 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 @@ -134,6 +134,7 @@ import com.ning.http.client.filter.FilterContext; import com.ning.http.client.filter.ResponseFilter; import com.ning.http.client.listener.TransferCompletionHandler; +import com.ning.http.client.ntlm.NTLMEngine; import com.ning.http.client.websocket.WebSocket; import com.ning.http.client.websocket.WebSocketByteListener; import com.ning.http.client.websocket.WebSocketCloseCodeReasonListener; @@ -164,6 +165,7 @@ public class GrizzlyAsyncHttpProvider implements AsyncHttpProvider { } private static final Attribute REQUEST_STATE_ATTR = Grizzly.DEFAULT_ATTRIBUTE_BUILDER.createAttribute(HttpTransactionContext.class.getName()); + private final static NTLMEngine ntlmEngine = new NTLMEngine(); private final BodyHandlerFactory bodyHandlerFactory = new BodyHandlerFactory(); @@ -905,6 +907,7 @@ private boolean sendAsGrizzlyRequest(final Request request, } addHeaders(request, requestPacket); addCookies(request, requestPacket); + addAuthorizationHeader(request, requestPacket); if (useProxy) { if (!requestPacket.getHeaders().contains(Header.ProxyConnection)) { @@ -926,6 +929,36 @@ private boolean sendAsGrizzlyRequest(final Request request, } + private void addAuthorizationHeader(final Request request, final HttpRequestPacket requestPacket) { + Realm realm = request.getRealm(); + if (realm == null) { + realm = config.getRealm(); + } + if (realm != null && realm.getUsePreemptiveAuth()) { + final String authHeaderValue = generateAuthHeader(realm); + if (authHeaderValue != null) { + requestPacket.addHeader(Header.Authorization, authHeaderValue); + } + } + } + + private String generateAuthHeader(final Realm realm) { + try { + switch (realm.getAuthScheme()) { + case BASIC: + return AuthenticatorUtils.computeBasicAuthentication(realm); + case DIGEST: + return AuthenticatorUtils.computeDigestAuthentication(realm); + case NTLM: + return ntlmEngine.generateType1Msg("NTLM " + realm.getNtlmDomain(), realm.getNtlmHost()); + default: + return null; + } + } catch (Exception e) { + throw new RuntimeException(e); + } + } + private boolean isUpgradeRequest(final AsyncHandler handler) { return (handler instanceof UpgradeHandler); 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 01c7632923..b9ea90cb09 100644 --- a/src/test/java/com/ning/http/client/async/BasicAuthTest.java +++ b/src/test/java/com/ning/http/client/async/BasicAuthTest.java @@ -22,6 +22,7 @@ import com.ning.http.client.HttpResponseHeaders; import com.ning.http.client.HttpResponseStatus; import com.ning.http.client.Realm; +import com.ning.http.client.Realm.AuthScheme; import com.ning.http.client.Response; import com.ning.http.client.generators.InputStreamBodyGenerator; @@ -72,6 +73,8 @@ public abstract class BasicAuthTest extends AbstractBasicTest { protected final static String admin = "admin"; private Server server2; + private Server serverNoAuth; + private int portNoAuth; @BeforeClass(alwaysRun = true) @Override @@ -201,6 +204,24 @@ private void stopSecondServer() throws Exception { server2.stop(); } + private void setUpServerNoAuth() throws Exception { + serverNoAuth = new Server(); + portNoAuth = findFreePort(); + + Connector listener = new SelectChannelConnector(); + listener.setHost("127.0.0.1"); + listener.setPort(portNoAuth); + + serverNoAuth.addConnector(listener); + + serverNoAuth.setHandler(new SimpleHandler()); + serverNoAuth.start(); + } + + private void stopServerNoAuth() throws Exception { + serverNoAuth.stop(); + } + private class RedirectHandler extends AbstractHandler { public void handle(String s, Request r, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { @@ -231,7 +252,7 @@ public void handle(String s, Request r, HttpServletRequest request, HttpServletR private class SimpleHandler extends AbstractHandler { public void handle(String s, Request r, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { - + if (request.getHeader("X-401") != null) { response.setStatus(401); response.getOutputStream().flush(); @@ -307,6 +328,10 @@ protected String getTargetUrl2() { return "http://127.0.0.1:" + port2 + "/uff"; } + protected String getTargetUrlNoAuth() { + return "http://127.0.0.1:" + portNoAuth + "/"; + } + @Test(groups = { "standalone", "default_provider" }) public void basic401Test() throws IOException, ExecutionException, TimeoutException, InterruptedException { AsyncHttpClient client = getAsyncHttpClient(null); @@ -351,10 +376,13 @@ public Integer onCompleted() throws Exception { } @Test(groups = { "standalone", "default_provider" }) - public void basicAuthTestPreemtiveTest() throws IOException, ExecutionException, TimeoutException, InterruptedException { + public void basicAuthTestPreemtiveTest() throws Exception, ExecutionException, TimeoutException, InterruptedException { AsyncHttpClient client = getAsyncHttpClient(null); try { - AsyncHttpClient.BoundRequestBuilder r = client.prepareGet(getTargetUrl()).setRealm((new Realm.RealmBuilder()).setPrincipal(user).setPassword(admin).setUsePreemptiveAuth(true).build()); + setUpServerNoAuth(); + + AsyncHttpClient.BoundRequestBuilder r = client.prepareGet(getTargetUrlNoAuth()) + .setRealm((new Realm.RealmBuilder()).setScheme(AuthScheme.BASIC).setPrincipal(user).setPassword(admin).setUsePreemptiveAuth(true).build()); Future f = r.execute(); Response resp = f.get(3, TimeUnit.SECONDS); @@ -363,6 +391,7 @@ public void basicAuthTestPreemtiveTest() throws IOException, ExecutionException, assertEquals(resp.getStatusCode(), HttpServletResponse.SC_OK); } finally { client.close(); + stopServerNoAuth(); } } From 8a02a6a198fe6cf259ccaf963e2e4a53f8c17fcf Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 26 Mar 2014 18:21:14 +0100 Subject: [PATCH 252/701] Expose RequestBuilder reset methods, close #515 --- .../com/ning/http/client/RequestBuilderBase.java | 14 +++++++++++--- 1 file changed, 11 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 4fc7ebc4ab..3722bbb81e 100644 --- a/src/main/java/com/ning/http/client/RequestBuilderBase.java +++ b/src/main/java/com/ning/http/client/RequestBuilderBase.java @@ -458,11 +458,19 @@ public T addCookie(Cookie cookie) { return derived.cast(this); } - private void resetParameters() { + public void resetQueryParameters() { + request.queryParams = null; + } + + public void resetCookies() { + request.cookies.clear();; + } + + public void resetParameters() { request.params = null; } - private void resetNonMultipartData() { + public void resetNonMultipartData() { request.byteData = null; request.stringData = null; request.streamData = null; @@ -470,7 +478,7 @@ private void resetNonMultipartData() { request.length = -1; } - private void resetMultipartData() { + public void resetMultipartData() { request.parts = null; } From 1498a6bd0072da2827d7a22e30c7196f9f676199 Mon Sep 17 00:00:00 2001 From: Kelvin Law Date: Wed, 2 Apr 2014 17:15:27 -0700 Subject: [PATCH 253/701] Fix RequestBuilderBase when using percent-encoded user info --- src/main/java/com/ning/http/client/RequestBuilderBase.java | 2 +- .../com/ning/http/client/async/RequestBuilderTest.java | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/ning/http/client/RequestBuilderBase.java b/src/main/java/com/ning/http/client/RequestBuilderBase.java index 3722bbb81e..61c4c5052d 100644 --- a/src/main/java/com/ning/http/client/RequestBuilderBase.java +++ b/src/main/java/com/ning/http/client/RequestBuilderBase.java @@ -175,7 +175,7 @@ private URI toURI(boolean encode) { AsyncHttpProviderUtils.validateSupportedScheme(originalUri); StringBuilder builder = new StringBuilder(); - builder.append(originalUri.getScheme()).append("://").append(originalUri.getAuthority()); + builder.append(originalUri.getScheme()).append("://").append(originalUri.getRawAuthority()); if (isNonEmpty(originalUri.getRawPath())) { builder.append(originalUri.getRawPath()); } else { diff --git a/src/test/java/com/ning/http/client/async/RequestBuilderTest.java b/src/test/java/com/ning/http/client/async/RequestBuilderTest.java index 52714d3ed9..02f7e57a4b 100644 --- a/src/test/java/com/ning/http/client/async/RequestBuilderTest.java +++ b/src/test/java/com/ning/http/client/async/RequestBuilderTest.java @@ -105,4 +105,11 @@ public void testUserProvidedRequestMethod() { assertEquals(req.getMethod(), "ABC"); assertEquals(req.getUrl(), "http://foo.com"); } + + @Test(groups = {"standalone", "default_provider"}) + public void testPercentageEncodedUserInfo() { + final Request req = new RequestBuilder("GET").setUrl("http://hello:wor%20ld@foo.com").build(); + assertEquals(req.getMethod(), "GET"); + assertEquals(req.getUrl(), "http://hello:wor%20ld@foo.com"); + } } From 0f49b39f3705a5e7cab2d449ed4ef6134f6c065a Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 3 Apr 2014 11:01:51 +0200 Subject: [PATCH 254/701] Fix license headers --- .../java/com/ning/http/client/date/CalendarTimeConverter.java | 2 +- src/main/java/com/ning/http/client/date/RFC2616Date.java | 2 +- src/main/java/com/ning/http/client/date/TimeConverter.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/ning/http/client/date/CalendarTimeConverter.java b/src/main/java/com/ning/http/client/date/CalendarTimeConverter.java index 270c6d9ecd..9e8b1b464b 100644 --- a/src/main/java/com/ning/http/client/date/CalendarTimeConverter.java +++ b/src/main/java/com/ning/http/client/date/CalendarTimeConverter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2014 Sonatype, Inc. All rights reserved. + * Copyright (c) 2014 AsyncHttpClient Project. 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. diff --git a/src/main/java/com/ning/http/client/date/RFC2616Date.java b/src/main/java/com/ning/http/client/date/RFC2616Date.java index 7a977c1b78..05f3dc05b5 100644 --- a/src/main/java/com/ning/http/client/date/RFC2616Date.java +++ b/src/main/java/com/ning/http/client/date/RFC2616Date.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2014 Sonatype, Inc. All rights reserved. + * Copyright (c) 2014 AsyncHttpClient Project. 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. diff --git a/src/main/java/com/ning/http/client/date/TimeConverter.java b/src/main/java/com/ning/http/client/date/TimeConverter.java index d42f48599a..26163df1fd 100644 --- a/src/main/java/com/ning/http/client/date/TimeConverter.java +++ b/src/main/java/com/ning/http/client/date/TimeConverter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2014 Sonatype, Inc. All rights reserved. + * Copyright (c) 2014 AsyncHttpClient Project. 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. From 8e10943045fb6067764beb161870e5a4ca5e1698 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 3 Apr 2014 11:48:51 +0200 Subject: [PATCH 255/701] Make disposition-type configurable, close #522 --- .../java/com/ning/http/multipart/Part.java | 80 ++++++++++++++----- 1 file changed, 62 insertions(+), 18 deletions(-) diff --git a/src/main/java/com/ning/http/multipart/Part.java b/src/main/java/com/ning/http/multipart/Part.java index e8f8268b17..6d822c5427 100644 --- a/src/main/java/com/ning/http/multipart/Part.java +++ b/src/main/java/com/ning/http/multipart/Part.java @@ -33,82 +33,102 @@ public abstract class Part implements com.ning.http.client.Part { /** * Carriage return/linefeed */ - protected static final String CRLF = "\r\n"; + public static final String CRLF = "\r\n"; /** * Carriage return/linefeed as a byte array */ - static final byte[] CRLF_BYTES = MultipartEncodingUtil.getAsciiBytes(CRLF); + public static final byte[] CRLF_BYTES = MultipartEncodingUtil.getAsciiBytes(CRLF); /** * Content dispostion characters */ - protected static final String QUOTE = "\""; + public static final String QUOTE = "\""; /** * Content dispostion as a byte array */ - static final byte[] QUOTE_BYTES = MultipartEncodingUtil.getAsciiBytes(QUOTE); + public static final byte[] QUOTE_BYTES = MultipartEncodingUtil.getAsciiBytes(QUOTE); /** * Extra characters */ - protected static final String EXTRA = "--"; + public static final String EXTRA = "--"; /** * Extra characters as a byte array */ - static final byte[] EXTRA_BYTES = MultipartEncodingUtil.getAsciiBytes(EXTRA); + public static final byte[] EXTRA_BYTES = MultipartEncodingUtil.getAsciiBytes(EXTRA); /** - * Content dispostion characters + * Content disposition characters */ - protected static final String CONTENT_DISPOSITION = "Content-Disposition: form-data; name="; + public static final String CONTENT_DISPOSITION = "Content-Disposition: "; /** - * Content dispostion as a byte array + * Content disposition as a byte array + */ + public static final byte[] CONTENT_DISPOSITION_BYTES = MultipartEncodingUtil.getAsciiBytes(CONTENT_DISPOSITION); + + /** + * form-data characters + */ + public static final String FORM_DATA_DISPOSITION_TYPE = "form-data"; + + /** + * form-data as a byte array + */ + public static final byte[] FORM_DATA_DISPOSITION_TYPE_BYTES = MultipartEncodingUtil.getAsciiBytes(FORM_DATA_DISPOSITION_TYPE); + + /** + * name characters */ - static final byte[] CONTENT_DISPOSITION_BYTES = MultipartEncodingUtil.getAsciiBytes(CONTENT_DISPOSITION); + public static final String NAME = "; name="; + + /** + * name as a byte array + */ + public static final byte[] NAME_BYTES = MultipartEncodingUtil.getAsciiBytes(NAME); /** * Content type header */ - protected static final String CONTENT_TYPE = "Content-Type: "; + public static final String CONTENT_TYPE = "Content-Type: "; /** * Content type header as a byte array */ - static final byte[] CONTENT_TYPE_BYTES = MultipartEncodingUtil.getAsciiBytes(CONTENT_TYPE); + public static final byte[] CONTENT_TYPE_BYTES = MultipartEncodingUtil.getAsciiBytes(CONTENT_TYPE); /** * Content charset */ - protected static final String CHARSET = "; charset="; + public static final String CHARSET = "; charset="; /** * Content charset as a byte array */ - static final byte[] CHARSET_BYTES = MultipartEncodingUtil.getAsciiBytes(CHARSET); + public static final byte[] CHARSET_BYTES = MultipartEncodingUtil.getAsciiBytes(CHARSET); /** * Content type header */ - protected static final String CONTENT_TRANSFER_ENCODING = "Content-Transfer-Encoding: "; + public static final String CONTENT_TRANSFER_ENCODING = "Content-Transfer-Encoding: "; /** * Content type header as a byte array */ - static final byte[] CONTENT_TRANSFER_ENCODING_BYTES = MultipartEncodingUtil.getAsciiBytes(CONTENT_TRANSFER_ENCODING); + public static final byte[] CONTENT_TRANSFER_ENCODING_BYTES = MultipartEncodingUtil.getAsciiBytes(CONTENT_TRANSFER_ENCODING); /** * Content type header */ - protected static final String CONTENT_ID = "Content-ID: "; + public static final String CONTENT_ID = "Content-ID: "; /** * Content type header as a byte array */ - static final byte[] CONTENT_ID_BYTES = MultipartEncodingUtil.getAsciiBytes(CONTENT_ID); + public static final byte[] CONTENT_ID_BYTES = MultipartEncodingUtil.getAsciiBytes(CONTENT_ID); /** * Return the name of this part. @@ -155,6 +175,20 @@ public boolean isRepeatable() { return true; } + private String dispositionType; + /** + * Gets the disposition-type to be used in Content-Disposition header + * + * @return the disposition-type + */ + public String getDispositionType() { + return dispositionType; + } + + public void setDispositionType(String dispositionType) { + this.dispositionType = dispositionType; + } + /** * Write the start to the specified output stream * @@ -181,6 +215,11 @@ protected void sendDispositionHeader(OutputStream out) throws IOException { if (getName() != null) { out.write(CRLF_BYTES); out.write(CONTENT_DISPOSITION_BYTES); + if (dispositionType != null) + out.write(MultipartEncodingUtil.getAsciiBytes(dispositionType)); + else + out.write(FORM_DATA_DISPOSITION_TYPE_BYTES); + out.write(NAME_BYTES); out.write(QUOTE_BYTES); out.write(MultipartEncodingUtil.getAsciiBytes(getName())); out.write(QUOTE_BYTES); @@ -192,6 +231,11 @@ protected long dispositionHeaderLength() { if (getName() != null) { length += CRLF_BYTES.length; length += CONTENT_DISPOSITION_BYTES.length; + if (dispositionType != null) + length += MultipartEncodingUtil.getAsciiBytes(dispositionType).length; + else + length += FORM_DATA_DISPOSITION_TYPE_BYTES.length; + length += NAME_BYTES.length; length += QUOTE_BYTES.length; length += MultipartEncodingUtil.getAsciiBytes(getName()).length; length += QUOTE_BYTES.length; From 8536ad58ef3a92d478e3eb78cd6a2a6b3a66088e Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 3 Apr 2014 14:48:56 +0200 Subject: [PATCH 256/701] Multipart name should be optional, close #523 --- .../multipart/MultipartRequestEntity.java | 12 ---- .../java/com/ning/http/multipart/Part.java | 59 ++++++++++--------- .../com/ning/http/multipart/PartBase.java | 6 +- .../ning/http/multipart/RequestEntity.java | 8 --- 4 files changed, 31 insertions(+), 54 deletions(-) diff --git a/src/main/java/com/ning/http/multipart/MultipartRequestEntity.java b/src/main/java/com/ning/http/multipart/MultipartRequestEntity.java index b486f7da82..87531211ee 100644 --- a/src/main/java/com/ning/http/multipart/MultipartRequestEntity.java +++ b/src/main/java/com/ning/http/multipart/MultipartRequestEntity.java @@ -110,18 +110,6 @@ protected byte[] getMultipartBoundary() { return multipartBoundary; } - /** - * Returns true if all parts are repeatable, false otherwise. - */ - public boolean isRepeatable() { - for (Part part : parts) { - if (!part.isRepeatable()) { - return false; - } - } - return true; - } - public void writeRequest(OutputStream out) throws IOException { Part.sendParts(out, parts, multipartBoundary); } diff --git a/src/main/java/com/ning/http/multipart/Part.java b/src/main/java/com/ning/http/multipart/Part.java index 6d822c5427..c66da43428 100644 --- a/src/main/java/com/ning/http/multipart/Part.java +++ b/src/main/java/com/ning/http/multipart/Part.java @@ -69,7 +69,7 @@ public abstract class Part implements com.ning.http.client.Part { * Content disposition as a byte array */ public static final byte[] CONTENT_DISPOSITION_BYTES = MultipartEncodingUtil.getAsciiBytes(CONTENT_DISPOSITION); - + /** * form-data characters */ @@ -79,7 +79,7 @@ public abstract class Part implements com.ning.http.client.Part { * form-data as a byte array */ public static final byte[] FORM_DATA_DISPOSITION_TYPE_BYTES = MultipartEncodingUtil.getAsciiBytes(FORM_DATA_DISPOSITION_TYPE); - + /** * name characters */ @@ -165,17 +165,8 @@ public abstract class Part implements com.ning.http.client.Part { */ public abstract String getContentId(); - /** - * 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. - * @since 3.0 - */ - public boolean isRepeatable() { - return true; - } - private String dispositionType; + /** * Gets the disposition-type to be used in Content-Disposition header * @@ -212,13 +203,14 @@ private int startLength(byte[] boundary) { * @throws IOException If an IO problem occurs. */ protected void sendDispositionHeader(OutputStream out) throws IOException { + out.write(CRLF_BYTES); + out.write(CONTENT_DISPOSITION_BYTES); + if (dispositionType != null) + out.write(MultipartEncodingUtil.getAsciiBytes(dispositionType)); + else + out.write(FORM_DATA_DISPOSITION_TYPE_BYTES); + if (getName() != null) { - out.write(CRLF_BYTES); - out.write(CONTENT_DISPOSITION_BYTES); - if (dispositionType != null) - out.write(MultipartEncodingUtil.getAsciiBytes(dispositionType)); - else - out.write(FORM_DATA_DISPOSITION_TYPE_BYTES); out.write(NAME_BYTES); out.write(QUOTE_BYTES); out.write(MultipartEncodingUtil.getAsciiBytes(getName())); @@ -228,13 +220,15 @@ protected void sendDispositionHeader(OutputStream out) throws IOException { protected long dispositionHeaderLength() { long length = 0L; + + length += CRLF_BYTES.length; + length += CONTENT_DISPOSITION_BYTES.length; + if (dispositionType != null) + length += MultipartEncodingUtil.getAsciiBytes(dispositionType).length; + else + length += FORM_DATA_DISPOSITION_TYPE_BYTES.length; + if (getName() != null) { - length += CRLF_BYTES.length; - length += CONTENT_DISPOSITION_BYTES.length; - if (dispositionType != null) - length += MultipartEncodingUtil.getAsciiBytes(dispositionType).length; - else - length += FORM_DATA_DISPOSITION_TYPE_BYTES.length; length += NAME_BYTES.length; length += QUOTE_BYTES.length; length += MultipartEncodingUtil.getAsciiBytes(getName()).length; @@ -345,7 +339,7 @@ protected void sendEndOfHeader(OutputStream out) throws IOException { protected long endOfHeaderLength() { return CRLF_BYTES.length * 2; } - + /** * Write the data to the specified output stream * @@ -400,9 +394,9 @@ public void send(OutputStream out, byte[] boundary) throws IOException { * @throws IOException If an IO problem occurs */ public long length(byte[] boundary) { - + long lengthOfData = lengthOfData(); - + if (lengthOfData < 0L) { return -1L; } else { @@ -424,7 +418,14 @@ public long length(byte[] boundary) { * @see java.lang.Object#toString() */ public String toString() { - return this.getName(); + return new StringBuilder()// + .append("name=").append(getName())// + .append(" contentType=").append(getContentType())// + .append(" charset=").append(getCharSet())// + .append(" tranferEncoding=").append(getTransferEncoding())// + .append(" contentId=").append(getContentId())// + .append(" dispositionType=").append(getDispositionType())// + .toString(); } /** @@ -492,7 +493,7 @@ public static void sendPart(OutputStream out, Part part, byte[] partBoundary) th * @since 3.0 */ public static long getLengthOfParts(Part[] parts, byte[] partBoundary) { - + try { if (parts == null) { throw new IllegalArgumentException("Parts may not be null"); diff --git a/src/main/java/com/ning/http/multipart/PartBase.java b/src/main/java/com/ning/http/multipart/PartBase.java index b37bbad292..32a3a256eb 100644 --- a/src/main/java/com/ning/http/multipart/PartBase.java +++ b/src/main/java/com/ning/http/multipart/PartBase.java @@ -47,16 +47,12 @@ public abstract class PartBase extends Part { /** * Constructor. * - * @param name The name of the part + * @param name The name of the part, or null * @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, String contentId) { - - if (name == null) { - throw new IllegalArgumentException("Name must not be null"); - } this.name = name; this.contentType = contentType; this.charSet = charSet; diff --git a/src/main/java/com/ning/http/multipart/RequestEntity.java b/src/main/java/com/ning/http/multipart/RequestEntity.java index d0f6bbe069..823c8aaf43 100644 --- a/src/main/java/com/ning/http/multipart/RequestEntity.java +++ b/src/main/java/com/ning/http/multipart/RequestEntity.java @@ -25,14 +25,6 @@ */ public interface RequestEntity { - /** - * Tests if {@link #writeRequest(java.io.OutputStream)} can be called more than once. - * - * @return true if the entity can be written to {@link java.io.OutputStream} more than once, - * false otherwise. - */ - boolean isRepeatable(); - /** * Writes the request entity to the given stream. * From dee9671a65c005a9c8dec760f41e22ca8f057f45 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 3 Apr 2014 15:09:17 +0200 Subject: [PATCH 257/701] Make multipart FilePart charset optional, close #524 --- src/main/java/com/ning/http/multipart/FilePart.java | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/main/java/com/ning/http/multipart/FilePart.java b/src/main/java/com/ning/http/multipart/FilePart.java index 0f3c84ff22..c8e125c758 100644 --- a/src/main/java/com/ning/http/multipart/FilePart.java +++ b/src/main/java/com/ning/http/multipart/FilePart.java @@ -33,11 +33,6 @@ public class FilePart extends PartBase { */ public static final String DEFAULT_CONTENT_TYPE = "application/octet-stream"; - /** - * Default charset of file attachments. - */ - public static final String DEFAULT_CHARSET = "ISO-8859-1"; - /** * Default transfer encoding of file attachments. */ @@ -68,7 +63,7 @@ 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); + super(name, contentType == null ? DEFAULT_CONTENT_TYPE : contentType, charset, DEFAULT_TRANSFER_ENCODING, contentId); if (partSource == null) { throw new IllegalArgumentException("Source may not be null"); } From dc1cc3e50d509285bcc64fef71a092ebcf823f69 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 3 Apr 2014 16:42:04 +0200 Subject: [PATCH 258/701] Disable shaded artifact until Sonatype gets fixed and we can successfully deploy big files --- pom.xml | 64 ++++++++++++++++++++++++++++----------------------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/pom.xml b/pom.xml index 581b864813..1c08423445 100644 --- a/pom.xml +++ b/pom.xml @@ -394,38 +394,38 @@ - - org.apache.maven.plugins - maven-shade-plugin - 1.2.1 - - - package - - shade - - - true - shaded - - - commons-codec:commons-codec - commons-lang:commons-lang - commons-logging:commons-logging - junit:junit - log4j:log4j - commons-httpclient:commons-httpclient - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 8cefd82eed71741612c44376d265bdf3c9c33057 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 3 Apr 2014 18:45:45 +0200 Subject: [PATCH 259/701] [maven-release-plugin] prepare release async-http-client-1.8.5 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 1c08423445..2cb620dc2b 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.8.5-SNAPSHOT + 1.8.5 jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From 134d74ce717febe0638c918645c8d7c7be8729eb Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 3 Apr 2014 18:45:56 +0200 Subject: [PATCH 260/701] [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 2cb620dc2b..b7a42d5730 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.8.5 + 1.8.6-SNAPSHOT jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From 8ceac66258d3ee2143c57ea57377b561bd70a57a Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 7 Apr 2014 18:33:05 +0200 Subject: [PATCH 261/701] Expose Parts hidden data, useful for debugging --- .../java/com/ning/http/multipart/ByteArrayPartSource.java | 3 +++ src/main/java/com/ning/http/multipart/FilePart.java | 4 ++-- src/main/java/com/ning/http/multipart/FilePartSource.java | 2 -- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/ning/http/multipart/ByteArrayPartSource.java b/src/main/java/com/ning/http/multipart/ByteArrayPartSource.java index 80ae3f59e3..a50f6ff490 100644 --- a/src/main/java/com/ning/http/multipart/ByteArrayPartSource.java +++ b/src/main/java/com/ning/http/multipart/ByteArrayPartSource.java @@ -68,4 +68,7 @@ public InputStream createInputStream() throws IOException { return new ByteArrayInputStream(bytes); } + public byte[] getBytes() { + return bytes; + } } diff --git a/src/main/java/com/ning/http/multipart/FilePart.java b/src/main/java/com/ning/http/multipart/FilePart.java index c8e125c758..d43aac9e4e 100644 --- a/src/main/java/com/ning/http/multipart/FilePart.java +++ b/src/main/java/com/ning/http/multipart/FilePart.java @@ -204,8 +204,8 @@ public long getStalledTime() { * * @return The source. */ - protected PartSource getSource() { - return this.source; + public PartSource getSource() { + return source; } /** diff --git a/src/main/java/com/ning/http/multipart/FilePartSource.java b/src/main/java/com/ning/http/multipart/FilePartSource.java index ddb772ba7c..70e2b22232 100644 --- a/src/main/java/com/ning/http/multipart/FilePartSource.java +++ b/src/main/java/com/ning/http/multipart/FilePartSource.java @@ -115,6 +115,4 @@ public InputStream createInputStream() throws IOException { public File getFile() { return file; } - - } From 790d8fa997e30ccbb3b6aac3737052a8497030cf Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 9 Apr 2014 11:05:55 +0200 Subject: [PATCH 262/701] Use Netty Timer interface instead of HashedWheelTimer, close #528 --- .../netty/NettyAsyncHttpProvider.java | 26 ++++++++++++------- .../netty/NettyAsyncHttpProviderConfig.java | 12 ++++----- .../providers/netty/NettyConnectionsPool.java | 12 ++++----- 3 files changed, 28 insertions(+), 22 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 a2e6c60c82..15e8eec7cc 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 @@ -104,6 +104,7 @@ import org.jboss.netty.handler.stream.ChunkedWriteHandler; import org.jboss.netty.util.HashedWheelTimer; import org.jboss.netty.util.Timeout; +import org.jboss.netty.util.Timer; import org.jboss.netty.util.TimerTask; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -214,8 +215,8 @@ public boolean remove(Object o) { private static SpnegoEngine spnegoEngine = null; private final Protocol httpProtocol = new HttpProtocol(); private final Protocol webSocketProtocol = new WebSocketProtocol(); - private final boolean allowStopHashedWheelTimer; - private final HashedWheelTimer hashedWheelTimer; + private final boolean allowStopNettyTimer; + private final Timer nettyTimer; private final long handshakeTimeoutInMillis; private static boolean isNTLM(List auth) { @@ -260,9 +261,8 @@ public NettyAsyncHttpProvider(AsyncHttpClientConfig config) { } } - allowStopHashedWheelTimer = providerConfig.getHashedWheelTimer() == null; - hashedWheelTimer = allowStopHashedWheelTimer ? new HashedWheelTimer() : providerConfig.getHashedWheelTimer(); - hashedWheelTimer.start(); + allowStopNettyTimer = providerConfig.getNettyTimer() == null; + nettyTimer = allowStopNettyTimer ? newNettyTimer() : providerConfig.getNettyTimer(); handshakeTimeoutInMillis = providerConfig.getHandshakeTimeoutInMillis(); @@ -277,7 +277,7 @@ public NettyAsyncHttpProvider(AsyncHttpClientConfig config) { // This is dangerous as we can't catch a wrong typed ConnectionsPool ConnectionsPool cp = (ConnectionsPool) config.getConnectionsPool(); if (cp == null && config.getAllowPoolingConnection()) { - cp = new NettyConnectionsPool(this, hashedWheelTimer); + cp = new NettyConnectionsPool(this, nettyTimer); } else if (cp == null) { cp = new NonConnectionsPool(); } @@ -294,6 +294,12 @@ public NettyAsyncHttpProvider(AsyncHttpClientConfig config) { disableZeroCopy = providerConfig.isDisableZeroCopy(); } + private Timer newNettyTimer() { + HashedWheelTimer timer = new HashedWheelTimer(); + timer.start(); + return timer; + } + @Override public String toString() { int availablePermits = freeConnections != null ? freeConnections.availablePermits() : 0; @@ -372,7 +378,7 @@ public ChannelPipeline getPipeline() throws Exception { try { SSLEngine sslEngine = createSSLEngine(); - SslHandler sslHandler = handshakeTimeoutInMillis > 0 ? new SslHandler(sslEngine, getDefaultBufferPool(), false, ImmediateExecutor.INSTANCE, hashedWheelTimer, + SslHandler sslHandler = handshakeTimeoutInMillis > 0 ? new SslHandler(sslEngine, getDefaultBufferPool(), false, ImmediateExecutor.INSTANCE, nettyTimer, handshakeTimeoutInMillis) : new SslHandler(sslEngine); pipeline.addLast(SSL_HANDLER, sslHandler); } catch (Throwable ex) { @@ -906,8 +912,8 @@ public void close() { secureWebSocketBootstrap.releaseExternalResources(); } - if (allowStopHashedWheelTimer) - hashedWheelTimer.stop(); + if (allowStopNettyTimer) + nettyTimer.stop(); } catch (Throwable t) { log.warn("Unexpected error on close", t); @@ -2448,7 +2454,7 @@ public boolean isClose() { } public Timeout newTimeoutInMs(TimerTask task, long delayInMs) { - return hashedWheelTimer.newTimeout(task, delayInMs, TimeUnit.MILLISECONDS); + return nettyTimer.newTimeout(task, delayInMs, TimeUnit.MILLISECONDS); } private static boolean isWebSocket(String scheme) { 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 d57090f170..3fbc497953 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 @@ -20,7 +20,7 @@ import java.util.Set; import java.util.concurrent.ConcurrentHashMap; -import org.jboss.netty.util.HashedWheelTimer; +import org.jboss.netty.util.Timer; import com.ning.http.client.AsyncHttpProviderConfig; @@ -85,7 +85,7 @@ public class NettyAsyncHttpProviderConfig implements AsyncHttpProviderConfig { private final ConcurrentHashMap channel2IdleChannel = new ConcurrentHashMap(); private final ConcurrentHashMap channel2CreationDate = new ConcurrentHashMap(); private final AtomicBoolean isClosed = new AtomicBoolean(false); - private final HashedWheelTimer hashedWheelTimer; + private final Timer nettyTimer; private final boolean sslConnectionPoolEnabled; private final int maxTotalConnections; private final int maxConnectionPerHost; private final int maxConnectionLifeTimeInMs; private final long maxIdleTime; - public NettyConnectionsPool(NettyAsyncHttpProvider provider, HashedWheelTimer hashedWheelTimer) { + public NettyConnectionsPool(NettyAsyncHttpProvider provider, Timer hashedWheelTimer) { this(provider.getConfig().getMaxTotalConnections(),// provider.getConfig().getMaxConnectionPerHost(),// provider.getConfig().getIdleConnectionInPoolTimeoutInMs(),// @@ -58,18 +58,18 @@ public NettyConnectionsPool(NettyAsyncHttpProvider provider, HashedWheelTimer ha } public NettyConnectionsPool(int maxTotalConnections, int maxConnectionPerHost, long maxIdleTime, int maxConnectionLifeTimeInMs, boolean sslConnectionPoolEnabled, - HashedWheelTimer hashedWheelTimer) { + Timer nettyTimer) { this.maxTotalConnections = maxTotalConnections; this.maxConnectionPerHost = maxConnectionPerHost; this.sslConnectionPoolEnabled = sslConnectionPoolEnabled; this.maxIdleTime = maxIdleTime; this.maxConnectionLifeTimeInMs = maxConnectionLifeTimeInMs; - this.hashedWheelTimer = hashedWheelTimer; + this.nettyTimer = nettyTimer; scheduleNewIdleChannelDetector(new IdleChannelDetector()); } private void scheduleNewIdleChannelDetector(TimerTask task) { - this.hashedWheelTimer.newTimeout(task, maxIdleTime, TimeUnit.MILLISECONDS); + this.nettyTimer.newTimeout(task, maxIdleTime, TimeUnit.MILLISECONDS); } private static class IdleChannel { From 67a9029ad9c12f7119b3d3e01276a6347e337e98 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 9 Apr 2014 15:27:48 +0200 Subject: [PATCH 263/701] [maven-release-plugin] prepare release async-http-client-1.8.6 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index b7a42d5730..8859b096bc 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.8.6-SNAPSHOT + 1.8.6 jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From 22e24a879a026673c9a8e9a478cdc8e35d93f076 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 9 Apr 2014 15:27:53 +0200 Subject: [PATCH 264/701] [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 8859b096bc..aa0a164a0b 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.8.6 + 1.8.7-SNAPSHOT jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From 97e62f38d470d488a2d1132ed7591b8055c23156 Mon Sep 17 00:00:00 2001 From: Raul Kripalani Date: Wed, 9 Apr 2014 17:38:27 +0100 Subject: [PATCH 265/701] #529 DIGEST Auth does not work if server doesn't indicate algorithm + fix in URI usage --- src/main/java/com/ning/http/client/Realm.java | 7 ++++--- .../client/providers/netty/NettyAsyncHttpProvider.java | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/ning/http/client/Realm.java b/src/main/java/com/ning/http/client/Realm.java index 95b2255357..111390ac67 100644 --- a/src/main/java/com/ning/http/client/Realm.java +++ b/src/main/java/com/ning/http/client/Realm.java @@ -22,8 +22,6 @@ import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; -import com.ning.http.util.MiscUtil; - /** * This class is required when authentication is needed. The class support DIGEST and BASIC. */ @@ -433,7 +431,10 @@ public RealmBuilder setUsePreemptiveAuth(boolean usePreemptiveAuth) { public RealmBuilder parseWWWAuthenticateHeader(String headerLine) { setRealmName(match(headerLine, "realm")); setNonce(match(headerLine, "nonce")); - setAlgorithm(match(headerLine, "algorithm")); + String algorithm = match(headerLine, "algorithm"); + if (isNonEmpty(algorithm)) { + setAlgorithm(algorithm); + } setOpaque(match(headerLine, "opaque")); setQop(match(headerLine, "qop")); if (isNonEmpty(getNonce())) { 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 15e8eec7cc..37a25c7440 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 @@ -2107,7 +2107,7 @@ public void handle(final ChannelHandlerContext ctx, final MessageEvent e) throws .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.getURI().getPath()).build(); log.debug("Sending authentication to {}", request.getUrl()); AsyncCallable ac = new AsyncCallable(future) { From 1643fa23e827ea550a1c59917f6d24be2710eac7 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Sat, 12 Apr 2014 22:52:09 +0200 Subject: [PATCH 266/701] MakeTimeoutsHolder threadsafe, close #534 --- .../client/providers/netty/timeout/TimeoutsHolder.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/timeout/TimeoutsHolder.java b/src/main/java/com/ning/http/client/providers/netty/timeout/TimeoutsHolder.java index b501ab321f..a41a4ba4a8 100644 --- a/src/main/java/com/ning/http/client/providers/netty/timeout/TimeoutsHolder.java +++ b/src/main/java/com/ning/http/client/providers/netty/timeout/TimeoutsHolder.java @@ -17,18 +17,19 @@ import org.jboss.netty.util.Timeout; +import java.util.concurrent.atomic.AtomicBoolean; + public class TimeoutsHolder { + private AtomicBoolean cancelled = new AtomicBoolean(); public volatile Timeout requestTimeout; public volatile Timeout idleConnectionTimeout; public void cancel() { - if (requestTimeout != null) { + if (cancelled.compareAndSet(false, true)) { requestTimeout.cancel(); - requestTimeout = null; - } - if (idleConnectionTimeout != null) { idleConnectionTimeout.cancel(); + requestTimeout = null; idleConnectionTimeout = null; } } From b8a4a91e8b97457ff115ce75dd8b6225495aa4f0 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Sat, 12 Apr 2014 22:56:57 +0200 Subject: [PATCH 267/701] [maven-release-plugin] prepare release async-http-client-1.8.7 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index aa0a164a0b..6d30389f7b 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.8.7-SNAPSHOT + 1.8.7 jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From 3ca1732b99c140171ff0cf67710da262a5352794 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Sat, 12 Apr 2014 22:57:02 +0200 Subject: [PATCH 268/701] [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 6d30389f7b..b6be39df45 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.8.7 + 1.8.8-SNAPSHOT jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From d168fc2588fe6d5b6099a19817ed3f12c668e0ea Mon Sep 17 00:00:00 2001 From: Kyrylo Stokoz Date: Tue, 15 Apr 2014 12:52:32 +0200 Subject: [PATCH 269/701] added remote channel address to read timeout exception --- .../http/client/providers/netty/NettyResponseFuture.java | 8 ++++++++ .../providers/netty/timeout/RequestTimeoutTimerTask.java | 3 ++- .../client/async/netty/NettyPerRequestTimeoutTest.java | 4 +++- 3 files changed, 13 insertions(+), 2 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 ff6413aafd..f34abb565d 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 static com.ning.http.util.DateUtil.millisTime; +import java.net.SocketAddress; import java.net.URI; import java.util.concurrent.CancellationException; import java.util.concurrent.CountDownLatch; @@ -479,6 +480,13 @@ protected boolean canRetry() { return true; } + public SocketAddress getChannelRemoteAddress() { + if (channel() != null && channel().getRemoteAddress() != null) { + return channel().getRemoteAddress(); + } + return null; + } + public void setRequest(Request request) { this.request = request; } diff --git a/src/main/java/com/ning/http/client/providers/netty/timeout/RequestTimeoutTimerTask.java b/src/main/java/com/ning/http/client/providers/netty/timeout/RequestTimeoutTimerTask.java index ac8003014c..7a8911a770 100644 --- a/src/main/java/com/ning/http/client/providers/netty/timeout/RequestTimeoutTimerTask.java +++ b/src/main/java/com/ning/http/client/providers/netty/timeout/RequestTimeoutTimerTask.java @@ -38,7 +38,8 @@ public void run(Timeout timeout) throws Exception { } if (!nettyResponseFuture.isDone() && !nettyResponseFuture.isCancelled()) { - expire("Request timeout of " + nettyResponseFuture.getRequestTimeoutInMs() + " ms", millisTime() - nettyResponseFuture.getStart()); + long age = millisTime() - nettyResponseFuture.getStart(); + expire("Request timed out to " + nettyResponseFuture.getChannelRemoteAddress() + " of " + nettyResponseFuture.getRequestTimeoutInMs() + " ms after " + age + " ms", age); nettyResponseFuture.setRequestTimeoutReached(); } } 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 097a4fcb1a..dc9f0d7e60 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 @@ -22,7 +22,9 @@ public class NettyPerRequestTimeoutTest extends PerRequestTimeoutTest { protected void checkTimeoutMessage(String message) { - assertTrue(message.equals("Request timeout of 100 ms")); + assertTrue(message.startsWith("Request timed out"), "error message indicates reason of error"); + assertTrue(message.contains("127.0.0.1"), "error message contains remote ip address"); + assertTrue(message.contains("of 100 ms"), "error message contains timeout configuration value"); } @Override From 93652c385e2462211ea2586ec41cffc2da0803ac Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 15 Apr 2014 15:01:29 +0200 Subject: [PATCH 270/701] Minor clean up, don't call channel().getRemoteAddress() twice --- .../http/client/providers/netty/NettyResponseFuture.java | 5 +---- 1 file changed, 1 insertion(+), 4 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 f34abb565d..0d2d6355e2 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 @@ -481,10 +481,7 @@ protected boolean canRetry() { } public SocketAddress getChannelRemoteAddress() { - if (channel() != null && channel().getRemoteAddress() != null) { - return channel().getRemoteAddress(); - } - return null; + return channel() != null? channel().getRemoteAddress(): null; } public void setRequest(Request request) { From 051792f0f4a3cf709c334761e133598075217caa Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 18 Apr 2014 10:31:04 +0200 Subject: [PATCH 271/701] idleConnectionTimeout might have been dropped or not set, close #534 --- .../providers/netty/timeout/TimeoutsHolder.java | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/timeout/TimeoutsHolder.java b/src/main/java/com/ning/http/client/providers/netty/timeout/TimeoutsHolder.java index a41a4ba4a8..6cd4db8915 100644 --- a/src/main/java/com/ning/http/client/providers/netty/timeout/TimeoutsHolder.java +++ b/src/main/java/com/ning/http/client/providers/netty/timeout/TimeoutsHolder.java @@ -21,16 +21,20 @@ public class TimeoutsHolder { - private AtomicBoolean cancelled = new AtomicBoolean(); + private final AtomicBoolean cancelled = new AtomicBoolean(); public volatile Timeout requestTimeout; public volatile Timeout idleConnectionTimeout; public void cancel() { if (cancelled.compareAndSet(false, true)) { - requestTimeout.cancel(); - idleConnectionTimeout.cancel(); - requestTimeout = null; - idleConnectionTimeout = null; + if (requestTimeout != null) { + requestTimeout.cancel(); + requestTimeout = null; + } + if (idleConnectionTimeout != null) { + idleConnectionTimeout.cancel(); + idleConnectionTimeout = null; + } } } } From bacc775ca576586f007afcc43783ea7690dfd9e0 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 18 Apr 2014 10:33:31 +0200 Subject: [PATCH 272/701] Bring back shaded version --- pom.xml | 64 ++++++++++++++++++++++++++++----------------------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/pom.xml b/pom.xml index b6be39df45..832d35d768 100644 --- a/pom.xml +++ b/pom.xml @@ -394,38 +394,38 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + org.apache.maven.plugins + maven-shade-plugin + 1.2.1 + + + package + + shade + + + true + shaded + + + commons-codec:commons-codec + commons-lang:commons-lang + commons-logging:commons-logging + junit:junit + log4j:log4j + commons-httpclient:commons-httpclient + + + + + + + + + + + From 375d4b1174cd2c18b128dab5fd082faadfb9110b Mon Sep 17 00:00:00 2001 From: Kelvin Law Date: Tue, 22 Apr 2014 14:27:54 -0700 Subject: [PATCH 273/701] Port #540 --- .../com/ning/http/client/RequestBuilderBase.java | 15 ++++++++++++++- .../http/client/async/RequestBuilderTest.java | 7 +++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/ning/http/client/RequestBuilderBase.java b/src/main/java/com/ning/http/client/RequestBuilderBase.java index 61c4c5052d..e2d0354f2d 100644 --- a/src/main/java/com/ning/http/client/RequestBuilderBase.java +++ b/src/main/java/com/ning/http/client/RequestBuilderBase.java @@ -621,9 +621,22 @@ public T setConnectionPoolKeyStrategy(ConnectionPoolKeyStrategy connectionPoolKe } public Request build() { + try { + final String contentType = request.headers.getFirstValue("Content-Type"); + if (contentType != null) { + final String charset = AsyncHttpProviderUtils.parseCharset(contentType); + if (charset != null) { + // ensure that if charset is provided with the Content-Type header, + // we propagate that down to the charset of the Request object + request.charset = charset; + } + } + } catch (Throwable e) { + // NoOp -- we can't fix the Content-Type or charset from here + } if (request.length < 0 && request.streamData == null) { // can't concatenate content-length - String contentLength = request.headers.getFirstValue("Content-Length"); + final String contentLength = request.headers.getFirstValue("Content-Length"); if (contentLength != null) { try { diff --git a/src/test/java/com/ning/http/client/async/RequestBuilderTest.java b/src/test/java/com/ning/http/client/async/RequestBuilderTest.java index 02f7e57a4b..b478e7a3ff 100644 --- a/src/test/java/com/ning/http/client/async/RequestBuilderTest.java +++ b/src/test/java/com/ning/http/client/async/RequestBuilderTest.java @@ -112,4 +112,11 @@ public void testPercentageEncodedUserInfo() { assertEquals(req.getMethod(), "GET"); assertEquals(req.getUrl(), "http://hello:wor%20ld@foo.com"); } + + public void testContentTypeCharsetToBodyEncoding() { + final Request req = new RequestBuilder("GET").setHeader("Content-Type", "application/json; charset=utf-8").build(); + assertEquals(req.getBodyEncoding(), "utf-8"); + final Request req2 = new RequestBuilder("GET").setHeader("Content-Type", "application/json; charset=\"utf-8\"").build(); + assertEquals(req2.getBodyEncoding(), "utf-8"); + } } From 4aed4b1e74dc091483d3d92af25d2e9e5f2b2bda Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 28 Apr 2014 09:53:40 +0200 Subject: [PATCH 274/701] Backport #539 --- .../ning/http/client/AsyncHttpClientConfigBean.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/main/java/com/ning/http/client/AsyncHttpClientConfigBean.java b/src/main/java/com/ning/http/client/AsyncHttpClientConfigBean.java index 01aab8d4af..8e2feccab4 100644 --- a/src/main/java/com/ning/http/client/AsyncHttpClientConfigBean.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClientConfigBean.java @@ -49,6 +49,7 @@ void configureDefaults() { idleConnectionInPoolTimeoutInMs = Integer.getInteger(ASYNC_CLIENT + "defaultIdleConnectionInPoolTimeoutInMS", 60 * 1000); idleConnectionTimeoutInMs = Integer.getInteger(ASYNC_CLIENT + "defaultIdleConnectionTimeoutInMS", 60 * 1000); requestTimeoutInMs = Integer.getInteger(ASYNC_CLIENT + "defaultRequestTimeoutInMS", 60 * 1000); + maxConnectionLifeTimeInMs = Integer.getInteger(ASYNC_CLIENT + "defaultMaxConnectionLifeTimeInMs", -1); redirectEnabled = Boolean.getBoolean(ASYNC_CLIENT + "defaultRedirectsEnabled"); maxDefaultRedirects = Integer.getInteger(ASYNC_CLIENT + "defaultMaxRedirects", 5); compressionEnabled = Boolean.getBoolean(ASYNC_CLIENT + "compressionEnabled"); @@ -107,6 +108,11 @@ public AsyncHttpClientConfigBean setIdleConnectionInPoolTimeoutInMs(int idleConn return this; } + public AsyncHttpClientConfigBean setStrict302Handling(boolean strict302Handling) { + this.strict302Handling = strict302Handling; + return this; + } + public AsyncHttpClientConfigBean setIdleConnectionTimeoutInMs(int idleConnectionTimeoutInMs) { this.idleConnectionTimeoutInMs = idleConnectionTimeoutInMs; return this; @@ -117,6 +123,11 @@ public AsyncHttpClientConfigBean setRequestTimeoutInMs(int requestTimeoutInMs) { return this; } + public AsyncHttpClientConfigBean setMaxConnectionLifeTimeInMs(int maxConnectionLifeTimeInMs) { + this.maxConnectionLifeTimeInMs = maxConnectionLifeTimeInMs; + return this; + } + public AsyncHttpClientConfigBean setRedirectEnabled(boolean redirectEnabled) { this.redirectEnabled = redirectEnabled; return this; From 8a17fc2182bd8a2e886317728406de458c01d536 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 28 Apr 2014 11:15:01 +0200 Subject: [PATCH 275/701] Still can't upload shaded jar!!! --- pom.xml | 64 ++++++++++++++++++++++++++++----------------------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/pom.xml b/pom.xml index 832d35d768..b6be39df45 100644 --- a/pom.xml +++ b/pom.xml @@ -394,38 +394,38 @@ - - org.apache.maven.plugins - maven-shade-plugin - 1.2.1 - - - package - - shade - - - true - shaded - - - commons-codec:commons-codec - commons-lang:commons-lang - commons-logging:commons-logging - junit:junit - log4j:log4j - commons-httpclient:commons-httpclient - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 470f4d23436cb1eb048e26022ba06705860c8c6a Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 28 Apr 2014 11:15:38 +0200 Subject: [PATCH 276/701] [maven-release-plugin] prepare release async-http-client-1.8.8 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index b6be39df45..78b7217712 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.8.8-SNAPSHOT + 1.8.8 jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From a3e436283947bcae2c1127751b5b57db106d0809 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 28 Apr 2014 11:15:43 +0200 Subject: [PATCH 277/701] [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 78b7217712..c57515d913 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.8.8 + 1.8.9-SNAPSHOT jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From 1428a7400e03a87733e9309c784e0cae06e26403 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 30 Apr 2014 21:47:12 +0200 Subject: [PATCH 278/701] Upgrade Netty 3.9.1, close #545 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index c57515d913..7aa874b4b4 100644 --- a/pom.xml +++ b/pom.xml @@ -81,7 +81,7 @@ io.netty netty - 3.9.0.Final + 3.9.1.Final From 402305b294cfa6feeb40247487ffb10f4718d19a Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 6 May 2014 15:47:15 +0200 Subject: [PATCH 279/701] Have idle timeout also expose remote ip, just like request timeout, close #548 --- .../netty/timeout/IdleConnectionTimeoutTimerTask.java | 3 ++- .../providers/netty/timeout/RequestTimeoutTimerTask.java | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/timeout/IdleConnectionTimeoutTimerTask.java b/src/main/java/com/ning/http/client/providers/netty/timeout/IdleConnectionTimeoutTimerTask.java index 32b0861992..316e7505fc 100644 --- a/src/main/java/com/ning/http/client/providers/netty/timeout/IdleConnectionTimeoutTimerTask.java +++ b/src/main/java/com/ning/http/client/providers/netty/timeout/IdleConnectionTimeoutTimerTask.java @@ -49,8 +49,9 @@ public void run(Timeout timeout) throws Exception { if (durationBeforeCurrentIdleConnectionTimeout <= 0L) { // idleConnectionTimeout reached + String message = "Idle connection timeout to " + nettyResponseFuture.getChannelRemoteAddress() + " of " + idleConnectionTimeout + " ms"; long durationSinceLastTouch = now - nettyResponseFuture.getLastTouch(); - expire("Idle connection timeout of " + idleConnectionTimeout + " ms", durationSinceLastTouch); + expire(message, durationSinceLastTouch); nettyResponseFuture.setIdleConnectionTimeoutReached(); } else if (currentIdleConnectionTimeoutInstant < requestTimeoutInstant) { diff --git a/src/main/java/com/ning/http/client/providers/netty/timeout/RequestTimeoutTimerTask.java b/src/main/java/com/ning/http/client/providers/netty/timeout/RequestTimeoutTimerTask.java index 7a8911a770..fa200a4f0e 100644 --- a/src/main/java/com/ning/http/client/providers/netty/timeout/RequestTimeoutTimerTask.java +++ b/src/main/java/com/ning/http/client/providers/netty/timeout/RequestTimeoutTimerTask.java @@ -38,8 +38,9 @@ public void run(Timeout timeout) throws Exception { } if (!nettyResponseFuture.isDone() && !nettyResponseFuture.isCancelled()) { + String message = "Request timed out to " + nettyResponseFuture.getChannelRemoteAddress() + " of " + nettyResponseFuture.getRequestTimeoutInMs() + " ms"; long age = millisTime() - nettyResponseFuture.getStart(); - expire("Request timed out to " + nettyResponseFuture.getChannelRemoteAddress() + " of " + nettyResponseFuture.getRequestTimeoutInMs() + " ms after " + age + " ms", age); + expire(message, age); nettyResponseFuture.setRequestTimeoutReached(); } } From c1fb38c4326a9dd83bb41c747afa257652db6dca Mon Sep 17 00:00:00 2001 From: oleksiys Date: Wed, 14 May 2014 22:29:14 -0700 Subject: [PATCH 280/701] [1.8.x] fix issue #549 https://github.com/AsyncHttpClient/async-http-client/issues/549 "[grizzly-provider] connection abort, when neither transfer-encoding nor content-length is specified" --- pom.xml | 5 +- .../grizzly/GrizzlyAsyncHttpProvider.java | 75 +++++++++++++------ .../grizzly/GrizzlyResponseStatus.java | 5 +- 3 files changed, 58 insertions(+), 27 deletions(-) diff --git a/pom.xml b/pom.xml index 7aa874b4b4..c034ca13e7 100644 --- a/pom.xml +++ b/pom.xml @@ -489,13 +489,13 @@ org.glassfish.grizzly grizzly-websockets - 2.3.11 + ${grizzly.version} true org.glassfish.grizzly grizzly-http-server - 2.3.11 + ${grizzly.version} test @@ -591,6 +591,7 @@ com/ning/http/client/providers/grizzly/*.java com/ning/http/client/async/grizzly/*.java com.ning.http.client.providers.grizzly + 2.3.12 1.5 1.5 2.12 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 9371ae0458..d9f87aca4a 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2013 Sonatype, Inc. All rights reserved. + * Copyright (c) 2012-2014 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. @@ -149,6 +149,7 @@ import com.ning.http.util.AuthenticatorUtils; import com.ning.http.util.ProxyUtils; import com.ning.http.util.SslUtils; +import org.glassfish.grizzly.http.HttpPacket; /** * A Grizzly 2.0-based implementation of {@link AsyncHttpProvider}. @@ -642,6 +643,7 @@ final class HttpTransactionContext { ProtocolHandler protocolHandler; WebSocket webSocket; boolean establishingTunnel; + boolean endOfResponseOnClose; // -------------------------------------------------------- Constructors @@ -679,6 +681,10 @@ HttpTransactionContext copy() { } + boolean isGracefullyFinishResponseOnClose() { + return endOfResponseOnClose && !responseStatus.getResponse().isChunked() + && responseStatus.getResponse().getContentLength() == -1; + } void abort(final Throwable t) { if (future != null) { @@ -742,36 +748,39 @@ public Object type() { private final class AsyncHttpClientTransportFilter extends TransportFilter { - @Override public NextAction handleRead(FilterChainContext ctx) throws IOException { final HttpTransactionContext context = getHttpTransactionContext(ctx.getConnection()); if (context == null) { return super.handleRead(ctx); } - ctx.getTransportContext().setCompletionHandler(new CompletionHandler() { - @Override - public void cancelled() { - - } - - @Override - public void failed(Throwable throwable) { - if (throwable instanceof EOFException) { - context.abort(new IOException("Remotely Closed")); - } - context.abort(throwable); - } + + IOException error = null; + NextAction nextAction = null; + + try { + nextAction = super.handleRead(ctx); + ctx.getConnection().assertOpen(); + } catch (IOException e) { + error = e instanceof EOFException ? + new IOException("Remotely Closed") : + e; + } - @Override - public void completed(Object result) { + if (error != null) { + if (context.isGracefullyFinishResponseOnClose()) { + ctx.setMessage(HttpContent.create( + context.responseStatus.getResponse(), true)); + return ctx.getInvokeAction(); + } else { + context.abort(error); + throw error; } + } - @Override - public void updated(Object result) { - } - }); - return super.handleRead(ctx); + assert nextAction != null; + + return nextAction; } } // END AsyncHttpClientTransportFilter @@ -1113,6 +1122,22 @@ private static final class AsyncHttpClientEventFilter extends HttpClientFilter { // --------------------------------------- Methods from HttpClientFilter + @Override + public NextAction handleRead(final FilterChainContext ctx) throws IOException { + final Object message = ctx.getMessage(); + if (HttpPacket.isHttp(message)) { + // TransportFilter tries to finish the request processing gracefully + final HttpPacket httpPacket = (HttpPacket) message; + onHttpPacketParsed(httpPacket.getHttpHeader(), ctx); + + return ctx.getInvokeAction(); + } + + // otherwise the message is a Buffer + return super.handleRead(ctx); + } + + @Override public void exceptionOccurred(FilterChainContext ctx, Throwable error) { @@ -1273,13 +1298,15 @@ protected void onHttpHeadersParsed(HttpHeader httpHeader, super.onHttpHeadersParsed(httpHeader, ctx); LOGGER.debug("RESPONSE: {}", httpHeader); + final HttpTransactionContext context = + provider.getHttpTransactionContext(ctx.getConnection()); + if (httpHeader.containsHeader(Header.Connection)) { if ("close".equals(httpHeader.getHeader(Header.Connection))) { + context.endOfResponseOnClose = true; ConnectionManager.markConnectionAsDoNotCache(ctx.getConnection()); } } - final HttpTransactionContext context = - provider.getHttpTransactionContext(ctx.getConnection()); if (httpHeader.isSkipRemainder() || context.establishingTunnel) { return; } diff --git a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponseStatus.java b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponseStatus.java index 2f25d35d6c..7774f10ac7 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponseStatus.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponseStatus.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012 Sonatype, Inc. All rights reserved. + * Copyright (c) 2012-2014 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. @@ -111,4 +111,7 @@ public String getProtocolText() { return response.getProtocolString(); } + public HttpResponsePacket getResponse() { + return response; + } } From 9ec5b43a157f04485f962c826969589df0a4ee1c Mon Sep 17 00:00:00 2001 From: oleksiys Date: Thu, 15 May 2014 01:31:00 -0700 Subject: [PATCH 281/701] [1.8.x] (rework) fix issue #549 https://github.com/AsyncHttpClient/async-http-client/issues/549 "[grizzly-provider] connection abort, when neither transfer-encoding nor content-length is specified" --- .../grizzly/GrizzlyAsyncHttpProvider.java | 67 +++++++---- .../GrizzlyNoTransferEncodingTest.java | 108 ++++++++++++++++++ 2 files changed, 154 insertions(+), 21 deletions(-) create mode 100644 src/test/java/com/ning/http/client/async/grizzly/GrizzlyNoTransferEncodingTest.java 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 d9f87aca4a..2c7e9d204e 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 @@ -643,7 +643,6 @@ final class HttpTransactionContext { ProtocolHandler protocolHandler; WebSocket webSocket; boolean establishingTunnel; - boolean endOfResponseOnClose; // -------------------------------------------------------- Constructors @@ -682,8 +681,9 @@ HttpTransactionContext copy() { } boolean isGracefullyFinishResponseOnClose() { - return endOfResponseOnClose && !responseStatus.getResponse().isChunked() - && responseStatus.getResponse().getContentLength() == -1; + final HttpResponsePacket response = responseStatus.getResponse(); + return !response.getProcessingState().isKeepAlive() && + !response.isChunked() && response.getContentLength() == -1; } void abort(final Throwable t) { @@ -746,7 +746,30 @@ public Object type() { } // END ContinueEvent + /** + * {@link FilterChainEvent} to gracefully complete the request-response processing + * when {@link Connection} is getting closed by the remote host. + * + * @since 1.8.7 + * @author The Grizzly Team + */ + public static class GracefulCloseEvent implements FilterChainEvent { + private final HttpTransactionContext httpTxContext; + + public GracefulCloseEvent(HttpTransactionContext httpTxContext) { + this.httpTxContext = httpTxContext; + } + + public HttpTransactionContext getHttpTxContext() { + return httpTxContext; + } + @Override + public Object type() { + return GracefulCloseEvent.class; + } + } // END GracefulCloseEvent + private final class AsyncHttpClientTransportFilter extends TransportFilter { @Override public NextAction handleRead(FilterChainContext ctx) throws IOException { @@ -769,13 +792,12 @@ public NextAction handleRead(FilterChainContext ctx) throws IOException { if (error != null) { if (context.isGracefullyFinishResponseOnClose()) { - ctx.setMessage(HttpContent.create( - context.responseStatus.getResponse(), true)); - return ctx.getInvokeAction(); + ctx.notifyUpstream(new GracefulCloseEvent(context)); } else { context.abort(error); - throw error; } + + throw error; } assert nextAction != null; @@ -1123,21 +1145,25 @@ private static final class AsyncHttpClientEventFilter extends HttpClientFilter { @Override - public NextAction handleRead(final FilterChainContext ctx) throws IOException { - final Object message = ctx.getMessage(); - if (HttpPacket.isHttp(message)) { - // TransportFilter tries to finish the request processing gracefully - final HttpPacket httpPacket = (HttpPacket) message; - onHttpPacketParsed(httpPacket.getHttpHeader(), ctx); - - return ctx.getInvokeAction(); - } - - // otherwise the message is a Buffer - return super.handleRead(ctx); - } + public NextAction handleEvent(final FilterChainContext ctx, + final FilterChainEvent event) throws IOException { + if (event.type() == GracefulCloseEvent.class) { + // Connection was closed. + // This event is fired only for responses, which don't have + // associated transfer-encoding or content-length. + // We have to complete such a request-response processing gracefully. + final GracefulCloseEvent closeEvent = (GracefulCloseEvent) event; + final HttpResponsePacket response = closeEvent.getHttpTxContext() + .responseStatus.getResponse(); + response.getProcessingState().getHttpContext().attach(ctx); + onHttpPacketParsed(response, ctx); + return ctx.getStopAction(); + } + return ctx.getInvokeAction(); + } + @Override public void exceptionOccurred(FilterChainContext ctx, Throwable error) { @@ -1303,7 +1329,6 @@ protected void onHttpHeadersParsed(HttpHeader httpHeader, if (httpHeader.containsHeader(Header.Connection)) { if ("close".equals(httpHeader.getHeader(Header.Connection))) { - context.endOfResponseOnClose = true; ConnectionManager.markConnectionAsDoNotCache(ctx.getConnection()); } } diff --git a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyNoTransferEncodingTest.java b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyNoTransferEncodingTest.java new file mode 100644 index 0000000000..8ce945dc25 --- /dev/null +++ b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyNoTransferEncodingTest.java @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2014 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.AsyncHttpClient; +import com.ning.http.client.AsyncHttpClientConfig; +import com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProvider; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import org.glassfish.grizzly.http.server.HttpHandler; +import org.glassfish.grizzly.http.server.HttpServer; +import org.glassfish.grizzly.http.server.NetworkListener; +import static org.glassfish.grizzly.http.server.NetworkListener.DEFAULT_NETWORK_HOST; +import org.glassfish.grizzly.http.server.Request; +import org.glassfish.grizzly.http.server.Response; +import org.testng.Assert; +import org.testng.annotations.AfterTest; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; + +public class GrizzlyNoTransferEncodingTest { + private static final String TEST_MESSAGE = "Hello World!"; + + private HttpServer server; + private int port; + // ------------------------------------------------------------------- Setup + + + @BeforeTest + public void setup() throws Exception { + server = new HttpServer(); + final NetworkListener listener = + new NetworkListener("server", + DEFAULT_NETWORK_HOST, + 0); + // disable chunking + listener.setChunkingEnabled(false); + server.addListener(listener); + server.getServerConfiguration().addHttpHandler( + new HttpHandler() { + + @Override + public void service(final Request request, + final Response response) throws Exception { + response.setContentType("plain/text;charset=\"utf-8\""); + // flush to make sure content-length will be missed + response.flush(); + + response.getWriter().write(TEST_MESSAGE); + } + }, "/test"); + + server.start(); + + port = listener.getPort(); + } + + + // --------------------------------------------------------------- Tear Down + + + @AfterTest + public void tearDown() { + server.shutdownNow(); + server = null; + } + + + // ------------------------------------------------------------ Test Methods + + + @Test + public void testNoTransferEncoding() throws Exception { + String url = "http://localhost:" + port + "/test"; + + AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder() + .setCompressionEnabled(true) + .setFollowRedirects(false) + .setConnectionTimeoutInMs(15000) + .setRequestTimeoutInMs(15000) + .setAllowPoolingConnection(false) + .setUseRawUrl(true) + .setIOThreadMultiplier(2) // 2 is default + .build(); + + AsyncHttpClient client = new AsyncHttpClient( + new GrizzlyAsyncHttpProvider(config), config); + + try { + Future f = client.prepareGet(url).execute(); + com.ning.http.client.Response r = f.get(10, TimeUnit.SECONDS); + Assert.assertEquals(TEST_MESSAGE, r.getResponseBody()); + } finally { + client.close(); + } + } +} From edd79c8eb1c35865677d28d0efc9c88e39db5f72 Mon Sep 17 00:00:00 2001 From: oleksiys Date: Thu, 15 May 2014 22:40:24 -0700 Subject: [PATCH 282/701] [1.8.x] fix issue #499 (not all the proposed changes are taken) https://github.com/AsyncHttpClient/async-http-client/pull/499 "NonBlockingFeeder improvements" --- .../grizzly/FeedableBodyGenerator.java | 46 +++--- .../GrizzlyFeedableBodyGeneratorTest.java | 147 ++++++++++++++++++ 2 files changed, 168 insertions(+), 25 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 5024d30c51..ef7e764e21 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012 Sonatype, Inc. All rights reserved. + * Copyright (c) 2012-2014 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. @@ -29,8 +29,6 @@ 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.threadpool.Threads; @@ -493,7 +491,7 @@ public NonBlockingFeeder(final FeedableBodyGenerator feedableBodyGenerator) { * It's important to only invoke {@link #feed(Buffer, boolean)} * once per invocation of {@link #canFeed()}. */ - public abstract void canFeed(); + public abstract void canFeed() throws IOException; /** * @return true if all data has been fed by this feeder, @@ -526,15 +524,14 @@ public NonBlockingFeeder(final FeedableBodyGenerator feedableBodyGenerator) { * {@inheritDoc} */ @Override - public synchronized void flush() { + public synchronized void flush() throws IOException { final Connection c = feedableBodyGenerator.context.getConnection(); if (isReady()) { - writeUntilFullOrDone(c); + boolean notReady = writeUntilFullOrDone(c); if (!isDone()) { - if (!isReady()) { + if (notReady) { notifyReadyToFeed(new ReadyToFeedListenerImpl()); - } - if (!c.canWrite()) { + } else { // write queue is full, leverage WriteListener to let us know // when it is safe to write again. c.notifyCanWrite(new WriteHandlerImpl()); @@ -549,15 +546,16 @@ public synchronized void flush() { // ----------------------------------------------------- Private Methods - private void writeUntilFullOrDone(final Connection c) { + private boolean writeUntilFullOrDone(final Connection c) throws IOException { while (c.canWrite()) { if (isReady()) { canFeed(); - } - if (!isReady()) { - break; + } else { + return true; } } + + return false; } @@ -596,17 +594,7 @@ private WriteHandlerImpl() { @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); - } - } + flush(); } @Override @@ -629,7 +617,15 @@ private final class ReadyToFeedListenerImpl @Override public void ready() { - flush(); + try { + flush(); + } catch (IOException e) { + final Connection c = feedableBodyGenerator.context.getConnection(); + c.setMaxAsyncWriteQueueSize(feedableBodyGenerator.origMaxPendingBytes); + GrizzlyAsyncHttpProvider.HttpTransactionContext ctx = + GrizzlyAsyncHttpProvider.getHttpTransactionContext(c); + ctx.abort(e); + } } } // END ReadToFeedListenerImpl 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 df46368153..c8b1e6cdf5 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 @@ -18,6 +18,7 @@ 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.FeedableBodyGenerator.NonBlockingFeeder; import com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProvider; import org.glassfish.grizzly.Buffer; import org.glassfish.grizzly.http.server.HttpHandler; @@ -115,6 +116,15 @@ public void testSimpleFeederOverSSLMultipleThreads() throws Exception { doSimpleFeeder(true); } + @Test + public void testNonBlockingFeederMultipleThreads() throws Exception { + doNonBlockingFeeder(false); + } + + @Test + public void testNonBlockingFeederOverSSLMultipleThreads() throws Exception { + doNonBlockingFeeder(true); + } // --------------------------------------------------------- Private Methods @@ -212,6 +222,8 @@ public void onThrowable(Throwable t) { latch.await(1, TimeUnit.MINUTES); } catch (InterruptedException e) { fail("Latch interrupted"); + } finally { + service.shutdownNow(); } for (int i = 0; i < threadCount; i++) { @@ -221,6 +233,141 @@ public void onThrowable(Throwable t) { } } + private void doNonBlockingFeeder(final boolean secure) { + 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"); + final ExecutorService service = Executors.newCachedThreadPool(); + + 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.NonBlockingFeeder nonBlockingFeeder = + new FeedableBodyGenerator.NonBlockingFeeder(generator) { + private final Random r = new Random(); + private final InputStream in; + private final byte[] bytesIn = new byte[2048]; + private boolean isDone; + + { + try { + in = new FileInputStream(tempFile); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + + @Override + public void canFeed() throws IOException { + final int read = in.read(bytesIn); + if (read == -1) { + isDone = true; + feed(Buffers.EMPTY_BUFFER, true); + return; + } + + final Buffer b = + Buffers.wrap( + DEFAULT_MEMORY_MANAGER, + bytesIn, + 0, + read); + feed(b, false); + } + + @Override + public boolean isDone() { + return isDone; + } + + @Override + public boolean isReady() { + // simulate real-life usecase, where data could not be ready + return r.nextInt(100) < 80; + } + + @Override + public void notifyReadyToFeed( + final NonBlockingFeeder.ReadyToFeedListener listener) { + service.execute(new Runnable() { + + public void run() { + try { + Thread.sleep(2); + } catch (InterruptedException e) { + } + + listener.ready(); + } + + }); + } + }; + generator.setFeeder(nonBlockingFeeder); + 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"); + } finally { + service.shutdownNow(); + } + + 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 { From 839be42089b21a7a422ff6fdccc43ebb9614f27c Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 16 May 2014 15:44:17 +0200 Subject: [PATCH 283/701] Fix test: http://google.com/ now replies with 302 --- src/test/java/com/ning/http/client/async/RemoteSiteTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 8eb3615299..50f83a4a68 100644 --- a/src/test/java/com/ning/http/client/async/RemoteSiteTest.java +++ b/src/test/java/com/ning/http/client/async/RemoteSiteTest.java @@ -116,7 +116,7 @@ public void testGoogleComWithTimeout() throws Throwable { try { Response response = c.prepareGet("http://google.com/").execute().get(10, TimeUnit.SECONDS); assertNotNull(response); - assertEquals(response.getStatusCode(), 301); + assertEquals(response.getStatusCode(), 302); } finally { c.close(); } From 4272eb0146c4e2e3d5f69e1a667e317b61f09d54 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 16 May 2014 17:13:09 +0200 Subject: [PATCH 284/701] Clean up test + uncover crazy Jetty 8 header normalization --- .../http/client/async/AbstractBasicTest.java | 7 +- .../client/async/AsyncStreamHandlerTest.java | 433 +++++++++--------- 2 files changed, 210 insertions(+), 230 deletions(-) diff --git a/src/test/java/com/ning/http/client/async/AbstractBasicTest.java b/src/test/java/com/ning/http/client/async/AbstractBasicTest.java index 9fc2c05090..c2f1a5e236 100644 --- a/src/test/java/com/ning/http/client/async/AbstractBasicTest.java +++ b/src/test/java/com/ning/http/client/async/AbstractBasicTest.java @@ -23,6 +23,7 @@ import com.ning.http.client.HttpResponseHeaders; import com.ning.http.client.HttpResponseStatus; import com.ning.http.client.Response; + import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.Server; @@ -37,11 +38,15 @@ import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; + import java.io.IOException; import java.net.ServerSocket; import java.util.Enumeration; public abstract class AbstractBasicTest { + + public final static String TEXT_HTML_CONTENT_TYPE_WITH_UTF_8_CHARSET = "text/html; charset=UTF-8"; + protected final Logger log = LoggerFactory.getLogger(AbstractBasicTest.class); protected Server server; protected int port1; @@ -64,7 +69,7 @@ public void handle(String pathInContext, if (httpRequest.getHeader("X-ISO") != null) { httpResponse.setContentType("text/html; charset=ISO-8859-1"); } else { - httpResponse.setContentType("text/html; charset=utf-8"); + httpResponse.setContentType(TEXT_HTML_CONTENT_TYPE_WITH_UTF_8_CHARSET); } if (request.getMethod().equalsIgnoreCase("OPTIONS")) { 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 ad78d7b664..319ec94031 100644 --- a/src/test/java/com/ning/http/client/async/AsyncStreamHandlerTest.java +++ b/src/test/java/com/ning/http/client/async/AsyncStreamHandlerTest.java @@ -15,46 +15,52 @@ */ package com.ning.http.client.async; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertNull; +import static org.testng.Assert.assertTrue; +import static org.testng.Assert.fail; + +import org.testng.annotations.Test; + import com.ning.http.client.AsyncHandler; import com.ning.http.client.AsyncHttpClient; +import com.ning.http.client.AsyncHttpClient.BoundRequestBuilder; import com.ning.http.client.AsyncHttpClientConfig; 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.Response; -import org.testng.Assert; -import org.testng.annotations.Test; 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; import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; public abstract class AsyncStreamHandlerTest extends AbstractBasicTest { private final static String RESPONSE = "param_1_"; - private final static String UTF8 = "text/html;charset=utf-8"; + + private String jetty8ContentTypeMadness(String saneValue) { + return saneValue.replace(" ", ""); + } @Test(groups = { "standalone", "default_provider" }) - public void asyncStreamGETTest() throws Throwable { - AsyncHttpClient client = getAsyncHttpClient(null); + public void asyncStreamGETTest() throws Exception { + final CountDownLatch l = new CountDownLatch(1); + AsyncHttpClient c = getAsyncHttpClient(null); + final AtomicReference responseHeaders = new AtomicReference(); + final AtomicReference throwable = new AtomicReference(); try { - final CountDownLatch l = new CountDownLatch(1); - - client.prepareGet(getTargetUrl()).execute(new AsyncHandlerAdapter() { + 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(Locale.ENGLISH), UTF8); + responseHeaders.set(content.getHeaders()); return STATE.ABORT; } finally { l.countDown(); @@ -64,7 +70,7 @@ public STATE onHeadersReceived(HttpResponseHeaders content) throws Exception { @Override public void onThrowable(Throwable t) { try { - Assert.fail("", t); + throwable.set(t); } finally { l.countDown(); } @@ -72,31 +78,35 @@ public void onThrowable(Throwable t) { }); if (!l.await(5, TimeUnit.SECONDS)) { - Assert.fail("Timeout out"); + fail("Timeout out"); } + + FluentCaseInsensitiveStringsMap h = responseHeaders.get(); + assertNotNull(h, "No response headers"); + assertEquals(h.getJoinedValue("content-type", ","), jetty8ContentTypeMadness(TEXT_HTML_CONTENT_TYPE_WITH_UTF_8_CHARSET), "Unexpected content-type"); + assertNull(throwable.get(), "Unexpected exception"); + } finally { - client.close(); + c.close(); } } @Test(groups = { "standalone", "default_provider" }) - public void asyncStreamPOSTTest() 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"); - Map> m = new HashMap>(); - m.put("param_1", Arrays.asList("value_1")); + public void asyncStreamPOSTTest() throws Exception { + + final AtomicReference responseHeaders = new AtomicReference(); - client.preparePost(getTargetUrl()).setParameters(m).execute(new AsyncHandlerAdapter() { + AsyncHttpClient c = getAsyncHttpClient(null); + try { + Future f = c.preparePost(getTargetUrl())// + .setHeader("Content-Type", "application/x-www-form-urlencoded")// + .addParameter("param_1", "value_1")// + .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(Locale.ENGLISH), UTF8); + responseHeaders.set(content.getHeaders()); return STATE.CONTINUE; } @@ -108,86 +118,79 @@ public STATE onBodyPartReceived(HttpResponseBodyPart content) throws Exception { @Override public String onCompleted() throws Exception { - try { - String r = builder.toString().trim(); - Assert.assertEquals(r, RESPONSE); - return r; - } finally { - l.countDown(); - } + return builder.toString().trim(); } }); - if (!l.await(10, TimeUnit.SECONDS)) { - Assert.fail("Timeout out"); - } + String responseBody = f.get(10, TimeUnit.SECONDS); + FluentCaseInsensitiveStringsMap h = responseHeaders.get(); + assertNotNull(h); + assertEquals(h.getJoinedValue("content-type", ","), jetty8ContentTypeMadness(TEXT_HTML_CONTENT_TYPE_WITH_UTF_8_CHARSET)); + assertEquals(responseBody, RESPONSE); + } finally { - client.close(); + c.close(); } } @Test(groups = { "standalone", "default_provider" }) - public void asyncStreamInterruptTest() throws Throwable { - AsyncHttpClient client = getAsyncHttpClient(null); + public void asyncStreamInterruptTest() throws Exception { + final CountDownLatch l = new CountDownLatch(1); + + AsyncHttpClient c = getAsyncHttpClient(null); + + final AtomicReference responseHeaders = new AtomicReference(); + final AtomicBoolean bodyReceived = new AtomicBoolean(false); + final AtomicReference throwable = new AtomicReference(); 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")); - - final AtomicBoolean a = new AtomicBoolean(true); - - client.preparePost(getTargetUrl()).setParameters(m).execute(new AsyncHandlerAdapter() { + c.preparePost(getTargetUrl())// + .setHeader("Content-Type", "application/x-www-form-urlencoded")// + .addParameter("param_1", "value_1")// + .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(Locale.ENGLISH), UTF8); + responseHeaders.set(content.getHeaders()); return STATE.ABORT; } @Override public STATE onBodyPartReceived(final HttpResponseBodyPart content) throws Exception { - a.set(false); - Assert.fail("Interrupted not working"); + bodyReceived.set(true); return STATE.ABORT; } @Override public void onThrowable(Throwable t) { - try { - Assert.fail("", t); - } finally { - l.countDown(); - } + throwable.set(t); + l.countDown(); } }); l.await(5, TimeUnit.SECONDS); - Assert.assertTrue(a.get()); + assertTrue(!bodyReceived.get(), "Interrupted not working"); + FluentCaseInsensitiveStringsMap h = responseHeaders.get(); + assertNotNull(h, "Should receive non null headers"); + assertEquals(h.getJoinedValue("content-type", ", "), jetty8ContentTypeMadness(TEXT_HTML_CONTENT_TYPE_WITH_UTF_8_CHARSET), "Unexpected content-type"); + assertNull(throwable.get(), "Should get an exception"); + } finally { - client.close(); + c.close(); } } @Test(groups = { "standalone", "default_provider" }) - public void asyncStreamFutureTest() throws Throwable { - AsyncHttpClient client = getAsyncHttpClient(null); + public void asyncStreamFutureTest() throws Exception { + AsyncHttpClient c = getAsyncHttpClient(null); + final AtomicReference responseHeaders = new AtomicReference(); + final AtomicReference throwable = new AtomicReference(); try { - Map> m = new HashMap>(); - m.put("param_1", Arrays.asList("value_1")); - - Future f = client.preparePost(getTargetUrl()).setParameters(m).execute(new AsyncHandlerAdapter() { + Future f = c.preparePost(getTargetUrl()).addParameter("param_1", "value_1").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(Locale.ENGLISH), UTF8); + responseHeaders.set(content.getHeaders()); return STATE.CONTINUE; } @@ -199,36 +202,35 @@ public STATE onBodyPartReceived(HttpResponseBodyPart content) throws Exception { @Override public String onCompleted() throws Exception { - String r = builder.toString().trim(); - Assert.assertEquals(r, RESPONSE); - return r; + return builder.toString().trim(); } @Override public void onThrowable(Throwable t) { - Assert.fail("", t); + throwable.set(t); } }); - try { - String r = f.get(5, TimeUnit.SECONDS); - Assert.assertNotNull(r); - Assert.assertEquals(r.trim(), RESPONSE); - } catch (TimeoutException ex) { - Assert.fail(); - } + String responseBody = f.get(5, TimeUnit.SECONDS); + FluentCaseInsensitiveStringsMap h = responseHeaders.get(); + assertNotNull(h, "Should receive non null headers"); + assertEquals(h.getJoinedValue("content-type", ", "), jetty8ContentTypeMadness(TEXT_HTML_CONTENT_TYPE_WITH_UTF_8_CHARSET), "Unexpected content-type"); + assertNotNull(responseBody, "No response body"); + assertEquals(responseBody.trim(), RESPONSE, "Unexpected response body"); + assertNull(throwable.get(), "Unexpected exception"); + } finally { - client.close(); + c.close(); } } @Test(groups = { "standalone", "default_provider" }) - public void asyncStreamThrowableRefusedTest() throws Throwable { - AsyncHttpClient client = getAsyncHttpClient(null); - try { - final CountDownLatch l = new CountDownLatch(1); + public void asyncStreamThrowableRefusedTest() throws Exception { - client.prepareGet(getTargetUrl()).execute(new AsyncHandlerAdapter() { + final CountDownLatch l = new CountDownLatch(1); + AsyncHttpClient c = getAsyncHttpClient(null); + try { + c.prepareGet(getTargetUrl()).execute(new AsyncHandlerAdapter() { @Override public STATE onHeadersReceived(HttpResponseHeaders content) throws Exception { @@ -239,7 +241,7 @@ public STATE onHeadersReceived(HttpResponseHeaders content) throws Exception { public void onThrowable(Throwable t) { try { if (t.getMessage() != null) { - Assert.assertEquals(t.getMessage(), "FOO"); + assertEquals(t.getMessage(), "FOO"); } } finally { l.countDown(); @@ -248,32 +250,29 @@ public void onThrowable(Throwable t) { }); if (!l.await(10, TimeUnit.SECONDS)) { - Assert.fail("Timed out"); + fail("Timed out"); } } finally { - client.close(); + c.close(); } } @Test(groups = { "standalone", "default_provider" }) - public void asyncStreamReusePOSTTest() 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"); - - Map> m = new HashMap>(); - m.put("param_1", Arrays.asList("value_1")); + public void asyncStreamReusePOSTTest() throws Exception { - client.preparePost(getTargetUrl()).setParameters(m).execute(new AsyncHandlerAdapter() { + AsyncHttpClient c = getAsyncHttpClient(null); + final AtomicReference responseHeaders = new AtomicReference(); + try { + BoundRequestBuilder rb = c.preparePost(getTargetUrl())// + .setHeader("Content-Type", "application/x-www-form-urlencoded") + .addParameter("param_1", "value_1"); + + Future f = rb.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(Locale.ENGLISH), UTF8); + responseHeaders.set(content.getHeaders()); return STATE.CONTINUE; } @@ -285,30 +284,26 @@ public STATE onBodyPartReceived(HttpResponseBodyPart content) throws Exception { @Override public String onCompleted() throws Exception { - try { - String r = builder.toString().trim(); - Assert.assertEquals(r, RESPONSE); - return r; - } finally { - l.countDown(); - } - + return builder.toString(); } }); - if (!l.await(20, TimeUnit.SECONDS)) { - Assert.fail("Timeout out"); - } + String r = f.get(5, TimeUnit.SECONDS); + FluentCaseInsensitiveStringsMap h = responseHeaders.get(); + assertNotNull(h, "Should receive non null headers"); + assertEquals(h.getJoinedValue("content-type", ", "), jetty8ContentTypeMadness(TEXT_HTML_CONTENT_TYPE_WITH_UTF_8_CHARSET), "Unexpected content-type"); + assertNotNull(r, "No response body"); + assertEquals(r.trim(), RESPONSE, "Unexpected response body"); + + responseHeaders.set(null); // Let do the same again - client.preparePost(getTargetUrl()).setParameters(m).execute(new AsyncHandlerAdapter() { + f = rb.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(Locale.ENGLISH), UTF8); + responseHeaders.set(content.getHeaders()); return STATE.CONTINUE; } @@ -320,153 +315,141 @@ public STATE onBodyPartReceived(HttpResponseBodyPart content) throws Exception { @Override public String onCompleted() throws Exception { - try { - String r = builder.toString().trim(); - Assert.assertEquals(r, RESPONSE); - return r; - } finally { - l.countDown(); - } + return builder.toString(); } }); - if (!l.await(20, TimeUnit.SECONDS)) { - Assert.fail("Timeout out"); - } + f.get(5, TimeUnit.SECONDS); + h = responseHeaders.get(); + assertNotNull(h, "Should receive non null headers"); + assertEquals(h.getJoinedValue("content-type", ", "), jetty8ContentTypeMadness(TEXT_HTML_CONTENT_TYPE_WITH_UTF_8_CHARSET), "Unexpected content-type"); + assertNotNull(r, "No response body"); + assertEquals(r.trim(), RESPONSE, "Unexpected response body"); } finally { - client.close(); + c.close(); } } @Test(groups = { "online", "default_provider" }) - public void asyncStream301WithBody() throws Throwable { - AsyncHttpClient client = getAsyncHttpClient(null); + public void asyncStream302WithBody() throws Exception { + AsyncHttpClient c = getAsyncHttpClient(null); + final AtomicReference statusCode = new AtomicReference(0); + final AtomicReference headers = new AtomicReference(); try { - final CountDownLatch l = new CountDownLatch(1); - client.prepareGet("http://google.com/").execute(new AsyncHandlerAdapter() { - private StringBuilder builder = new StringBuilder(); + Future f = c.prepareGet("http://google.com/").execute(new AsyncHandlerAdapter() { + + public STATE onStatusReceived(HttpResponseStatus status) throws Exception { + statusCode.set(status.getStatusCode()); + 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(Locale.ENGLISH), "text/html; charset=utf-8"); + headers.set(content.getHeaders()); return STATE.CONTINUE; } @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; + return null; } }); - if (!l.await(20, TimeUnit.SECONDS)) { - Assert.fail("Timeout out"); - } + f.get(20, TimeUnit.SECONDS); + assertEquals(statusCode.get().intValue(), 302); + FluentCaseInsensitiveStringsMap h = headers.get(); + assertNotNull(h); + assertEquals(h.getJoinedValue("content-type", ", ").toLowerCase(Locale.ENGLISH), TEXT_HTML_CONTENT_TYPE_WITH_UTF_8_CHARSET.toLowerCase(Locale.ENGLISH)); + } finally { - client.close(); + c.close(); } } @Test(groups = { "online", "default_provider" }) - public void asyncStream301RedirectWithBody() throws Throwable { - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setFollowRedirects(true).build()); + public void asyncStream302RedirectWithBody() throws Exception { + AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setFollowRedirects(true).build()); + final AtomicReference statusCode = new AtomicReference(0); + final AtomicReference responseHeaders = new AtomicReference(); try { - final CountDownLatch l = new CountDownLatch(1); - client.prepareGet("http://google.com/").execute(new AsyncHandlerAdapter() { - private StringBuilder builder = new StringBuilder(); + Future f = c.prepareGet("http://google.com/").execute(new AsyncHandlerAdapter() { - @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"); + public STATE onStatusReceived(HttpResponseStatus status) throws Exception { + statusCode.set(status.getStatusCode()); return STATE.CONTINUE; } @Override - public STATE onBodyPartReceived(HttpResponseBodyPart content) throws Exception { - builder.append(new String(content.getBodyPartBytes())); + public STATE onHeadersReceived(HttpResponseHeaders content) throws Exception { + responseHeaders.set(content.getHeaders()); return STATE.CONTINUE; } @Override public String onCompleted() throws Exception { - String r = builder.toString(); - Assert.assertTrue(!r.contains("301 Moved")); - l.countDown(); - - return r; + return null; } }); - if (!l.await(20, TimeUnit.SECONDS)) { - Assert.fail("Timeout out"); - } + f.get(20, TimeUnit.SECONDS); + assertTrue(statusCode.get() != 302); + FluentCaseInsensitiveStringsMap h = responseHeaders.get(); + assertNotNull(h); + 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. + // + // assertEquals(h.getJoinedValue("content-type", ", "), "text/html; charset=ISO-8859-1"); } finally { - client.close(); + c.close(); } } @Test(groups = { "standalone", "default_provider" }, timeOut = 3000, description = "Test behavior of 'read only status line' scenario.") - public void asyncStreamJustStatusLine() throws Throwable { + public void asyncStreamJustStatusLine() throws Exception { + 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); 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 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 onHeadersReceived(HttpResponseHeaders headers) throws Exception { whatCalled[OTHER] = true; latch.countDown(); return STATE.ABORT; } - /* @Override */ public Integer onCompleted() throws Exception { whatCalled[COMPLETED] = true; latch.countDown(); @@ -475,20 +458,20 @@ public Integer onCompleted() throws Exception { }); if (!latch.await(2, TimeUnit.SECONDS)) { - Assert.fail("Timeout"); + fail("Timeout"); return; } Integer status = statusCode.get(TIMEOUT, TimeUnit.SECONDS); - Assert.assertEquals((int) status, 200, "Expected status code failed."); + assertEquals((int) status, 200, "Expected status code failed."); if (!whatCalled[STATUS]) { - Assert.fail("onStatusReceived not called."); + fail("onStatusReceived not called."); } if (!whatCalled[COMPLETED]) { - Assert.fail("onCompleted not called."); + fail("onCompleted not called."); } if (whatCalled[OTHER]) { - Assert.fail("Other method of AsyncHandler got called."); + fail("Other method of AsyncHandler got called."); } } finally { client.close(); @@ -496,53 +479,45 @@ public Integer onCompleted() throws Exception { } @Test(groups = { "online", "default_provider" }) - public void asyncOptionsTest() throws Throwable { - AsyncHttpClient client = getAsyncHttpClient(null); + public void asyncOptionsTest() throws Exception { + AsyncHttpClient c = getAsyncHttpClient(null); + final AtomicReference responseHeaders = new AtomicReference(); + try { - final CountDownLatch l = new CountDownLatch(1); - client.prepareOptions("http://www.apache.org/").execute(new AsyncHandlerAdapter() { + final String[] expected = { "GET", "HEAD", "OPTIONS", "POST", "TRACE" }; + Future f = 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); + responseHeaders.set(content.getHeaders()); return STATE.ABORT; } - @Override - public STATE onBodyPartReceived(HttpResponseBodyPart content) throws Exception { - return STATE.CONTINUE; - } - @Override public String onCompleted() throws Exception { - try { - return "OK"; - } finally { - l.countDown(); - } + return "OK"; } }); - if (!l.await(20, TimeUnit.SECONDS)) { - Assert.fail("Timeout out"); - } + f.get(20, TimeUnit.SECONDS) ; + FluentCaseInsensitiveStringsMap h = responseHeaders.get(); + assertNotNull(h); + String[] values = h.get("Allow").get(0).split(",|, "); + assertNotNull(values); + assertEquals(values.length, expected.length); + Arrays.sort(values); + assertEquals(values, expected); + } finally { - client.close(); + c.close(); } } @Test(groups = { "standalone", "default_provider" }) - public void closeConnectionTest() throws Throwable { - AsyncHttpClient client = getAsyncHttpClient(null); + public void closeConnectionTest() throws Exception { + AsyncHttpClient c = getAsyncHttpClient(null); try { - Response r = client.prepareGet(getTargetUrl()).execute(new AsyncHandler() { + Response r = c.prepareGet(getTargetUrl()).execute(new AsyncHandler() { private Response.ResponseBuilder builder = new Response.ResponseBuilder(); @@ -558,7 +533,7 @@ public STATE onBodyPartReceived(HttpResponseBodyPart content) throws Exception { builder.accumulate(content); if (content.isLast()) { - content.markUnderlyingConnectionAsClosed(); + content.closeUnderlyingConnection(); } return STATE.CONTINUE; } @@ -574,10 +549,10 @@ public Response onCompleted() throws Exception { } }).get(); - Assert.assertNotNull(r); - Assert.assertEquals(r.getStatusCode(), 200); + assertNotNull(r); + assertEquals(r.getStatusCode(), 200); } finally { - client.close(); + c.close(); } } } From 88c1566f2589cc9d97e8174d14e959ee3f27303a Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 20 May 2014 11:11:35 +0200 Subject: [PATCH 285/701] Make SignatureCalculator available on RequestBuilderBase, close #557 --- .../com/ning/http/client/AsyncHttpClient.java | 27 +------------------ .../ning/http/client/RequestBuilderBase.java | 22 +++++++++++++++ 2 files changed, 23 insertions(+), 26 deletions(-) diff --git a/src/main/java/com/ning/http/client/AsyncHttpClient.java b/src/main/java/com/ning/http/client/AsyncHttpClient.java index a2e86d9965..10eb77d984 100755 --- a/src/main/java/com/ning/http/client/AsyncHttpClient.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClient.java @@ -212,17 +212,6 @@ public AsyncHttpClient(String providerClass, AsyncHttpClientConfig config) { } public class BoundRequestBuilder extends RequestBuilderBase { - /** - * Calculator used for calculating request signature for the request being - * built, if any. - */ - protected SignatureCalculator signatureCalculator; - - /** - * URL used as the base, not including possibly query parameters. Needed for - * signature calculation - */ - protected String baseURL; private BoundRequestBuilder(String reqType, boolean useRawUrl) { super(BoundRequestBuilder.class, reqType, useRawUrl); @@ -271,18 +260,6 @@ public BoundRequestBuilder addQueryParameter(String name, String value) { @Override public Request build() { - /* Let's first calculate and inject signature, before finalizing actual build - * (order does not matter with current implementation but may in future) - */ - if (signatureCalculator != null) { - String url = baseURL; - // Should not include query parameters, ensure: - int i = url.indexOf('?'); - if (i >= 0) { - url = url.substring(0, i); - } - signatureCalculator.calculateAndAddSignature(url, request, this); - } return super.build(); } @@ -338,7 +315,6 @@ public BoundRequestBuilder setParameters(FluentStringsMap parameters) throws Ill @Override public BoundRequestBuilder setUrl(String url) { - baseURL = url; return super.setUrl(url); } @@ -348,8 +324,7 @@ public BoundRequestBuilder setVirtualHost(String virtualHost) { } public BoundRequestBuilder setSignatureCalculator(SignatureCalculator signatureCalculator) { - this.signatureCalculator = signatureCalculator; - return this; + return super.setSignatureCalculator(signatureCalculator); } } diff --git a/src/main/java/com/ning/http/client/RequestBuilderBase.java b/src/main/java/com/ning/http/client/RequestBuilderBase.java index e2d0354f2d..748f893a9c 100644 --- a/src/main/java/com/ning/http/client/RequestBuilderBase.java +++ b/src/main/java/com/ning/http/client/RequestBuilderBase.java @@ -357,6 +357,8 @@ public boolean isUseRawUrl() { private final Class derived; protected final RequestImpl request; protected boolean useRawUrl = false; + protected String baseURL; + protected SignatureCalculator signatureCalculator; protected RequestBuilderBase(Class derived, String method, boolean rawUrls) { this.derived = derived; @@ -372,6 +374,7 @@ protected RequestBuilderBase(Class derived, Request prototype) { } public T setUrl(String url) { + this.baseURL = url; return setURI(URI.create(url)); } @@ -620,7 +623,26 @@ public T setConnectionPoolKeyStrategy(ConnectionPoolKeyStrategy connectionPoolKe return derived.cast(this); } + public T setSignatureCalculator(SignatureCalculator signatureCalculator) { + this.signatureCalculator = signatureCalculator; + return derived.cast(this); + } + public Request build() { + + /* Let's first calculate and inject signature, before finalizing actual build + * (order does not matter with current implementation but may in future) + */ + if (signatureCalculator != null) { + String url = baseURL != null ? baseURL : request.originalUri.toString(); + // Should not include query parameters, ensure: + int i = url.indexOf('?'); + if (i != -1) { + url = url.substring(0, i); + } + signatureCalculator.calculateAndAddSignature(url, request, this); + } + try { final String contentType = request.headers.getFirstValue("Content-Type"); if (contentType != null) { From 5061749acfd37f6c80d86959c8315f0e1c5321a3 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 20 May 2014 15:27:29 +0200 Subject: [PATCH 286/701] Introduce Realm useAbsoluteURI and omitQuery, close #553 --- src/main/java/com/ning/http/client/Realm.java | 51 +++++++++++++++++-- .../netty/NettyAsyncHttpProvider.java | 40 +++++++++++---- 2 files changed, 79 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/ning/http/client/Realm.java b/src/main/java/com/ning/http/client/Realm.java index 111390ac67..2dc5a17fb0 100644 --- a/src/main/java/com/ning/http/client/Realm.java +++ b/src/main/java/com/ning/http/client/Realm.java @@ -46,6 +46,8 @@ public class Realm { private final String enc; private final String host; private final boolean messageType2Received; + private final boolean useAbsoluteURI; + private final boolean omitQuery; private final String domain; @@ -71,8 +73,13 @@ private Realm(AuthScheme scheme, String uri, String method, boolean usePreemptiveAuth, - String domain, String enc, String host, boolean messageType2Received, - String opaque) { + String domain, + String enc, + String host, + boolean messageType2Received, + String opaque, + boolean useAbsoluteURI, + boolean omitQuery) { this.principal = principal; this.password = password; @@ -92,6 +99,8 @@ private Realm(AuthScheme scheme, this.enc = enc; this.host = host; this.messageType2Received = messageType2Received; + this.useAbsoluteURI = useAbsoluteURI; + this.omitQuery = omitQuery; } public String getPrincipal() { @@ -196,6 +205,14 @@ public boolean isNtlmMessageType2Received() { return messageType2Received; } + public boolean isUseAbsoluteURI() { + return useAbsoluteURI; + } + + public boolean isOmitQuery() { + return omitQuery; + } + @Override public boolean equals(Object o) { if (this == o) return true; @@ -214,6 +231,8 @@ public boolean equals(Object o) { if (response != null ? !response.equals(realm.response) : realm.response != null) return false; if (scheme != realm.scheme) return false; if (uri != null ? !uri.equals(realm.uri) : realm.uri != null) return false; + if (useAbsoluteURI != !realm.useAbsoluteURI) return false; + if (omitQuery != !realm.omitQuery) return false; return true; } @@ -233,6 +252,8 @@ public String toString() { ", cnonce='" + cnonce + '\'' + ", uri='" + uri + '\'' + ", methodName='" + methodName + '\'' + + ", useAbsoluteURI='" + useAbsoluteURI + '\'' + + ", omitQuery='" + omitQuery + '\'' + '}'; } @@ -280,6 +301,8 @@ public static class RealmBuilder { private String enc = "UTF-8"; private String host = "localhost"; private boolean messageType2Received = false; + private boolean useAbsoluteURI = true; + private boolean omitQuery = false; @Deprecated public String getDomain() { @@ -428,6 +451,24 @@ public RealmBuilder setUsePreemptiveAuth(boolean usePreemptiveAuth) { return this; } + public boolean isUseAbsoluteURI() { + return useAbsoluteURI; + } + + public RealmBuilder setUseAbsoluteURI(boolean useAbsoluteURI) { + this.useAbsoluteURI = useAbsoluteURI; + return this; + } + + public boolean isOmitQuery() { + return omitQuery; + } + + public RealmBuilder setOmitQuery(boolean omitQuery) { + this.omitQuery = omitQuery; + return this; + } + public RealmBuilder parseWWWAuthenticateHeader(String headerLine) { setRealmName(match(headerLine, "realm")); setNonce(match(headerLine, "nonce")); @@ -467,6 +508,8 @@ public RealmBuilder clone(Realm clone) { setNtlmDomain(clone.getNtlmDomain()); setNtlmHost(clone.getNtlmHost()); setNtlmMessageType2Received(clone.isNtlmMessageType2Received()); + setUseAbsoluteURI(clone.isUseAbsoluteURI()); + setOmitQuery(clone.isOmitQuery()); return this; } @@ -618,7 +661,9 @@ public Realm build() { enc, host, messageType2Received, - opaque); + opaque, + useAbsoluteURI, + omitQuery); } } 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 37a25c7440..813681e4f3 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 @@ -40,6 +40,7 @@ import java.net.InetSocketAddress; import java.net.MalformedURLException; import java.net.URI; +import java.net.URISyntaxException; import java.nio.channels.ClosedChannelException; import java.nio.channels.FileChannel; import java.nio.channels.WritableByteChannel; @@ -152,6 +153,7 @@ import com.ning.http.util.AsyncHttpProviderUtils; import com.ning.http.util.AuthenticatorUtils; import com.ning.http.util.CleanupChannelGroup; +import com.ning.http.util.MiscUtil; import com.ning.http.util.ProxyUtils; import com.ning.http.util.SslUtils; import com.ning.http.util.UTF8UrlEncoder; @@ -2017,6 +2019,28 @@ public Object call() throws Exception { return false; } + private final String computeRealmURI(Realm realm, URI requestURI) throws URISyntaxException { + if (realm.isUseAbsoluteURI()) { + + if (realm.isOmitQuery() && MiscUtil.isNonEmpty(requestURI.getQuery())) { + return new URI( + requestURI.getScheme(), + requestURI.getAuthority(), + requestURI.getPath(), + null, + null).toString(); + } else { + return requestURI.toString(); + } + } else { + if (realm.isOmitQuery() && MiscUtil.isNonEmpty(requestURI.getQuery())) { + return requestURI.getPath(); + } else { + return requestURI.getPath() + "?" + requestURI.getQuery(); + } + } + } + private final class HttpProtocol implements Protocol { // @Override public void handle(final ChannelHandlerContext ctx, final MessageEvent e) throws Exception { @@ -2077,7 +2101,6 @@ public void handle(final ChannelHandlerContext ctx, final MessageEvent e) throws return; } - Realm newRealm = null; final FluentCaseInsensitiveStringsMap headers = request.getHeaders(); final RequestBuilder builder = new RequestBuilder(future.getRequest()); @@ -2088,6 +2111,8 @@ public void handle(final ChannelHandlerContext ctx, final MessageEvent e) throws if (statusCode == 401 && realm != null && !wwwAuth.isEmpty() && !future.getAndSetAuth(true)) { future.setState(NettyResponseFuture.STATE.NEW); + Realm newRealm = null; + // NTLM if (!wwwAuth.contains("Kerberos") && (isNTLM(wwwAuth) || (wwwAuth.contains("Negotiate")))) { newRealm = ntlmChallenge(wwwAuth, request, proxyServer, headers, realm, future); @@ -2097,17 +2122,13 @@ public void handle(final ChannelHandlerContext ctx, final MessageEvent e) throws if (newRealm == null) return; } else { - Realm.RealmBuilder realmBuilder; - if (realm != null) { - realmBuilder = new Realm.RealmBuilder().clone(realm).setScheme(realm.getAuthScheme()); - } else { - realmBuilder = new Realm.RealmBuilder(); - } + Realm.RealmBuilder realmBuilder = new Realm.RealmBuilder().clone(realm).setScheme(realm.getAuthScheme()); 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.getURI().getPath()).build(); + + String realmURI = computeRealmURI(newRealm, request.getURI()); + final Realm nr = new Realm.RealmBuilder().clone(newRealm).setUri(realmURI).build(); log.debug("Sending authentication to {}", request.getUrl()); AsyncCallable ac = new AsyncCallable(future) { @@ -2140,6 +2161,7 @@ public Object call() throws Exception { log.debug("Sending proxy authentication to {}", request.getUrl()); future.setState(NettyResponseFuture.STATE.NEW); + Realm newRealm = null; if (!proxyAuth.contains("Kerberos") && (isNTLM(proxyAuth) || (proxyAuth.contains("Negotiate")))) { newRealm = ntlmProxyChallenge(proxyAuth, request, proxyServer, headers, realm, future); From f2a087b57d884b9b3b21ae3eb665bdb409551b7e Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 20 May 2014 15:40:40 +0200 Subject: [PATCH 287/701] Trying to deploy shaded jar once again, may the Sonatype gods be with us... --- pom.xml | 64 ++++++++++++++++++++++++++++----------------------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/pom.xml b/pom.xml index c034ca13e7..fba5fa02b2 100644 --- a/pom.xml +++ b/pom.xml @@ -394,38 +394,38 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + org.apache.maven.plugins + maven-shade-plugin + 1.2.1 + + + package + + shade + + + true + shaded + + + commons-codec:commons-codec + commons-lang:commons-lang + commons-logging:commons-logging + junit:junit + log4j:log4j + commons-httpclient:commons-httpclient + + + + + + + + + + + From 23ef07a6965d792b31569eb0492e4b3a9745b68e Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 20 May 2014 15:48:04 +0200 Subject: [PATCH 288/701] Upgrade OSS parent --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index fba5fa02b2..e27193dcbf 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ org.sonatype.oss oss-parent - 5 + 9 4.0.0 com.ning From 9886803675ad7f5497ea2810b823ee7d1525a731 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 20 May 2014 15:57:25 +0200 Subject: [PATCH 289/701] Definitively giving up on shaded jar (at least as far as I'm concerned) --- pom.xml | 64 ++++++++++++++++++++++++++++----------------------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/pom.xml b/pom.xml index e27193dcbf..2ebf207346 100644 --- a/pom.xml +++ b/pom.xml @@ -394,38 +394,38 @@ - - org.apache.maven.plugins - maven-shade-plugin - 1.2.1 - - - package - - shade - - - true - shaded - - - commons-codec:commons-codec - commons-lang:commons-lang - commons-logging:commons-logging - junit:junit - log4j:log4j - commons-httpclient:commons-httpclient - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 06ef0df0f1927925492b356dea182b6218c6fcca Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 20 May 2014 15:58:12 +0200 Subject: [PATCH 290/701] [maven-release-plugin] prepare release async-http-client-1.8.9 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 2ebf207346..a12dcb130b 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.8.9-SNAPSHOT + 1.8.9 jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From 60dd3c065e005df2f0acaa72d36f7d30d5c128d3 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 20 May 2014 15:58:17 +0200 Subject: [PATCH 291/701] [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 a12dcb130b..195daaae76 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.8.9 + 1.8.10-SNAPSHOT jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From 11f1719ebf5dcbd5d8cfee75e21e4119a9eca243 Mon Sep 17 00:00:00 2001 From: oleksiys Date: Tue, 20 May 2014 22:28:06 -0700 Subject: [PATCH 292/701] [1.8.x] + fix the issue #559 https://github.com/AsyncHttpClient/async-http-client/issues/559 GrizzlyAsyncHttpProvider hangs on Exception #559 --- .../grizzly/GrizzlyAsyncHttpProvider.java | 40 +++++++++++-------- 1 file changed, 23 insertions(+), 17 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 2c7e9d204e..3a8227e2fa 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 @@ -149,7 +149,6 @@ import com.ning.http.util.AuthenticatorUtils; import com.ning.http.util.ProxyUtils; import com.ning.http.util.SslUtils; -import org.glassfish.grizzly.http.HttpPacket; /** * A Grizzly 2.0-based implementation of {@link AsyncHttpProvider}. @@ -807,7 +806,7 @@ public NextAction handleRead(FilterChainContext ctx) throws IOException { } // END AsyncHttpClientTransportFilter - + private final class AsyncHttpClientFilter extends BaseFilter { @@ -1167,7 +1166,7 @@ public NextAction handleEvent(final FilterChainContext ctx, @Override public void exceptionOccurred(FilterChainContext ctx, Throwable error) { - provider.getHttpTransactionContext(ctx.getConnection()).abort(error); + getHttpTransactionContext(ctx.getConnection()).abort(error); } @@ -1177,7 +1176,7 @@ protected void onHttpContentParsed(HttpContent content, FilterChainContext ctx) { final HttpTransactionContext context = - provider.getHttpTransactionContext(ctx.getConnection()); + getHttpTransactionContext(ctx.getConnection()); final AsyncHandler handler = context.handler; if (handler != null && context.currentState != AsyncHandler.STATE.ABORT) { try { @@ -1195,7 +1194,8 @@ protected void onHttpContentParsed(HttpContent content, @Override protected void onHttpHeadersEncoded(HttpHeader httpHeader, FilterChainContext ctx) { - final HttpTransactionContext context = provider.getHttpTransactionContext(ctx.getConnection()); + final HttpTransactionContext context = + getHttpTransactionContext(ctx.getConnection()); final AsyncHandler handler = context.handler; if (handler instanceof TransferCompletionHandler) { ((TransferCompletionHandler) handler).onHeaderWriteCompleted(); @@ -1207,7 +1207,8 @@ protected void onHttpHeadersEncoded(HttpHeader httpHeader, FilterChainContext ct @Override protected void onHttpContentEncoded(HttpContent content, FilterChainContext ctx) { - final HttpTransactionContext context = provider.getHttpTransactionContext(ctx.getConnection()); + final HttpTransactionContext context = + getHttpTransactionContext(ctx.getConnection()); final AsyncHandler handler = context.handler; if (handler instanceof TransferCompletionHandler) { final int written = content.getContent().remaining(); @@ -1229,7 +1230,7 @@ protected void onInitialLineParsed(HttpHeader httpHeader, } final Connection connection = ctx.getConnection(); final HttpTransactionContext context = - provider.getHttpTransactionContext(connection); + getHttpTransactionContext(connection); final int status = ((HttpResponsePacket) httpHeader).getStatus(); if (context.establishingTunnel && HttpStatus.OK_200.statusMatches(status)) { return; @@ -1304,19 +1305,24 @@ protected void onInitialLineParsed(HttpHeader httpHeader, } - @Override protected void onHttpHeaderError(final HttpHeader httpHeader, final FilterChainContext ctx, final Throwable t) throws IOException { - t.printStackTrace(); httpHeader.setSkipRemainder(true); - final HttpTransactionContext context = - provider.getHttpTransactionContext(ctx.getConnection()); - context.abort(t); + getHttpTransactionContext(ctx.getConnection()).abort(t); } + @Override + protected void onHttpContentError(final HttpHeader httpHeader, + final FilterChainContext ctx, + final Throwable t) throws IOException { + + httpHeader.setSkipRemainder(true); + getHttpTransactionContext(ctx.getConnection()).abort(t); + } + @SuppressWarnings({"unchecked"}) @Override protected void onHttpHeadersParsed(HttpHeader httpHeader, @@ -1325,7 +1331,7 @@ protected void onHttpHeadersParsed(HttpHeader httpHeader, super.onHttpHeadersParsed(httpHeader, ctx); LOGGER.debug("RESPONSE: {}", httpHeader); final HttpTransactionContext context = - provider.getHttpTransactionContext(ctx.getConnection()); + getHttpTransactionContext(ctx.getConnection()); if (httpHeader.containsHeader(Header.Connection)) { if ("close".equals(httpHeader.getHeader(Header.Connection))) { @@ -1450,7 +1456,8 @@ protected boolean onHttpPacketParsed(HttpHeader httpHeader, FilterChainContext c result = super.onHttpPacketParsed(httpHeader, ctx); - final HttpTransactionContext context = provider.getHttpTransactionContext(ctx.getConnection()); + final HttpTransactionContext context = + getHttpTransactionContext(ctx.getConnection()); if (context.establishingTunnel && HttpStatus.OK_200.statusMatches( ((HttpResponsePacket) httpHeader).getStatus())) { @@ -1513,9 +1520,8 @@ private static HttpTransactionContext cleanup(final FilterChainContext ctx, final GrizzlyAsyncHttpProvider provider) { final Connection c = ctx.getConnection(); - final HttpTransactionContext context = - provider.getHttpTransactionContext(c); - context.provider.setHttpTransactionContext(c, null); + final HttpTransactionContext context = getHttpTransactionContext(c); + setHttpTransactionContext(c, null); if (!context.provider.connectionManager.canReturnConnection(c)) { context.abort(new IOException("Maximum pooled connections exceeded")); } else { From d61fe944259fe6593f1ee24d9642750c0231fd0b Mon Sep 17 00:00:00 2001 From: oleksiys Date: Tue, 20 May 2014 22:28:06 -0700 Subject: [PATCH 293/701] [1.8.x] + fix the issue #559 https://github.com/AsyncHttpClient/async-http-client/issues/559 GrizzlyAsyncHttpProvider hangs on Exception #559 --- .../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 c8b1e6cdf5..e023f35908 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 @@ -367,7 +367,7 @@ public void onThrowable(Throwable t) { assertNull(errors[i]); assertEquals(tempFile.length(), totalsReceived[i]); } - } + } private static SSLEngineConfigurator createSSLConfig() throws Exception { From ae4f46d051a14fa96f21f19c30efde93e4685028 Mon Sep 17 00:00:00 2001 From: oleksiys Date: Thu, 22 May 2014 17:50:38 -0700 Subject: [PATCH 294/701] [1.8.x] + refactored the code to look more like [master] --- .../grizzly/FeedableBodyGenerator.java | 27 +-- .../grizzly/GrizzlyAsyncHttpProvider.java | 190 +++++++++--------- 2 files changed, 99 insertions(+), 118 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 ef7e764e21..57e20bf5aa 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,6 +14,7 @@ import com.ning.http.client.Body; import com.ning.http.client.BodyGenerator; +import com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProvider.HttpTransactionContext; import java.io.IOException; import java.nio.ByteBuffer; @@ -34,7 +35,6 @@ import org.glassfish.grizzly.threadpool.Threads; 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; @@ -181,10 +181,7 @@ public void run() { feeder.flush(); } } catch (IOException ioe) { - GrizzlyAsyncHttpProvider.HttpTransactionContext ctx = - GrizzlyAsyncHttpProvider.getHttpTransactionContext( - c); - ctx.abort(ioe); + HttpTransactionContext.get(c).abort(ioe); } } }; @@ -224,9 +221,7 @@ public void onComplete(Connection connection) { try { feeder.flush(); } catch (IOException ioe) { - GrizzlyAsyncHttpProvider.HttpTransactionContext ctx = - GrizzlyAsyncHttpProvider.getHttpTransactionContext(c); - ctx.abort(ioe); + HttpTransactionContext.get(c).abort(ioe); } } } @@ -385,13 +380,9 @@ private static void block(final Connection c, future.get(); } } catch (ExecutionException e) { - GrizzlyAsyncHttpProvider.HttpTransactionContext httpCtx = - getHttpTransactionContext(c); - httpCtx.abort(e.getCause()); + HttpTransactionContext.get(c).abort(e.getCause()); } catch (Exception e) { - GrizzlyAsyncHttpProvider.HttpTransactionContext httpCtx = - getHttpTransactionContext(c); - httpCtx.abort(e); + HttpTransactionContext.get(c).abort(e); } } @@ -600,9 +591,7 @@ public void onWritePossible() throws Exception { @Override public void onError(Throwable t) { c.setMaxAsyncWriteQueueSize(feedableBodyGenerator.origMaxPendingBytes); - GrizzlyAsyncHttpProvider.HttpTransactionContext ctx = - GrizzlyAsyncHttpProvider.getHttpTransactionContext(c); - ctx.abort(t); + HttpTransactionContext.get(c).abort(t); } } // END WriteHandlerImpl @@ -622,9 +611,7 @@ public void ready() { } catch (IOException e) { final Connection c = feedableBodyGenerator.context.getConnection(); c.setMaxAsyncWriteQueueSize(feedableBodyGenerator.origMaxPendingBytes); - GrizzlyAsyncHttpProvider.HttpTransactionContext ctx = - GrizzlyAsyncHttpProvider.getHttpTransactionContext(c); - ctx.abort(e); + HttpTransactionContext.get(c).abort(e); } } 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 3a8227e2fa..0a3d866131 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 @@ -19,7 +19,6 @@ import static com.ning.http.util.MiscUtil.isNonEmpty; import java.io.ByteArrayOutputStream; -import java.io.EOFException; import java.io.File; import java.io.FileInputStream; import java.io.IOException; @@ -55,7 +54,6 @@ 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; import org.glassfish.grizzly.filterchain.FilterChain; import org.glassfish.grizzly.filterchain.FilterChainBuilder; @@ -149,6 +147,9 @@ import com.ning.http.util.AuthenticatorUtils; import com.ning.http.util.ProxyUtils; import com.ning.http.util.SslUtils; +import org.glassfish.grizzly.CloseListener; +import org.glassfish.grizzly.CloseType; +import org.glassfish.grizzly.Closeable; /** * A Grizzly 2.0-based implementation of {@link AsyncHttpProvider}. @@ -167,6 +168,12 @@ public class GrizzlyAsyncHttpProvider implements AsyncHttpProvider { Grizzly.DEFAULT_ATTRIBUTE_BUILDER.createAttribute(HttpTransactionContext.class.getName()); private final static NTLMEngine ntlmEngine = new NTLMEngine(); + public static final IOException REMOTELY_CLOSED_EXCEPTION = new IOException("Remotely Closed"); + + static { + REMOTELY_CLOSED_EXCEPTION.setStackTrace(new StackTraceElement[] {}); + } + private final BodyHandlerFactory bodyHandlerFactory = new BodyHandlerFactory(); private final TCPNIOTransport clientTransport; @@ -228,7 +235,7 @@ public void failed(final Throwable throwable) { @Override public void completed(final Connection c) { try { - execute(c, request, handler, future); + execute(c, request, handler, future, true); } catch (Exception e) { if (e instanceof RuntimeException) { failed(e); @@ -303,13 +310,14 @@ public Response prepareResponse(HttpResponseStatus status, protected ListenableFuture execute(final Connection c, final Request request, final AsyncHandler handler, - final GrizzlyResponseFuture future) + final GrizzlyResponseFuture future, + final boolean forceTxContextExist) throws IOException { try { - if (getHttpTransactionContext(c) == null) { - setHttpTransactionContext(c, - new HttpTransactionContext(future, request, handler)); + if (forceTxContextExist && HttpTransactionContext.get(c) == null) { + HttpTransactionContext.set(c, + new HttpTransactionContext(this, future, request, handler)); } c.write(request, createWriteCompletionHandler(future)); } catch (Exception e) { @@ -330,7 +338,7 @@ protected ListenableFuture execute(final Connection c, protected void initializeTransport(final AsyncHttpClientConfig clientConfig) { final FilterChainBuilder fcb = FilterChainBuilder.stateless(); - fcb.add(new AsyncHttpClientTransportFilter()); + fcb.add(new TransportFilter()); final int timeout = clientConfig.getRequestTimeoutInMs(); if (timeout > 0) { @@ -345,7 +353,7 @@ protected void initializeTransport(final AsyncHttpClientConfig clientConfig) { @Override public long getTimeout(FilterChainContext ctx) { final HttpTransactionContext context = - GrizzlyAsyncHttpProvider.this.getHttpTransactionContext(ctx.getConnection()); + HttpTransactionContext.get(ctx.getConnection()); if (context != null) { if (context.isWSRequest) { return clientConfig.getWebSocketIdleTimeoutInMs(); @@ -510,28 +518,9 @@ public void updated(WriteResult result) { } - static void setHttpTransactionContext(final AttributeStorage storage, - final HttpTransactionContext httpTransactionState) { - - if (httpTransactionState == null) { - REQUEST_STATE_ATTR.remove(storage); - } else { - REQUEST_STATE_ATTR.set(storage, httpTransactionState); - } - - } - - static HttpTransactionContext getHttpTransactionContext(final AttributeStorage storage) { - - return REQUEST_STATE_ATTR.get(storage); - - } - - void timeout(final Connection c) { - final HttpTransactionContext context = getHttpTransactionContext(c); - setHttpTransactionContext(c, null); + final HttpTransactionContext context = HttpTransactionContext.remove(c); context.abort(new TimeoutException("Timeout exceeded")); } @@ -561,7 +550,7 @@ boolean sendRequest(final FilterChainContext ctx, boolean isWriteComplete = true; if (requestHasEntityBody(request)) { - final HttpTransactionContext context = getHttpTransactionContext(ctx.getConnection()); + final HttpTransactionContext context = HttpTransactionContext.get(ctx.getConnection()); BodyHandler handler = bodyHandlerFactory.getBodyHandler(request); if (requestPacket.getHeaders().contains(Header.Expect) && requestPacket.getHeaders().getValue(1).equalsIgnoreCase("100-Continue")) { @@ -614,14 +603,13 @@ boolean handleStatus(final HttpResponsePacket httpResponse, } // END StatusHandler - final class HttpTransactionContext { + static final class HttpTransactionContext { final AtomicInteger redirectCount = new AtomicInteger(0); final int maxRedirectCount; final boolean redirectsAllowed; - final GrizzlyAsyncHttpProvider provider = - GrizzlyAsyncHttpProvider.this; + final GrizzlyAsyncHttpProvider provider; Request request; String requestUrl; @@ -642,15 +630,53 @@ final class HttpTransactionContext { ProtocolHandler protocolHandler; WebSocket webSocket; boolean establishingTunnel; + + private final CloseListener listener = new CloseListener() { + @Override + public void onClosed(Closeable closeable, CloseType type) throws IOException { + if (isGracefullyFinishResponseOnClose()) { + // Connection was closed. + // This event is fired only for responses, which don't have + // associated transfer-encoding or content-length. + // We have to complete such a request-response processing gracefully. + final Connection c = responseStatus.getResponse() + .getRequest().getConnection(); + final FilterChain fc = (FilterChain) c.getProcessor(); + + fc.fireEventUpstream(c, + new GracefulCloseEvent(HttpTransactionContext.this), null); + } else if (CloseType.REMOTELY.equals(type)) { + abort(REMOTELY_CLOSED_EXCEPTION); + } + } + }; + + // -------------------------------------------------------- Static methods + + static void set(final Connection c, final HttpTransactionContext httpTxContext) { + c.addCloseListener(httpTxContext.listener); + REQUEST_STATE_ATTR.set(c, httpTxContext); + } + static HttpTransactionContext remove(final Connection c) { + final HttpTransactionContext httpTxContext = REQUEST_STATE_ATTR.remove(c); + c.removeCloseListener(httpTxContext.listener); + return httpTxContext; + } + static HttpTransactionContext get(final Connection c) { + return REQUEST_STATE_ATTR.get(c); + } + // -------------------------------------------------------- Constructors - HttpTransactionContext(final GrizzlyResponseFuture future, + HttpTransactionContext(final GrizzlyAsyncHttpProvider provider, + final GrizzlyResponseFuture future, final Request request, final AsyncHandler handler) { + this.provider = provider; this.future = future; this.request = request; this.handler = handler; @@ -666,7 +692,8 @@ final class HttpTransactionContext { HttpTransactionContext copy() { final HttpTransactionContext newContext = - new HttpTransactionContext(future, + new HttpTransactionContext(provider, + future, request, handler); newContext.invocationStatus = invocationStatus; @@ -768,45 +795,7 @@ public Object type() { return GracefulCloseEvent.class; } } // END GracefulCloseEvent - - private final class AsyncHttpClientTransportFilter extends TransportFilter { - @Override - public NextAction handleRead(FilterChainContext ctx) throws IOException { - final HttpTransactionContext context = getHttpTransactionContext(ctx.getConnection()); - if (context == null) { - return super.handleRead(ctx); - } - - IOException error = null; - NextAction nextAction = null; - - try { - nextAction = super.handleRead(ctx); - ctx.getConnection().assertOpen(); - } catch (IOException e) { - error = e instanceof EOFException ? - new IOException("Remotely Closed") : - e; - } - - if (error != null) { - if (context.isGracefullyFinishResponseOnClose()) { - ctx.notifyUpstream(new GracefulCloseEvent(context)); - } else { - context.abort(error); - } - - throw error; - } - - assert nextAction != null; - - return nextAction; - } - - } // END AsyncHttpClientTransportFilter - - + private final class AsyncHttpClientFilter extends BaseFilter { @@ -864,8 +853,10 @@ public NextAction handleEvent(final FilterChainContext ctx, private boolean sendAsGrizzlyRequest(final Request request, final FilterChainContext ctx) throws IOException { - - final HttpTransactionContext httpCtx = getHttpTransactionContext(ctx.getConnection()); + + final Connection connection = ctx.getConnection(); + + final HttpTransactionContext httpCtx = HttpTransactionContext.get(connection); if (isUpgradeRequest(httpCtx.handler) && isWSRequest(httpCtx.requestUrl)) { httpCtx.isWSRequest = true; convertToUpgradeRequest(httpCtx); @@ -889,7 +880,7 @@ private boolean sendAsGrizzlyRequest(final Request request, final ProxyServer proxy = ProxyUtils.getProxyServer(config, request); final boolean useProxy = proxy != null; if (useProxy) { - if ((secure || httpCtx.isWSRequest) && !httpCtx.isTunnelEstablished(ctx.getConnection())) { + if ((secure || httpCtx.isWSRequest) && !httpCtx.isTunnelEstablished(connection)) { secure = false; httpCtx.establishingTunnel = true; builder.method(Method.CONNECT); @@ -929,7 +920,7 @@ private boolean sendAsGrizzlyRequest(final Request request, } requestPacket.setSecure(secure); - ctx.notifyDownstream(new SwitchingSSLFilter.SSLSwitchingEvent(secure, ctx.getConnection())); + ctx.notifyDownstream(new SwitchingSSLFilter.SSLSwitchingEvent(secure, connection)); if (!useProxy && !httpCtx.isWSRequest) { requestPacket.setQueryString(uri.getRawQuery()); @@ -955,6 +946,7 @@ private boolean sendAsGrizzlyRequest(final Request request, new FluentCaseInsensitiveStringsMap(request.getHeaders()); TransferCompletionHandler.class.cast(h).transferAdapter(new GrizzlyTransferAdapter(map)); } + requestPacket.setConnection(connection); return sendRequest(ctx, request, requestPacket); } @@ -1166,7 +1158,7 @@ public NextAction handleEvent(final FilterChainContext ctx, @Override public void exceptionOccurred(FilterChainContext ctx, Throwable error) { - getHttpTransactionContext(ctx.getConnection()).abort(error); + HttpTransactionContext.get(ctx.getConnection()).abort(error); } @@ -1176,7 +1168,7 @@ protected void onHttpContentParsed(HttpContent content, FilterChainContext ctx) { final HttpTransactionContext context = - getHttpTransactionContext(ctx.getConnection()); + HttpTransactionContext.get(ctx.getConnection()); final AsyncHandler handler = context.handler; if (handler != null && context.currentState != AsyncHandler.STATE.ABORT) { try { @@ -1195,7 +1187,7 @@ protected void onHttpContentParsed(HttpContent content, @Override protected void onHttpHeadersEncoded(HttpHeader httpHeader, FilterChainContext ctx) { final HttpTransactionContext context = - getHttpTransactionContext(ctx.getConnection()); + HttpTransactionContext.get(ctx.getConnection()); final AsyncHandler handler = context.handler; if (handler instanceof TransferCompletionHandler) { ((TransferCompletionHandler) handler).onHeaderWriteCompleted(); @@ -1208,7 +1200,7 @@ protected void onHttpHeadersEncoded(HttpHeader httpHeader, FilterChainContext ct @Override protected void onHttpContentEncoded(HttpContent content, FilterChainContext ctx) { final HttpTransactionContext context = - getHttpTransactionContext(ctx.getConnection()); + HttpTransactionContext.get(ctx.getConnection()); final AsyncHandler handler = context.handler; if (handler instanceof TransferCompletionHandler) { final int written = content.getContent().remaining(); @@ -1228,9 +1220,8 @@ protected void onInitialLineParsed(HttpHeader httpHeader, if (httpHeader.isSkipRemainder()) { return; } - final Connection connection = ctx.getConnection(); final HttpTransactionContext context = - getHttpTransactionContext(connection); + HttpTransactionContext.get(ctx.getConnection()); final int status = ((HttpResponsePacket) httpHeader).getStatus(); if (context.establishingTunnel && HttpStatus.OK_200.statusMatches(status)) { return; @@ -1311,7 +1302,7 @@ protected void onHttpHeaderError(final HttpHeader httpHeader, final Throwable t) throws IOException { httpHeader.setSkipRemainder(true); - getHttpTransactionContext(ctx.getConnection()).abort(t); + HttpTransactionContext.get(ctx.getConnection()).abort(t); } @Override @@ -1320,7 +1311,7 @@ protected void onHttpContentError(final HttpHeader httpHeader, final Throwable t) throws IOException { httpHeader.setSkipRemainder(true); - getHttpTransactionContext(ctx.getConnection()).abort(t); + HttpTransactionContext.get(ctx.getConnection()).abort(t); } @SuppressWarnings({"unchecked"}) @@ -1331,7 +1322,7 @@ protected void onHttpHeadersParsed(HttpHeader httpHeader, super.onHttpHeadersParsed(httpHeader, ctx); LOGGER.debug("RESPONSE: {}", httpHeader); final HttpTransactionContext context = - getHttpTransactionContext(ctx.getConnection()); + HttpTransactionContext.get(ctx.getConnection()); if (httpHeader.containsHeader(Header.Connection)) { if ("close".equals(httpHeader.getHeader(Header.Connection))) { @@ -1372,12 +1363,13 @@ protected void onHttpHeadersParsed(HttpHeader httpHeader, final HttpTransactionContext newContext = context.copy(); context.future = null; - provider.setHttpTransactionContext(c, newContext); + HttpTransactionContext.set(c, newContext); try { context.provider.execute(c, newRequest, newHandler, - context.future); + context.future, + false); } catch (IOException ioe) { newContext.abort(ioe); } @@ -1457,7 +1449,7 @@ protected boolean onHttpPacketParsed(HttpHeader httpHeader, FilterChainContext c result = super.onHttpPacketParsed(httpHeader, ctx); final HttpTransactionContext context = - getHttpTransactionContext(ctx.getConnection()); + HttpTransactionContext.get(ctx.getConnection()); if (context.establishingTunnel && HttpStatus.OK_200.statusMatches( ((HttpResponsePacket) httpHeader).getStatus())) { @@ -1468,7 +1460,8 @@ protected boolean onHttpPacketParsed(HttpHeader httpHeader, FilterChainContext c context.provider.execute(c, context.request, context.handler, - context.future); + context.future, + false); return result; } catch (IOException e) { context.abort(e); @@ -1520,8 +1513,7 @@ private static HttpTransactionContext cleanup(final FilterChainContext ctx, final GrizzlyAsyncHttpProvider provider) { final Connection c = ctx.getConnection(); - final HttpTransactionContext context = getHttpTransactionContext(c); - setHttpTransactionContext(c, null); + final HttpTransactionContext context = HttpTransactionContext.remove(c); if (!context.provider.connectionManager.canReturnConnection(c)) { context.abort(new IOException("Maximum pooled connections exceeded")); } else { @@ -1631,13 +1623,14 @@ public boolean handleStatus(final HttpResponsePacket responsePacket, final HttpTransactionContext newContext = httpTransactionContext.copy(); httpTransactionContext.future = null; - httpTransactionContext.provider.setHttpTransactionContext(c, newContext); + HttpTransactionContext.set(c, newContext); newContext.invocationStatus = InvocationStatus.STOP; try { httpTransactionContext.provider.execute(c, req, httpTransactionContext.handler, - httpTransactionContext.future); + httpTransactionContext.future, + false); return false; } catch (IOException ioe) { newContext.abort(ioe); @@ -1718,11 +1711,12 @@ public boolean handleStatus(final HttpResponsePacket responsePacket, newContext.invocationStatus = InvocationStatus.CONTINUE; newContext.request = requestToSend; newContext.requestUrl = requestToSend.getUrl(); - httpTransactionContext.provider.setHttpTransactionContext(c, newContext); + HttpTransactionContext.set(c, newContext); httpTransactionContext.provider.execute(c, requestToSend, newContext.handler, - newContext.future); + newContext.future, + false); return false; } catch (Exception e) { httpTransactionContext.abort(e); @@ -2251,7 +2245,7 @@ public boolean doHandle(final FilterChainContext ctx, final File f = request.getFile(); requestPacket.setContentLengthLong(f.length()); - final HttpTransactionContext context = getHttpTransactionContext(ctx.getConnection()); + final HttpTransactionContext context = HttpTransactionContext.get(ctx.getConnection()); if (!SEND_FILE_SUPPORT || requestPacket.isSecure()) { final FileInputStream fis = new FileInputStream(request.getFile()); final MemoryManager mm = ctx.getMemoryManager(); From 9ff18727f172a4b1958bc85677954d301b94c1a0 Mon Sep 17 00:00:00 2001 From: oleksiys Date: Thu, 22 May 2014 17:50:38 -0700 Subject: [PATCH 295/701] [1.8.x] + refactored the code to look more like [master] --- .../client/providers/grizzly/GrizzlyAsyncHttpProvider.java | 3 ++- 1 file changed, 2 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 0a3d866131..0eb7041e6e 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 @@ -634,7 +634,8 @@ static final class HttpTransactionContext { private final CloseListener listener = new CloseListener() { @Override public void onClosed(Closeable closeable, CloseType type) throws IOException { - if (isGracefullyFinishResponseOnClose()) { + if (responseStatus != null && // responseStatus==null if request wasn't even sent + isGracefullyFinishResponseOnClose()) { // Connection was closed. // This event is fired only for responses, which don't have // associated transfer-encoding or content-length. From 56b7eebe1f96d311ae081a1edc9a8d4ca0edcd81 Mon Sep 17 00:00:00 2001 From: oleksiys Date: Tue, 27 May 2014 13:10:41 -0700 Subject: [PATCH 296/701] [1.8.x] + integrate Grizzly 2.3.13 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 195daaae76..702ecb1f16 100644 --- a/pom.xml +++ b/pom.xml @@ -591,7 +591,7 @@ com/ning/http/client/providers/grizzly/*.java com/ning/http/client/async/grizzly/*.java com.ning.http.client.providers.grizzly - 2.3.12 + 2.3.13 1.5 1.5 2.12 From a352b02f9c4a301f278c320f338a507d0dfbbe16 Mon Sep 17 00:00:00 2001 From: artnaseef Date: Mon, 2 Jun 2014 16:44:46 -0700 Subject: [PATCH 297/701] Support NTLM protocol with the proxy: fixed the header name for Proxy-Authorization. --- .../netty/NettyAsyncHttpProvider.java | 36 +++++++++++-------- 1 file changed, 22 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 813681e4f3..ad1f9ea1de 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 @@ -1229,7 +1229,7 @@ public void messageReceived(final ChannelHandlerContext ctx, MessageEvent e) thr } private Realm kerberosChallenge(List proxyAuth, Request request, ProxyServer proxyServer, FluentCaseInsensitiveStringsMap headers, Realm realm, - NettyResponseFuture future) throws NTLMEngineException { + NettyResponseFuture future, boolean proxyInd) throws NTLMEngineException { URI uri = request.getURI(); String host = request.getVirtualHost() == null ? AsyncHttpProviderUtils.getHost(uri) : request.getVirtualHost(); @@ -1248,30 +1248,38 @@ 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 (isNTLM(proxyAuth)) { - return ntlmChallenge(proxyAuth, request, proxyServer, headers, realm, future); + return ntlmChallenge(proxyAuth, request, proxyServer, headers, realm, future, proxyInd); } abort(future, throwable); return null; } } - private void addNTLMAuthorization(FluentCaseInsensitiveStringsMap headers, String challengeHeader) { - headers.add(HttpHeaders.Names.AUTHORIZATION, "NTLM " + challengeHeader); + private void addNTLMAuthorization(FluentCaseInsensitiveStringsMap headers, String challengeHeader, boolean proxyInd) { + if ( proxyInd ) { + headers.add(HttpHeaders.Names.PROXY_AUTHORIZATION, "NTLM " + challengeHeader); + } else { + headers.add(HttpHeaders.Names.AUTHORIZATION, "NTLM " + challengeHeader); + } } - private void addType3NTLMAuthorizationHeader(List auth, FluentCaseInsensitiveStringsMap headers, String username, String password, String domain, String workstation) + private void addType3NTLMAuthorizationHeader(List auth, FluentCaseInsensitiveStringsMap headers, String username, String password, String domain, String workstation, boolean proxyInd) throws NTLMEngineException { - headers.remove(HttpHeaders.Names.AUTHORIZATION); + if ( proxyInd ) { + headers.remove(HttpHeaders.Names.PROXY_AUTHORIZATION); + } else { + headers.remove(HttpHeaders.Names.AUTHORIZATION); + } // Beware of space!, see #462 if (isNonEmpty(auth) && auth.get(0).startsWith("NTLM ")) { String serverChallenge = auth.get(0).trim().substring("NTLM ".length()); String challengeHeader = ntlmEngine.generateType3Msg(username, password, domain, workstation, serverChallenge); - addNTLMAuthorization(headers, challengeHeader); + addNTLMAuthorization(headers, challengeHeader, proxyInd); } } - private Realm ntlmChallenge(List wwwAuth, Request request, ProxyServer proxyServer, FluentCaseInsensitiveStringsMap headers, Realm realm, NettyResponseFuture future) + private Realm ntlmChallenge(List wwwAuth, Request request, ProxyServer proxyServer, FluentCaseInsensitiveStringsMap headers, Realm realm, NettyResponseFuture future, boolean proxyInd) throws NTLMEngineException { boolean useRealm = (proxyServer == null && realm != null); @@ -1286,12 +1294,12 @@ private Realm ntlmChallenge(List wwwAuth, Request request, ProxyServer p String challengeHeader = ntlmEngine.generateType1Msg(ntlmDomain, ntlmHost); URI uri = request.getURI(); - addNTLMAuthorization(headers, challengeHeader); + addNTLMAuthorization(headers, challengeHeader, proxyInd); 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, proxyInd); Realm.RealmBuilder realmBuilder; Realm.AuthScheme authScheme; @@ -1312,7 +1320,7 @@ private Realm ntlmProxyChallenge(List wwwAuth, Request request, ProxySer NettyResponseFuture future) throws NTLMEngineException { future.getAndSetAuth(false); - addType3NTLMAuthorizationHeader(wwwAuth, headers, proxyServer.getPrincipal(), proxyServer.getPassword(), proxyServer.getNtlmDomain(), proxyServer.getHost()); + addType3NTLMAuthorizationHeader(wwwAuth, headers, proxyServer.getPrincipal(), proxyServer.getPassword(), proxyServer.getNtlmDomain(), proxyServer.getHost(), true); Realm newRealm; Realm.RealmBuilder realmBuilder = new Realm.RealmBuilder(); @@ -2115,10 +2123,10 @@ public void handle(final ChannelHandlerContext ctx, final MessageEvent e) throws // NTLM if (!wwwAuth.contains("Kerberos") && (isNTLM(wwwAuth) || (wwwAuth.contains("Negotiate")))) { - newRealm = ntlmChallenge(wwwAuth, request, proxyServer, headers, realm, future); + newRealm = ntlmChallenge(wwwAuth, request, proxyServer, headers, realm, future, false); // SPNEGO KERBEROS } else if (wwwAuth.contains("Negotiate")) { - newRealm = kerberosChallenge(wwwAuth, request, proxyServer, headers, realm, future); + newRealm = kerberosChallenge(wwwAuth, request, proxyServer, headers, realm, future, false); if (newRealm == null) return; } else { @@ -2167,7 +2175,7 @@ public Object call() throws Exception { newRealm = ntlmProxyChallenge(proxyAuth, request, proxyServer, headers, realm, future); // SPNEGO KERBEROS } else if (proxyAuth.contains("Negotiate")) { - newRealm = kerberosChallenge(proxyAuth, request, proxyServer, headers, realm, future); + newRealm = kerberosChallenge(proxyAuth, request, proxyServer, headers, realm, future, true); if (newRealm == null) return; } else { From 7dbeb65cc05cb989df3e76c0bd31c80ffe85d8fa Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 3 Jun 2014 10:50:59 +0200 Subject: [PATCH 298/701] Minor clean up --- .../providers/netty/NettyAsyncHttpProvider.java | 16 ++++++---------- 1 file changed, 6 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 ad1f9ea1de..fb75198aa5 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 @@ -1255,21 +1255,17 @@ private Realm kerberosChallenge(List proxyAuth, Request request, ProxySe } } + private String authorizationHeaderName(boolean proxyInd) { + return proxyInd? HttpHeaders.Names.PROXY_AUTHORIZATION: HttpHeaders.Names.AUTHORIZATION; + } + private void addNTLMAuthorization(FluentCaseInsensitiveStringsMap headers, String challengeHeader, boolean proxyInd) { - if ( proxyInd ) { - headers.add(HttpHeaders.Names.PROXY_AUTHORIZATION, "NTLM " + challengeHeader); - } else { - headers.add(HttpHeaders.Names.AUTHORIZATION, "NTLM " + challengeHeader); - } + headers.add(authorizationHeaderName(proxyInd), "NTLM " + challengeHeader); } private void addType3NTLMAuthorizationHeader(List auth, FluentCaseInsensitiveStringsMap headers, String username, String password, String domain, String workstation, boolean proxyInd) throws NTLMEngineException { - if ( proxyInd ) { - headers.remove(HttpHeaders.Names.PROXY_AUTHORIZATION); - } else { - headers.remove(HttpHeaders.Names.AUTHORIZATION); - } + headers.remove(authorizationHeaderName(proxyInd)); // Beware of space!, see #462 if (isNonEmpty(auth) && auth.get(0).startsWith("NTLM ")) { From 37cfab461a42d7371f8ebb086ebef838606a442e Mon Sep 17 00:00:00 2001 From: oleksiys Date: Tue, 3 Jun 2014 12:37:45 -0700 Subject: [PATCH 299/701] [1.8.x] fix issue #564 https://github.com/AsyncHttpClient/async-http-client/issues/564 "emtpy HTTP delete message is sent using chunked transfer-encoding for no reason" --- .../grizzly/GrizzlyAsyncHttpProvider.java | 117 ++++++++++-------- 1 file changed, 68 insertions(+), 49 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 0eb7041e6e..99a95f6ab9 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 @@ -544,23 +544,20 @@ static int getPort(final URI uri, final int p) { @SuppressWarnings({"unchecked"}) boolean sendRequest(final FilterChainContext ctx, final Request request, - final HttpRequestPacket requestPacket) + final HttpRequestPacket requestPacket, + final BodyHandler bodyHandler) throws IOException { boolean isWriteComplete = true; - if (requestHasEntityBody(request)) { + if (bodyHandler != null) { // Check if the HTTP request has body final HttpTransactionContext context = HttpTransactionContext.get(ctx.getConnection()); - BodyHandler handler = bodyHandlerFactory.getBodyHandler(request); - if (requestPacket.getHeaders().contains(Header.Expect) - && requestPacket.getHeaders().getValue(1).equalsIgnoreCase("100-Continue")) { - handler = new ExpectHandler(handler); - } - context.bodyHandler = handler; + + context.bodyHandler = bodyHandler; if (LOGGER.isDebugEnabled()) { LOGGER.debug("REQUEST: " + requestPacket.toString()); } - isWriteComplete = handler.doHandle(ctx, request, requestPacket); + isWriteComplete = bodyHandler.doHandle(ctx, request, requestPacket); } else { if (LOGGER.isDebugEnabled()) { LOGGER.debug("REQUEST: " + requestPacket.toString()); @@ -572,18 +569,6 @@ boolean sendRequest(final FilterChainContext ctx, return isWriteComplete; } - - private static boolean requestHasEntityBody(final Request request) { - - final String method = request.getMethod(); - return (Method.POST.matchesMethod(method) - || Method.PUT.matchesMethod(method) - || Method.PATCH.matchesMethod(method) - || Method.DELETE.matchesMethod(method)); - - } - - // ----------------------------------------------------------- Inner Classes @@ -864,9 +849,10 @@ private boolean sendAsGrizzlyRequest(final Request request, } final Request req = httpCtx.request; final URI uri = req.isUseRawUrl() ? req.getRawURI() : req.getURI(); + final Method method = Method.valueOf(request.getMethod()); final HttpRequestPacket.Builder builder = HttpRequestPacket.builder(); boolean secure = "https".equals(uri.getScheme()); - builder.method(request.getMethod()); + builder.method(method); builder.protocol(Protocol.HTTP_1_1); String host = request.getVirtualHost(); if (host != null) { @@ -894,7 +880,12 @@ private boolean sendAsGrizzlyRequest(final Request request, } else { builder.uri(uri.getPath()); } - if (requestHasEntityBody(request)) { + + final BodyHandler bodyHandler = isPayloadAllowed(method) ? + bodyHandlerFactory.getBodyHandler(request) : + null; + + if (bodyHandler != null) { final long contentLength = request.getContentLength(); if (contentLength >= 0) { builder.contentLength(contentLength); @@ -903,7 +894,7 @@ private boolean sendAsGrizzlyRequest(final Request request, builder.chunked(true); } } - + HttpRequestPacket requestPacket; if (httpCtx.isWSRequest && !httpCtx.establishingTunnel) { try { @@ -947,11 +938,38 @@ private boolean sendAsGrizzlyRequest(final Request request, new FluentCaseInsensitiveStringsMap(request.getHeaders()); TransferCompletionHandler.class.cast(h).transferAdapter(new GrizzlyTransferAdapter(map)); } + requestPacket.setConnection(connection); - return sendRequest(ctx, request, requestPacket); + return sendRequest(ctx, request, requestPacket, + wrapWithExpectHandlerIfNeeded(bodyHandler, requestPacket)); } + /** + * check if we need to wrap the BodyHandler with ExpectHandler + */ + private BodyHandler wrapWithExpectHandlerIfNeeded( + final BodyHandler bodyHandler, + final HttpRequestPacket requestPacket) { + + if (bodyHandler == null) { + return null; + } + + // check if we need to wrap the BodyHandler with ExpectHandler + final MimeHeaders headers = requestPacket.getHeaders(); + final int expectHeaderIdx = headers.indexOf(Header.Expect, 0); + + return expectHeaderIdx != -1 + && headers.getValue(expectHeaderIdx).equalsIgnoreCase("100-Continue") + ? new ExpectHandler(bodyHandler) + : bodyHandler; + } + + private boolean isPayloadAllowed(final Method method) { + return method.getPayloadExpectation() != Method.PayloadExpectation.NOT_ALLOWED; + } + private void addAuthorizationHeader(final Request request, final HttpRequestPacket requestPacket) { Realm realm = request.getRealm(); if (realm == null) { @@ -1873,7 +1891,8 @@ public BodyHandler getBodyHandler(final Request request) { return h; } } - return new NoBodyHandler(); + + return null; } } // END BodyHandlerFactory @@ -1985,29 +2004,29 @@ public boolean doHandle(final FilterChainContext ctx, } // END StringBodyHandler - private static final class NoBodyHandler implements BodyHandler { - - - // -------------------------------------------- Methods from BodyHandler - - - public boolean handlesBodyType(final Request request) { - return false; - } - - @SuppressWarnings({"unchecked"}) - public boolean doHandle(final FilterChainContext ctx, - final Request request, - final HttpRequestPacket requestPacket) - throws IOException { - - final HttpContent content = requestPacket.httpContentBuilder().content(Buffers.EMPTY_BUFFER).build(); - content.setLast(true); - ctx.write(content, ((!requestPacket.isCommitted()) ? ctx.getTransportContext().getCompletionHandler() : null)); - return true; - } - - } // END NoBodyHandler +// private static final class NoBodyHandler implements BodyHandler { +// +// +// // -------------------------------------------- Methods from BodyHandler +// +// +// public boolean handlesBodyType(final Request request) { +// return false; +// } +// +// @SuppressWarnings({"unchecked"}) +// public boolean doHandle(final FilterChainContext ctx, +// final Request request, +// final HttpRequestPacket requestPacket) +// throws IOException { +// +// final HttpContent content = requestPacket.httpContentBuilder().content(Buffers.EMPTY_BUFFER).build(); +// content.setLast(true); +// ctx.write(content, ((!requestPacket.isCommitted()) ? ctx.getTransportContext().getCompletionHandler() : null)); +// return true; +// } +// +// } // END NoBodyHandler private final class ParamsBodyHandler implements BodyHandler { From e92bc9ab36d1bb46a3d79268d5da6fa078aab868 Mon Sep 17 00:00:00 2001 From: oleksiys Date: Tue, 3 Jun 2014 21:53:06 -0700 Subject: [PATCH 300/701] [1.8.x] + if Expect 100-Continue is used - try to predict the content-length before sending the header --- .../grizzly/GrizzlyAsyncHttpProvider.java | 100 ++++++++++-------- 1 file changed, 58 insertions(+), 42 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 99a95f6ab9..9cd861b909 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 @@ -1858,17 +1858,28 @@ public void destroy() { } // END NonCachingPool + public static abstract class BodyHandler { - private static interface BodyHandler { + public static int MAX_CHUNK_SIZE = 8192; - static int MAX_CHUNK_SIZE = 8192; + public abstract boolean handlesBodyType(final Request request); - boolean handlesBodyType(final Request request); - - boolean doHandle(final FilterChainContext ctx, - final Request request, - final HttpRequestPacket requestPacket) throws IOException; + public abstract boolean doHandle(final FilterChainContext ctx, + final Request request, final HttpRequestPacket requestPacket) + throws IOException; + /** + * Tries to predict request content-length based on the {@link Request}. + * Not all the BodyHandlers can predict the content-length in + * advance. + * + * @param request + * @return the content-length, or -1 if the content-length + * can't be predicted + */ + protected long getContentLength(final Request request) { + return request.getContentLength(); + } } // END BodyHandler @@ -1898,7 +1909,7 @@ public BodyHandler getBodyHandler(final Request request) { } // END BodyHandlerFactory - private static final class ExpectHandler implements BodyHandler { + private static final class ExpectHandler extends BodyHandler { private final BodyHandler delegate; private Request request; @@ -1925,6 +1936,13 @@ public boolean handlesBodyType(Request request) { public boolean doHandle(FilterChainContext ctx, Request request, HttpRequestPacket requestPacket) throws IOException { this.request = request; this.requestPacket = requestPacket; + + // Set content-length if possible + final long contentLength = delegate.getContentLength(request); + if (contentLength != -1) { + requestPacket.setContentLengthLong(contentLength); + } + ctx.write(requestPacket, ((!requestPacket.isCommitted()) ? ctx.getTransportContext().getCompletionHandler() : null)); return true; } @@ -1936,7 +1954,7 @@ public void finish(final FilterChainContext ctx) throws IOException { } // END ContinueHandler - private final class ByteArrayBodyHandler implements BodyHandler { + private final class ByteArrayBodyHandler extends BodyHandler { // -------------------------------------------- Methods from BodyHandler @@ -1964,10 +1982,21 @@ public boolean doHandle(final FilterChainContext ctx, ctx.write(content, ((!requestPacket.isCommitted()) ? ctx.getTransportContext().getCompletionHandler() : null)); return true; } + + @Override + protected long getContentLength(final Request request) { + if (request.getContentLength() >= 0) { + return request.getContentLength(); + } + + return clientConfig.isCompressionEnabled() + ? -1 + : request.getByteData().length; + } } - private final class StringBodyHandler implements BodyHandler { + private final class StringBodyHandler extends BodyHandler { // -------------------------------------------- Methods from BodyHandler @@ -2004,32 +2033,7 @@ public boolean doHandle(final FilterChainContext ctx, } // END StringBodyHandler -// private static final class NoBodyHandler implements BodyHandler { -// -// -// // -------------------------------------------- Methods from BodyHandler -// -// -// public boolean handlesBodyType(final Request request) { -// return false; -// } -// -// @SuppressWarnings({"unchecked"}) -// public boolean doHandle(final FilterChainContext ctx, -// final Request request, -// final HttpRequestPacket requestPacket) -// throws IOException { -// -// final HttpContent content = requestPacket.httpContentBuilder().content(Buffers.EMPTY_BUFFER).build(); -// content.setLast(true); -// ctx.write(content, ((!requestPacket.isCommitted()) ? ctx.getTransportContext().getCompletionHandler() : null)); -// return true; -// } -// -// } // END NoBodyHandler - - - private final class ParamsBodyHandler implements BodyHandler { + private final class ParamsBodyHandler extends BodyHandler { // -------------------------------------------- Methods from BodyHandler @@ -2091,7 +2095,7 @@ public boolean doHandle(final FilterChainContext ctx, } // END ParamsBodyHandler - private static final class EntityWriterBodyHandler implements BodyHandler { + private static final class EntityWriterBodyHandler extends BodyHandler { // -------------------------------------------- Methods from BodyHandler @@ -2125,7 +2129,7 @@ public boolean doHandle(final FilterChainContext ctx, } // END EntityWriterBodyHandler - private static final class StreamDataBodyHandler implements BodyHandler { + private static final class StreamDataBodyHandler extends BodyHandler { // -------------------------------------------- Methods from BodyHandler @@ -2176,7 +2180,7 @@ public boolean doHandle(final FilterChainContext ctx, } // END StreamDataBodyHandler - private static final class PartsBodyHandler implements BodyHandler { + private static final class PartsBodyHandler extends BodyHandler { // -------------------------------------------- Methods from BodyHandler @@ -2248,7 +2252,7 @@ public void flush() throws IOException { } // END PartsBodyHandler - private final class FileBodyHandler implements BodyHandler { + private final class FileBodyHandler extends BodyHandler { // -------------------------------------------- Methods from BodyHandler @@ -2266,7 +2270,9 @@ public boolean doHandle(final FilterChainContext ctx, final File f = request.getFile(); requestPacket.setContentLengthLong(f.length()); final HttpTransactionContext context = HttpTransactionContext.get(ctx.getConnection()); - if (!SEND_FILE_SUPPORT || requestPacket.isSecure()) { + if (clientConfig.isCompressionEnabled() || !SEND_FILE_SUPPORT || + requestPacket.isSecure()) { + final FileInputStream fis = new FileInputStream(request.getFile()); final MemoryManager mm = ctx.getMemoryManager(); AtomicInteger written = new AtomicInteger(); @@ -2318,10 +2324,20 @@ public void updated(WriteResult result) { return true; } + @Override + protected long getContentLength(final Request request) { + if (request.getContentLength() >= 0) { + return request.getContentLength(); + } + + return clientConfig.isCompressionEnabled() + ? -1 + : request.getFile().length(); + } } // END FileBodyHandler - private static final class BodyGeneratorBodyHandler implements BodyHandler { + private static final class BodyGeneratorBodyHandler extends BodyHandler { // -------------------------------------------- Methods from BodyHandler From 9134f89fa45c69fc6dc8c671a82c86daa3e36352 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 4 Jun 2014 07:33:27 +0200 Subject: [PATCH 301/701] Have one central place for configuration defaults, close #565 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit My great grandchildren will still be cleaning up this library… --- .../http/client/AsyncHttpClientConfig.java | 136 +++++++++--------- .../client/AsyncHttpClientConfigBean.java | 63 ++++---- .../client/AsyncHttpClientConfigDefaults.java | 123 ++++++++++++++++ 3 files changed, 220 insertions(+), 102 deletions(-) create mode 100644 src/main/java/com/ning/http/client/AsyncHttpClientConfigDefaults.java diff --git a/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java b/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java index 700309d35f..4624bbf0c2 100644 --- a/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java @@ -15,13 +15,12 @@ */ package com.ning.http.client; -import static com.ning.http.util.MiscUtil.getBoolean; +import static com.ning.http.client.AsyncHttpClientConfigDefaults.*; import com.ning.http.client.date.TimeConverter; import com.ning.http.client.filter.IOExceptionFilter; import com.ning.http.client.filter.RequestFilter; import com.ning.http.client.filter.ResponseFilter; -import com.ning.http.util.AllowAllHostnameVerifier; import com.ning.http.util.ProxyUtils; import javax.net.ssl.HostnameVerifier; @@ -54,8 +53,6 @@ */ public class AsyncHttpClientConfig { - protected final static String ASYNC_CLIENT = AsyncHttpClientConfig.class.getName() + "."; - protected int maxTotalConnections; protected int maxConnectionPerHost; protected int connectionTimeOutInMs; @@ -64,7 +61,7 @@ public class AsyncHttpClientConfig { protected int idleConnectionTimeoutInMs; protected int requestTimeoutInMs; protected boolean redirectEnabled; - protected int maxDefaultRedirects; + protected int maxRedirects; protected boolean compressionEnabled; protected String userAgent; protected boolean allowPoolingConnection; @@ -102,7 +99,7 @@ private AsyncHttpClientConfig(int maxTotalConnections, int requestTimeoutInMs, int connectionMaxLifeTimeInMs, boolean redirectEnabled, - int maxDefaultRedirects, + int maxRedirects, boolean compressionEnabled, String userAgent, boolean keepAlive, @@ -135,7 +132,7 @@ private AsyncHttpClientConfig(int maxTotalConnections, this.requestTimeoutInMs = requestTimeoutInMs; this.maxConnectionLifeTimeInMs = connectionMaxLifeTimeInMs; this.redirectEnabled = redirectEnabled; - this.maxDefaultRedirects = maxDefaultRedirects; + this.maxRedirects = maxRedirects; this.compressionEnabled = compressionEnabled; this.userAgent = userAgent; this.allowPoolingConnection = keepAlive; @@ -245,7 +242,7 @@ public boolean isRedirectEnabled() { * @return the maximum number of HTTP redirect */ public int getMaxRedirects() { - return maxDefaultRedirects; + return maxRedirects; } /** @@ -526,22 +523,31 @@ public TimeConverter getTimeConverter() { * Builder for an {@link AsyncHttpClient} */ public static class Builder { - private int defaultMaxTotalConnections = Integer.getInteger(ASYNC_CLIENT + "defaultMaxTotalConnections", -1); - private int defaultMaxConnectionPerHost = Integer.getInteger(ASYNC_CLIENT + "defaultMaxConnectionsPerHost", -1); - private int defaultConnectionTimeOutInMs = Integer.getInteger(ASYNC_CLIENT + "defaultConnectionTimeoutInMS", 60 * 1000); - private int defaultWebsocketIdleTimeoutInMs = Integer.getInteger(ASYNC_CLIENT + "defaultWebsocketTimoutInMS", 15 * 60 * 1000); - 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"); - 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 = getBoolean(ASYNC_CLIENT + "useRelativeURIsWithSSLProxies", true); + private int maxTotalConnections = defaultMaxTotalConnections(); + private int maxConnectionPerHost = defaultMaxConnectionPerHost(); + private int connectionTimeOutInMs = defaultConnectionTimeOutInMs(); + private int webSocketIdleTimeoutInMs = defaultWebSocketIdleTimeoutInMs(); + private int idleConnectionInPoolTimeoutInMs = defaultIdleConnectionInPoolTimeoutInMs(); + private int idleConnectionTimeoutInMs = defaultIdleConnectionTimeoutInMs(); + private int requestTimeoutInMs = defaultRequestTimeoutInMs(); + private int maxConnectionLifeTimeInMs = defaultMaxConnectionLifeTimeInMs(); + private boolean redirectEnabled = defaultRedirectEnabled(); + private int maxDefaultRedirects = defaultMaxRedirects(); + private boolean compressionEnabled = defaultCompressionEnabled(); + private String userAgent = defaultUserAgent(); + private boolean useProxyProperties = defaultUseProxyProperties(); + private boolean useProxySelector = defaultUseProxySelector(); + private boolean allowPoolingConnection = defaultAllowPoolingConnection(); + private boolean useRelativeURIsWithSSLProxies = defaultUseRelativeURIsWithSSLProxies(); + private int requestCompressionLevel = defaultRequestCompressionLevel(); + private int maxRequestRetry = defaultMaxRequestRetry(); + private int ioThreadMultiplier = defaultIoThreadMultiplier(); + private boolean allowSslConnectionPool = defaultAllowSslConnectionPool(); + private boolean useRawUrl = defaultUseRawUrl(); + private boolean removeQueryParamOnRedirect = defaultRemoveQueryParamOnRedirect(); + private boolean strict302Handling = defaultStrict302Handling(); + private HostnameVerifier hostnameVerifier = defaultHostnameVerifier(); + private ExecutorService applicationThreadPool; private ProxyServerSelector proxyServerSelector = null; private SSLContext sslContext; @@ -549,17 +555,9 @@ public static class Builder { private AsyncHttpProviderConfig providerConfig; private ConnectionsPool connectionsPool; private Realm realm; - private int requestCompressionLevel = -1; - private int maxRequestRetry = 5; private final List requestFilters = new LinkedList(); private final List responseFilters = new LinkedList(); private final List ioExceptionFilters = new LinkedList(); - private boolean allowSslConnectionPool = true; - private boolean useRawUrl = false; - private boolean removeQueryParamOnRedirect = true; - private HostnameVerifier hostnameVerifier = new AllowAllHostnameVerifier(); - private int ioThreadMultiplier = 2; - private boolean strict302Handling; private TimeConverter timeConverter; public Builder() { @@ -568,57 +566,57 @@ public Builder() { /** * Set the maximum number of connections an {@link com.ning.http.client.AsyncHttpClient} can handle. * - * @param defaultMaxTotalConnections the maximum number of connections an {@link com.ning.http.client.AsyncHttpClient} can handle. + * @param maxTotalConnections the maximum number of connections an {@link com.ning.http.client.AsyncHttpClient} can handle. * @return a {@link Builder} */ - public Builder setMaximumConnectionsTotal(int defaultMaxTotalConnections) { - this.defaultMaxTotalConnections = defaultMaxTotalConnections; + public Builder setMaximumConnectionsTotal(int maxTotalConnections) { + this.maxTotalConnections = maxTotalConnections; return this; } /** * Set the maximum number of connections per hosts an {@link com.ning.http.client.AsyncHttpClient} can handle. * - * @param defaultMaxConnectionPerHost the maximum number of connections per host an {@link com.ning.http.client.AsyncHttpClient} can handle. + * @param maxConnectionPerHost the maximum number of connections per host an {@link com.ning.http.client.AsyncHttpClient} can handle. * @return a {@link Builder} */ - public Builder setMaximumConnectionsPerHost(int defaultMaxConnectionPerHost) { - this.defaultMaxConnectionPerHost = defaultMaxConnectionPerHost; + public Builder setMaximumConnectionsPerHost(int maxConnectionPerHost) { + this.maxConnectionPerHost = maxConnectionPerHost; return this; } /** * Set the maximum time in millisecond an {@link com.ning.http.client.AsyncHttpClient} can wait when connecting to a remote host * - * @param defaultConnectionTimeOutInMs the maximum time in millisecond an {@link com.ning.http.client.AsyncHttpClient} can wait when connecting to a remote host + * @param connectionTimeOutInMs the maximum time in millisecond an {@link com.ning.http.client.AsyncHttpClient} can wait when connecting to a remote host * @return a {@link Builder} */ - public Builder setConnectionTimeoutInMs(int defaultConnectionTimeOutInMs) { - this.defaultConnectionTimeOutInMs = defaultConnectionTimeOutInMs; + public Builder setConnectionTimeoutInMs(int connectionTimeOutInMs) { + this.connectionTimeOutInMs = connectionTimeOutInMs; return this; } /** * Set the maximum time in millisecond an {@link com.ning.http.client.websocket.WebSocket} can stay idle. * - * @param defaultWebSocketIdleTimeoutInMs + * @param webSocketIdleTimeoutInMs * the maximum time in millisecond an {@link com.ning.http.client.websocket.WebSocket} can stay idle. * @return a {@link Builder} */ - public Builder setWebSocketIdleTimeoutInMs(int defaultWebSocketIdleTimeoutInMs) { - this.defaultWebsocketIdleTimeoutInMs = defaultWebSocketIdleTimeoutInMs; + public Builder setWebSocketIdleTimeoutInMs(int webSocketIdleTimeoutInMs) { + this.webSocketIdleTimeoutInMs = webSocketIdleTimeoutInMs; return this; } /** * Set the maximum time in millisecond an {@link com.ning.http.client.AsyncHttpClient} can stay idle. * - * @param defaultIdleConnectionTimeoutInMs + * @param idleConnectionTimeoutInMs * the maximum time in millisecond an {@link com.ning.http.client.AsyncHttpClient} can stay idle. * @return a {@link Builder} */ - public Builder setIdleConnectionTimeoutInMs(int defaultIdleConnectionTimeoutInMs) { - this.defaultIdleConnectionTimeoutInMs = defaultIdleConnectionTimeoutInMs; + public Builder setIdleConnectionTimeoutInMs(int idleConnectionTimeoutInMs) { + this.idleConnectionTimeoutInMs = idleConnectionTimeoutInMs; return this; } @@ -626,24 +624,24 @@ public Builder setIdleConnectionTimeoutInMs(int defaultIdleConnectionTimeoutInMs * Set the maximum time in millisecond an {@link com.ning.http.client.AsyncHttpClient} will keep connection * idle in pool. * - * @param defaultIdleConnectionInPoolTimeoutInMs + * @param idleConnectionInPoolTimeoutInMs * the maximum time in millisecond an {@link com.ning.http.client.AsyncHttpClient} will keep connection * idle in pool. * @return a {@link Builder} */ - public Builder setIdleConnectionInPoolTimeoutInMs(int defaultIdleConnectionInPoolTimeoutInMs) { - this.defaultIdleConnectionInPoolTimeoutInMs = defaultIdleConnectionInPoolTimeoutInMs; + public Builder setIdleConnectionInPoolTimeoutInMs(int idleConnectionInPoolTimeoutInMs) { + this.idleConnectionInPoolTimeoutInMs = idleConnectionInPoolTimeoutInMs; return this; } /** * Set the maximum time in millisecond an {@link com.ning.http.client.AsyncHttpClient} wait for a response * - * @param defaultRequestTimeoutInMs the maximum time in millisecond an {@link com.ning.http.client.AsyncHttpClient} wait for a response + * @param requestTimeoutInMs the maximum time in millisecond an {@link com.ning.http.client.AsyncHttpClient} wait for a response * @return a {@link Builder} */ - public Builder setRequestTimeoutInMs(int defaultRequestTimeoutInMs) { - this.defaultRequestTimeoutInMs = defaultRequestTimeoutInMs; + public Builder setRequestTimeoutInMs(int requestTimeoutInMs) { + this.requestTimeoutInMs = requestTimeoutInMs; return this; } @@ -1026,7 +1024,7 @@ public Builder setUseRelativeURIsWithSSLProxies(boolean useRelativeURIsWithSSLPr * @return a {@link Builder} */ public Builder setMaxConnectionLifeTimeInMs(int maxConnectionLifeTimeInMs) { - this.defaultMaxConnectionLifeTimeInMs = maxConnectionLifeTimeInMs; + this.maxConnectionLifeTimeInMs = maxConnectionLifeTimeInMs; return this; } @@ -1044,16 +1042,16 @@ public Builder(AsyncHttpClientConfig prototype) { allowPoolingConnection = prototype.getAllowPoolingConnection(); providerConfig = prototype.getAsyncHttpProviderConfig(); connectionsPool = prototype.getConnectionsPool(); - defaultConnectionTimeOutInMs = prototype.getConnectionTimeoutInMs(); - defaultIdleConnectionInPoolTimeoutInMs = prototype.getIdleConnectionInPoolTimeoutInMs(); - defaultIdleConnectionTimeoutInMs = prototype.getIdleConnectionTimeoutInMs(); - defaultMaxConnectionPerHost = prototype.getMaxConnectionPerHost(); - defaultMaxConnectionLifeTimeInMs = prototype.getMaxConnectionLifeTimeInMs(); + connectionTimeOutInMs = prototype.getConnectionTimeoutInMs(); + idleConnectionInPoolTimeoutInMs = prototype.getIdleConnectionInPoolTimeoutInMs(); + idleConnectionTimeoutInMs = prototype.getIdleConnectionTimeoutInMs(); + maxConnectionPerHost = prototype.getMaxConnectionPerHost(); + maxConnectionLifeTimeInMs = prototype.getMaxConnectionLifeTimeInMs(); maxDefaultRedirects = prototype.getMaxRedirects(); - defaultMaxTotalConnections = prototype.getMaxTotalConnections(); + maxTotalConnections = prototype.getMaxTotalConnections(); proxyServerSelector = prototype.getProxyServerSelector(); realm = prototype.getRealm(); - defaultRequestTimeoutInMs = prototype.getRequestTimeoutInMs(); + requestTimeoutInMs = prototype.getRequestTimeoutInMs(); sslContext = prototype.getSSLContext(); sslEngineFactory = prototype.getSSLEngineFactory(); userAgent = prototype.getUserAgent(); @@ -1110,14 +1108,14 @@ public Thread newThread(Runnable r) { proxyServerSelector = ProxyServerSelector.NO_PROXY_SELECTOR; } - return new AsyncHttpClientConfig(defaultMaxTotalConnections, - defaultMaxConnectionPerHost, - defaultConnectionTimeOutInMs, - defaultWebsocketIdleTimeoutInMs, - defaultIdleConnectionInPoolTimeoutInMs, - defaultIdleConnectionTimeoutInMs, - defaultRequestTimeoutInMs, - defaultMaxConnectionLifeTimeInMs, + return new AsyncHttpClientConfig(maxTotalConnections, + maxConnectionPerHost, + connectionTimeOutInMs, + webSocketIdleTimeoutInMs, + idleConnectionInPoolTimeoutInMs, + idleConnectionTimeoutInMs, + requestTimeoutInMs, + maxConnectionLifeTimeInMs, redirectEnabled, maxDefaultRedirects, compressionEnabled, diff --git a/src/main/java/com/ning/http/client/AsyncHttpClientConfigBean.java b/src/main/java/com/ning/http/client/AsyncHttpClientConfigBean.java index 8e2feccab4..db2639a7f7 100644 --- a/src/main/java/com/ning/http/client/AsyncHttpClientConfigBean.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClientConfigBean.java @@ -12,6 +12,8 @@ */ package com.ning.http.client; +import static com.ning.http.client.AsyncHttpClientConfigDefaults.*; + import com.ning.http.client.filter.IOExceptionFilter; import com.ning.http.client.filter.RequestFilter; import com.ning.http.client.filter.ResponseFilter; @@ -19,7 +21,7 @@ import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLSession; + import java.util.LinkedList; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -43,39 +45,34 @@ void configureFilters() { } void configureDefaults() { - maxTotalConnections = Integer.getInteger(ASYNC_CLIENT + "defaultMaxTotalConnections", -1); - maxConnectionPerHost = Integer.getInteger(ASYNC_CLIENT + "defaultMaxConnectionsPerHost", -1); - connectionTimeOutInMs = Integer.getInteger(ASYNC_CLIENT + "defaultConnectionTimeoutInMS", 60 * 1000); - idleConnectionInPoolTimeoutInMs = Integer.getInteger(ASYNC_CLIENT + "defaultIdleConnectionInPoolTimeoutInMS", 60 * 1000); - idleConnectionTimeoutInMs = Integer.getInteger(ASYNC_CLIENT + "defaultIdleConnectionTimeoutInMS", 60 * 1000); - requestTimeoutInMs = Integer.getInteger(ASYNC_CLIENT + "defaultRequestTimeoutInMS", 60 * 1000); - maxConnectionLifeTimeInMs = Integer.getInteger(ASYNC_CLIENT + "defaultMaxConnectionLifeTimeInMs", -1); - redirectEnabled = Boolean.getBoolean(ASYNC_CLIENT + "defaultRedirectsEnabled"); - 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", 2); - - boolean useProxySelector = Boolean.getBoolean(ASYNC_CLIENT + "useProxySelector"); - boolean useProxyProperties = Boolean.getBoolean(ASYNC_CLIENT + "useProxyProperties"); - if (useProxySelector) { + maxTotalConnections = defaultMaxTotalConnections(); + maxConnectionPerHost = defaultMaxConnectionPerHost(); + connectionTimeOutInMs = defaultConnectionTimeOutInMs(); + webSocketIdleTimeoutInMs = defaultWebSocketIdleTimeoutInMs(); + idleConnectionInPoolTimeoutInMs = defaultIdleConnectionInPoolTimeoutInMs(); + idleConnectionTimeoutInMs = defaultIdleConnectionTimeoutInMs(); + requestTimeoutInMs = defaultRequestTimeoutInMs(); + maxConnectionLifeTimeInMs = defaultMaxConnectionLifeTimeInMs(); + redirectEnabled = defaultRedirectEnabled(); + maxRedirects = defaultMaxRedirects(); + compressionEnabled = defaultCompressionEnabled(); + userAgent = defaultUserAgent(); + allowPoolingConnection = defaultAllowPoolingConnection(); + useRelativeURIsWithSSLProxies = defaultUseRelativeURIsWithSSLProxies(); + requestCompressionLevel = defaultRequestCompressionLevel(); + maxRequestRetry = defaultMaxRequestRetry(); + ioThreadMultiplier = defaultIoThreadMultiplier(); + allowSslConnectionPool = defaultAllowSslConnectionPool(); + useRawUrl = defaultUseRawUrl(); + removeQueryParamOnRedirect = defaultRemoveQueryParamOnRedirect(); + strict302Handling = defaultStrict302Handling(); + hostnameVerifier = defaultHostnameVerifier(); + + if (defaultUseProxySelector()) { proxyServerSelector = ProxyUtils.getJdkDefaultProxyServerSelector(); - } else if (useProxyProperties) { + } else if (defaultUseProxyProperties()) { proxyServerSelector = ProxyUtils.createProxyServerSelector(System.getProperties()); } - - allowPoolingConnection = true; - requestCompressionLevel = -1; - maxRequestRetry = 5; - allowSslConnectionPool = true; - useRawUrl = false; - removeQueryParamOnRedirect = true; - hostnameVerifier = new HostnameVerifier() { - - public boolean verify(String s, SSLSession sslSession) { - return true; - } - }; } void configureExecutors() { @@ -133,8 +130,8 @@ public AsyncHttpClientConfigBean setRedirectEnabled(boolean redirectEnabled) { return this; } - public AsyncHttpClientConfigBean setMaxDefaultRedirects(int maxDefaultRedirects) { - this.maxDefaultRedirects = maxDefaultRedirects; + public AsyncHttpClientConfigBean setMaxRedirects(int maxRedirects) { + this.maxRedirects = maxRedirects; return this; } diff --git a/src/main/java/com/ning/http/client/AsyncHttpClientConfigDefaults.java b/src/main/java/com/ning/http/client/AsyncHttpClientConfigDefaults.java new file mode 100644 index 0000000000..58ccb8ce14 --- /dev/null +++ b/src/main/java/com/ning/http/client/AsyncHttpClientConfigDefaults.java @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2014 AsyncHttpClient Project. 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; + +import com.ning.http.util.AllowAllHostnameVerifier; +import static com.ning.http.util.MiscUtil.getBoolean; + +import javax.net.ssl.HostnameVerifier; + +public final class AsyncHttpClientConfigDefaults { + + private AsyncHttpClientConfigDefaults() { + } + + public static final String ASYNC_CLIENT = AsyncHttpClientConfig.class.getName() + "."; + + public static int defaultMaxTotalConnections() { + return Integer.getInteger(ASYNC_CLIENT + "maxTotalConnections", -1); + } + + public static int defaultMaxConnectionPerHost() { + return Integer.getInteger(ASYNC_CLIENT + "maxConnectionsPerHost", -1); + } + + public static int defaultConnectionTimeOutInMs() { + return Integer.getInteger(ASYNC_CLIENT + "connectionTimeoutInMs", 60 * 1000); + } + + public static int defaultIdleConnectionInPoolTimeoutInMs() { + return Integer.getInteger(ASYNC_CLIENT + "idleConnectionInPoolTimeoutInMs", 60 * 1000); + } + + public static int defaultIdleConnectionTimeoutInMs() { + return Integer.getInteger(ASYNC_CLIENT + "idleConnectionTimeoutInMs", 60 * 1000); + } + + public static int defaultRequestTimeoutInMs() { + return Integer.getInteger(ASYNC_CLIENT + "requestTimeoutInMs", 60 * 1000); + } + + public static int defaultWebSocketIdleTimeoutInMs() { + return Integer.getInteger(ASYNC_CLIENT + "webSocketTimoutInMS", 15 * 60 * 1000); + } + + public static int defaultMaxConnectionLifeTimeInMs() { + return Integer.getInteger(ASYNC_CLIENT + "maxConnectionLifeTimeInMs", -1); + } + + public static boolean defaultRedirectEnabled() { + return Boolean.getBoolean(ASYNC_CLIENT + "redirectsEnabled"); + } + + public static int defaultMaxRedirects() { + return Integer.getInteger(ASYNC_CLIENT + "maxRedirects", 5); + } + + public static boolean defaultCompressionEnabled() { + return Boolean.getBoolean(ASYNC_CLIENT + "compressionEnabled"); + } + + public static String defaultUserAgent() { + return System.getProperty(ASYNC_CLIENT + "userAgent", "NING/1.0"); + } + + public static int defaultIoThreadMultiplier() { + return Integer.getInteger(ASYNC_CLIENT + "ioThreadMultiplier", 2); + } + + public static boolean defaultUseProxySelector() { + return Boolean.getBoolean(ASYNC_CLIENT + "useProxySelector"); + } + + public static boolean defaultUseProxyProperties() { + return Boolean.getBoolean(ASYNC_CLIENT + "useProxyProperties"); + } + + public static boolean defaultStrict302Handling() { + return Boolean.getBoolean(ASYNC_CLIENT + "strict302Handling"); + } + + public static boolean defaultAllowPoolingConnection() { + return getBoolean(ASYNC_CLIENT + "allowPoolingConnection", true); + } + + public static boolean defaultUseRelativeURIsWithSSLProxies() { + return getBoolean(ASYNC_CLIENT + "useRelativeURIsWithSSLProxies", true); + } + + // unused/broken, left there for compatibility, fixed in Netty 4 + public static int defaultRequestCompressionLevel() { + return Integer.getInteger(ASYNC_CLIENT + "requestCompressionLevel", -1); + } + + public static int defaultMaxRequestRetry() { + return Integer.getInteger(ASYNC_CLIENT + "maxRequestRetry", 5); + } + + public static boolean defaultAllowSslConnectionPool() { + return getBoolean(ASYNC_CLIENT + "allowSslConnectionPool", true); + } + + public static boolean defaultUseRawUrl() { + return Boolean.getBoolean(ASYNC_CLIENT + "useRawUrl"); + } + + public static boolean defaultRemoveQueryParamOnRedirect() { + return getBoolean(ASYNC_CLIENT + "removeQueryParamOnRedirect", true); + } + + public static HostnameVerifier defaultHostnameVerifier() { + return new AllowAllHostnameVerifier(); + } +} From accba1ab9231d44a21732c902ed7980f1cd9a8bf Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 4 Jun 2014 08:56:22 +0200 Subject: [PATCH 302/701] Only trigger IdleChannelDetector when maxIdleTime is > 0, close #566 --- .../http/client/providers/netty/NettyConnectionsPool.java | 4 +++- 1 file changed, 3 insertions(+), 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 5bc1765237..491b88a339 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 @@ -65,7 +65,9 @@ public NettyConnectionsPool(int maxTotalConnections, int maxConnectionPerHost, l this.maxIdleTime = maxIdleTime; this.maxConnectionLifeTimeInMs = maxConnectionLifeTimeInMs; this.nettyTimer = nettyTimer; - scheduleNewIdleChannelDetector(new IdleChannelDetector()); + if (maxIdleTime > 0L) { + scheduleNewIdleChannelDetector(new IdleChannelDetector()); + } } private void scheduleNewIdleChannelDetector(TimerTask task) { From b4f289b75a86bc9a5ab21cdbaa70a669e2a35a0a Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 4 Jun 2014 14:22:24 +0200 Subject: [PATCH 303/701] minor clean up --- .../providers/netty/NettyConnectionsPool.java | 61 ++++++++----------- 1 file changed, 26 insertions(+), 35 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 491b88a339..0a8e3a8e9e 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,7 +36,8 @@ */ public class NettyConnectionsPool implements ConnectionsPool { - private final static Logger log = LoggerFactory.getLogger(NettyConnectionsPool.class); + private static final Logger LOGGER = LoggerFactory.getLogger(NettyConnectionsPool.class); + private final ConcurrentHashMap> connectionsPool = new ConcurrentHashMap>(); private final ConcurrentHashMap channel2IdleChannel = new ConcurrentHashMap(); private final ConcurrentHashMap channel2CreationDate = new ConcurrentHashMap(); @@ -57,8 +58,8 @@ public NettyConnectionsPool(NettyAsyncHttpProvider provider, Timer hashedWheelTi hashedWheelTimer); } - public NettyConnectionsPool(int maxTotalConnections, int maxConnectionPerHost, long maxIdleTime, int maxConnectionLifeTimeInMs, boolean sslConnectionPoolEnabled, - Timer nettyTimer) { + public NettyConnectionsPool(int maxTotalConnections, int maxConnectionPerHost, long maxIdleTime, int maxConnectionLifeTimeInMs, + boolean sslConnectionPoolEnabled, Timer nettyTimer) { this.maxTotalConnections = maxTotalConnections; this.maxConnectionPerHost = maxConnectionPerHost; this.sslConnectionPoolEnabled = sslConnectionPoolEnabled; @@ -74,12 +75,16 @@ private void scheduleNewIdleChannelDetector(TimerTask task) { this.nettyTimer.newTimeout(task, maxIdleTime, TimeUnit.MILLISECONDS); } - private static class IdleChannel { + private static final class IdleChannel { final String uri; final Channel channel; final long start; IdleChannel(String uri, Channel channel) { + if (uri == null) + throw new NullPointerException("uri"); + if (channel == null) + throw new NullPointerException("channel"); this.uri = uri; this.channel = channel; this.start = millisTime(); @@ -87,17 +92,7 @@ private static class IdleChannel { @Override public boolean equals(Object o) { - if (this == o) - return true; - if (!(o instanceof IdleChannel)) - return false; - - IdleChannel that = (IdleChannel) o; - - if (channel != null ? !channel.equals(that.channel) : that.channel != null) - return false; - - return true; + return this == o || (o instanceof IdleChannel && channel.equals(IdleChannel.class.cast(o).channel)); } @Override @@ -113,11 +108,11 @@ public void run(Timeout timeout) throws Exception { if (isClosed.get()) return; - if (log.isDebugEnabled()) { + if (LOGGER.isDebugEnabled()) { Set keys = connectionsPool.keySet(); for (String s : keys) { - log.debug("Entry count for : {} : {}", s, connectionsPool.get(s).size()); + LOGGER.debug("Entry count for : {} : {}", s, connectionsPool.get(s).size()); } } @@ -128,7 +123,7 @@ public void run(Timeout timeout) throws Exception { long age = currentTime - idleChannel.start; if (age > maxIdleTime) { - log.debug("Adding Candidate Idle Channel {}", idleChannel.channel); + LOGGER.debug("Adding Candidate Idle Channel {}", idleChannel.channel); // store in an unsynchronized list to minimize the impact on the ConcurrentHashMap. channelsInTimeout.add(idleChannel); @@ -140,30 +135,29 @@ public void run(Timeout timeout) throws Exception { Object attachment = idleChannel.channel.getPipeline().getContext(NettyAsyncHttpProvider.class).getAttachment(); if (attachment instanceof NettyResponseFuture) { NettyResponseFuture future = (NettyResponseFuture) attachment; - if (!future.isDone() && !future.isCancelled()) { - log.debug("Future not in appropriate state %s\n", future); + LOGGER.debug("Future not in appropriate state %s\n", future); continue; } } if (remove(idleChannel)) { - log.debug("Closing Idle Channel {}", idleChannel.channel); + LOGGER.debug("Closing Idle Channel {}", idleChannel.channel); close(idleChannel.channel); } } - if (log.isTraceEnabled()) { + if (LOGGER.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, millisTime() - endConcurrentLoop)); + LOGGER.trace(String.format("%d channel open, %d idle channels closed (times: 1st-loop=%d, 2nd-loop=%d).\n", openChannels, + channelsInTimeout.size(), endConcurrentLoop - currentTime, millisTime() - endConcurrentLoop)); } } catch (Throwable t) { - log.error("uncaught exception!", t); + LOGGER.error("uncaught exception!", t); } scheduleNewIdleChannelDetector(timeout.getTask()); @@ -174,22 +168,19 @@ public void run(Timeout timeout) throws Exception { * {@inheritDoc} */ public boolean offer(String uri, Channel channel) { - if (isClosed.get()) + if (isClosed.get() || (!sslConnectionPoolEnabled && uri.startsWith("https"))) return false; - if (!sslConnectionPoolEnabled && uri.startsWith("https")) { - return false; - } - Long createTime = channel2CreationDate.get(channel); if (createTime == null) { channel2CreationDate.putIfAbsent(channel, millisTime()); + } else if (maxConnectionLifeTimeInMs != -1 && (createTime + maxConnectionLifeTimeInMs) < millisTime()) { - log.debug("Channel {} expired", channel); + LOGGER.debug("Channel {} expired", channel); return false; } - log.debug("Adding uri: {} for channel {}", uri, channel); + LOGGER.debug("Adding uri: {} for channel {}", uri, channel); channel.getPipeline().getContext(NettyAsyncHttpProvider.class).setAttachment(new NettyAsyncHttpProvider.DiscardEvent()); ConcurrentLinkedQueue idleConnectionForHost = connectionsPool.get(uri); @@ -208,11 +199,11 @@ public boolean offer(String uri, Channel channel) { added = idleConnectionForHost.add(idleChannel); if (channel2IdleChannel.put(channel, idleChannel) != null) { - log.error("Channel {} already exists in the connections pool!", channel); + LOGGER.error("Channel {} already exists in the connections pool!", channel); } } } else { - log.debug("Maximum number of requests per host reached {} for {}", maxConnectionPerHost, uri); + LOGGER.debug("Maximum number of requests per host reached {} for {}", maxConnectionPerHost, uri); added = false; } return added; @@ -244,7 +235,7 @@ public Channel poll(String uri) { poolEmpty = true; } else if (!idleChannel.channel.isConnected() || !idleChannel.channel.isOpen()) { idleChannel = null; - log.trace("Channel not connected or not opened!"); + LOGGER.trace("Channel not connected or not opened!"); } } } From 4d157acc1301425018c31d7020b6ea50fe897bee Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 4 Jun 2014 16:40:03 +0200 Subject: [PATCH 304/701] minor renaming --- .../providers/netty/NettyConnectionsPool.java | 35 ++++++++----------- 1 file changed, 15 insertions(+), 20 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 0a8e3a8e9e..145bf0ecc5 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 @@ -76,16 +76,16 @@ private void scheduleNewIdleChannelDetector(TimerTask task) { } private static final class IdleChannel { - final String uri; + final String key; final Channel channel; final long start; - IdleChannel(String uri, Channel channel) { - if (uri == null) - throw new NullPointerException("uri"); + IdleChannel(String key, Channel channel) { + if (key == null) + throw new NullPointerException("key"); if (channel == null) throw new NullPointerException("channel"); - this.uri = uri; + this.key = key; this.channel = channel; this.start = millisTime(); } @@ -218,13 +218,13 @@ public Channel poll(String uri) { } IdleChannel idleChannel = null; - ConcurrentLinkedQueue idleConnectionForHost = connectionsPool.get(uri); - if (idleConnectionForHost != null) { + ConcurrentLinkedQueue pooledConnectionForKey = connectionsPool.get(uri); + if (pooledConnectionForKey != null) { boolean poolEmpty = false; while (!poolEmpty && idleChannel == null) { - if (!idleConnectionForHost.isEmpty()) { - synchronized (idleConnectionForHost) { - idleChannel = idleConnectionForHost.poll(); + if (!pooledConnectionForKey.isEmpty()) { + synchronized (pooledConnectionForKey) { + idleChannel = pooledConnectionForKey.poll(); if (idleChannel != null) { channel2IdleChannel.remove(idleChannel.channel); } @@ -247,12 +247,11 @@ private boolean remove(IdleChannel pooledChannel) { return false; boolean isRemoved = false; - ConcurrentLinkedQueue pooledConnectionForHost = connectionsPool.get(pooledChannel.uri); - if (pooledConnectionForHost != null) { - isRemoved = pooledConnectionForHost.remove(pooledChannel); + ConcurrentLinkedQueue pooledConnectionForKey = connectionsPool.get(pooledChannel.key); + if (pooledConnectionForKey != null) { + isRemoved = pooledConnectionForKey.remove(pooledChannel); } - isRemoved |= channel2IdleChannel.remove(pooledChannel.channel) != null; - return isRemoved; + return isRemoved |= channel2IdleChannel.remove(pooledChannel.channel) != null; } /** @@ -267,11 +266,7 @@ public boolean removeAll(Channel channel) { * {@inheritDoc} */ public boolean canCacheConnection() { - if (!isClosed.get() && maxTotalConnections != -1 && channel2IdleChannel.size() >= maxTotalConnections) { - return false; - } else { - return true; - } + return !isClosed.get() && (maxTotalConnections != -1 || channel2IdleChannel.size() < maxTotalConnections); } /** From d85102c76984fda59c86e84bf082665b952b0904 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 5 Jun 2014 17:29:00 +0200 Subject: [PATCH 305/701] Curse people setting public modifier on interface methods --- .../ning/http/client/AsyncHttpProvider.java | 11 ++-- .../http/client/AsyncHttpProviderConfig.java | 8 +-- src/main/java/com/ning/http/client/Body.java | 1 - .../com/ning/http/client/BodyConsumer.java | 1 - .../com/ning/http/client/BodyGenerator.java | 4 +- .../client/ConnectionPoolKeyStrategy.java | 2 +- .../com/ning/http/client/ConnectionsPool.java | 10 +-- src/main/java/com/ning/http/client/Part.java | 4 +- .../http/client/ProgressAsyncHandler.java | 2 +- .../ning/http/client/ProxyServerSelector.java | 1 + .../ning/http/client/RandomAccessBody.java | 4 +- .../java/com/ning/http/client/Request.java | 64 +++++++++---------- .../java/com/ning/http/client/Response.java | 41 ++++++------ .../http/client/ResumableBodyConsumer.java | 2 - .../ning/http/client/SignatureCalculator.java | 5 +- .../ning/http/client/ThrowableHandler.java | 1 - .../com/ning/http/client/UpgradeHandler.java | 1 - .../http/client/filter/IOExceptionFilter.java | 2 +- .../http/client/filter/RequestFilter.java | 3 +- .../http/client/filter/ResponseFilter.java | 3 +- .../client/listener/TransferListener.java | 12 ++-- .../netty/spnego/SpnegoTokenGenerator.java | 1 - .../resumable/ResumableAsyncHandler.java | 10 ++- .../client/resumable/ResumableListener.java | 9 ++- .../simple/SimpleAHCTransferListener.java | 2 +- .../ning/http/client/websocket/WebSocket.java | 1 + .../websocket/WebSocketByteListener.java | 2 - .../client/websocket/WebSocketListener.java | 1 - .../websocket/WebSocketPingListener.java | 1 - .../websocket/WebSocketPongListener.java | 1 - .../websocket/WebSocketTextListener.java | 1 - .../com/ning/http/multipart/PartSource.java | 2 +- .../ning/http/multipart/RequestEntity.java | 2 +- 33 files changed, 97 insertions(+), 118 deletions(-) diff --git a/src/main/java/com/ning/http/client/AsyncHttpProvider.java b/src/main/java/com/ning/http/client/AsyncHttpProvider.java index 1dfdb0474c..8aa6052400 100644 --- a/src/main/java/com/ning/http/client/AsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/AsyncHttpProvider.java @@ -31,12 +31,12 @@ public interface AsyncHttpProvider { * @return a {@link ListenableFuture} of Type T. * @throws IOException */ - public ListenableFuture execute(Request request, AsyncHandler handler) throws IOException; + ListenableFuture execute(Request request, AsyncHandler handler) throws IOException; /** * Close the current underlying TCP/HTTP connection. */ - public void close(); + void close(); /** * Prepare a {@link Response} @@ -46,8 +46,7 @@ public interface AsyncHttpProvider { * @param bodyParts list of {@link HttpResponseBodyPart} * @return a {@link Response} */ - public Response prepareResponse(HttpResponseStatus status, - HttpResponseHeaders headers, - List bodyParts); - + Response prepareResponse(HttpResponseStatus status, + HttpResponseHeaders headers, + List bodyParts); } diff --git a/src/main/java/com/ning/http/client/AsyncHttpProviderConfig.java b/src/main/java/com/ning/http/client/AsyncHttpProviderConfig.java index ea5e0f8911..f73c909b5f 100644 --- a/src/main/java/com/ning/http/client/AsyncHttpProviderConfig.java +++ b/src/main/java/com/ning/http/client/AsyncHttpProviderConfig.java @@ -29,7 +29,7 @@ public interface AsyncHttpProviderConfig { * @param value the value of the property * @return this instance of AsyncHttpProviderConfig */ - public AsyncHttpProviderConfig addProperty(U name, V value); + AsyncHttpProviderConfig addProperty(U name, V value); /** * Return the value associated with the property's name @@ -37,7 +37,7 @@ public interface AsyncHttpProviderConfig { * @param name * @return this instance of AsyncHttpProviderConfig */ - public V getProperty(U name); + V getProperty(U name); /** * Remove the value associated with the property's name @@ -45,12 +45,12 @@ public interface AsyncHttpProviderConfig { * @param name * @return true if removed */ - public V removeProperty(U name); + V removeProperty(U name); /** * Return the curent entry set. * * @return a the curent entry set. */ - public Set> propertiesSet(); + Set> propertiesSet(); } diff --git a/src/main/java/com/ning/http/client/Body.java b/src/main/java/com/ning/http/client/Body.java index 309fbec5ae..b26be40790 100644 --- a/src/main/java/com/ning/http/client/Body.java +++ b/src/main/java/com/ning/http/client/Body.java @@ -43,5 +43,4 @@ public interface Body { * @throws IOException */ void close() throws IOException; - } diff --git a/src/main/java/com/ning/http/client/BodyConsumer.java b/src/main/java/com/ning/http/client/BodyConsumer.java index b092ec1210..c9e188b76e 100644 --- a/src/main/java/com/ning/http/client/BodyConsumer.java +++ b/src/main/java/com/ning/http/client/BodyConsumer.java @@ -35,5 +35,4 @@ public interface BodyConsumer { * @throws IOException */ void close() throws IOException; - } diff --git a/src/main/java/com/ning/http/client/BodyGenerator.java b/src/main/java/com/ning/http/client/BodyGenerator.java index 35fe386282..30cc33c41f 100644 --- a/src/main/java/com/ning/http/client/BodyGenerator.java +++ b/src/main/java/com/ning/http/client/BodyGenerator.java @@ -28,7 +28,5 @@ public interface BodyGenerator { * @return The request body, never {@code null}. * @throws IOException If the body could not be created. */ - Body createBody() - throws IOException; - + Body createBody() throws IOException; } diff --git a/src/main/java/com/ning/http/client/ConnectionPoolKeyStrategy.java b/src/main/java/com/ning/http/client/ConnectionPoolKeyStrategy.java index d0e6643db1..3beb10d3ec 100644 --- a/src/main/java/com/ning/http/client/ConnectionPoolKeyStrategy.java +++ b/src/main/java/com/ning/http/client/ConnectionPoolKeyStrategy.java @@ -20,4 +20,4 @@ public interface ConnectionPoolKeyStrategy { String getKey(URI uri); -} \ No newline at end of file +} diff --git a/src/main/java/com/ning/http/client/ConnectionsPool.java b/src/main/java/com/ning/http/client/ConnectionsPool.java index 1feb843d8b..02dd4283d5 100644 --- a/src/main/java/com/ning/http/client/ConnectionsPool.java +++ b/src/main/java/com/ning/http/client/ConnectionsPool.java @@ -28,7 +28,7 @@ public interface ConnectionsPool { * @param connection an I/O connection * @return true if added. */ - public boolean offer(U uri, V connection); + boolean offer(U uri, V connection); /** * Remove the connection associated with the uri. @@ -36,7 +36,7 @@ public interface ConnectionsPool { * @param uri the uri used when invoking addConnection * @return the connection associated with the uri */ - public V poll(U uri); + V poll(U uri); /** * Remove all connections from the cache. A connection might have been associated with several uri. @@ -44,7 +44,7 @@ public interface ConnectionsPool { * @param connection a connection * @return the true if the connection has been removed */ - public boolean removeAll(V connection); + boolean removeAll(V connection); /** * Return true if a connection can be cached. A implementation can decide based on some rules to allow caching @@ -52,10 +52,10 @@ public interface ConnectionsPool { * * @return true if a connection can be cached. */ - public boolean canCacheConnection(); + boolean canCacheConnection(); /** * Destroy all connections that has been cached by this instance. */ - public void destroy(); + void destroy(); } diff --git a/src/main/java/com/ning/http/client/Part.java b/src/main/java/com/ning/http/client/Part.java index 95e34eeca7..b66fe7f850 100644 --- a/src/main/java/com/ning/http/client/Part.java +++ b/src/main/java/com/ning/http/client/Part.java @@ -20,5 +20,5 @@ * Interface for the parts in a multipart request. */ public interface Part { - public String getName(); -} \ No newline at end of file + String getName(); +} diff --git a/src/main/java/com/ning/http/client/ProgressAsyncHandler.java b/src/main/java/com/ning/http/client/ProgressAsyncHandler.java index 3c0363d8f0..f1150301da 100644 --- a/src/main/java/com/ning/http/client/ProgressAsyncHandler.java +++ b/src/main/java/com/ning/http/client/ProgressAsyncHandler.java @@ -44,5 +44,5 @@ public interface ProgressAsyncHandler extends AsyncHandler { * @return a {@link com.ning.http.client.AsyncHandler.STATE} telling to CONTINUE or ABORT the current processing. */ STATE onContentWriteProgress(long amount, long current, long total); - } + diff --git a/src/main/java/com/ning/http/client/ProxyServerSelector.java b/src/main/java/com/ning/http/client/ProxyServerSelector.java index 8544e7e617..68e5d70ff3 100644 --- a/src/main/java/com/ning/http/client/ProxyServerSelector.java +++ b/src/main/java/com/ning/http/client/ProxyServerSelector.java @@ -24,3 +24,4 @@ public ProxyServer select(URI uri) { } }; } + diff --git a/src/main/java/com/ning/http/client/RandomAccessBody.java b/src/main/java/com/ning/http/client/RandomAccessBody.java index c4ee2f2332..725b092db6 100644 --- a/src/main/java/com/ning/http/client/RandomAccessBody.java +++ b/src/main/java/com/ning/http/client/RandomAccessBody.java @@ -19,8 +19,7 @@ /** * A request body which supports random access to its contents. */ -public interface RandomAccessBody - extends Body { +public interface RandomAccessBody extends Body { /** * Transfers the specified chunk of bytes from this body to the specified channel. @@ -33,5 +32,4 @@ public interface RandomAccessBody */ long transferTo(long position, long count, WritableByteChannel target) throws IOException; - } diff --git a/src/main/java/com/ning/http/client/Request.java b/src/main/java/com/ning/http/client/Request.java index 90b4d88074..1250974078 100644 --- a/src/main/java/com/ning/http/client/Request.java +++ b/src/main/java/com/ning/http/client/Request.java @@ -44,7 +44,7 @@ public interface Request { * An entity that can be used to manipulate the Request's body output before it get sent. */ public static interface EntityWriter { - public void writeEntity(OutputStream out) throws IOException; + void writeEntity(OutputStream out) throws IOException; } /** @@ -53,90 +53,90 @@ public static interface EntityWriter { * @return the request's type (GET, POST, etc.) * @deprecated - use getMethod */ - public String getReqType(); + String getReqType(); /** * Return the request's method name (GET, POST, etc.) * * @return the request's method name (GET, POST, etc.) */ - public String getMethod(); + String getMethod(); /** * Return the decoded url * * @return the decoded url */ - public String getUrl(); + String getUrl(); - public URI getOriginalURI(); - public URI getURI(); - public URI getRawURI(); + URI getOriginalURI(); + URI getURI(); + URI getRawURI(); /** * Return the InetAddress to override * * @return the InetAddress */ - public InetAddress getInetAddress(); + InetAddress getInetAddress(); - public InetAddress getLocalAddress(); + InetAddress getLocalAddress(); /** * Return the undecoded url * * @return the undecoded url */ - public String getRawUrl(); + String getRawUrl(); /** * Return the current set of Headers. * * @return a {@link FluentCaseInsensitiveStringsMap} contains headers. */ - public FluentCaseInsensitiveStringsMap getHeaders(); + FluentCaseInsensitiveStringsMap getHeaders(); /** * Return Coookie. * * @return an unmodifiable Collection of Cookies */ - public Collection getCookies(); + Collection getCookies(); /** * Return the current request's body as a byte array * * @return a byte array of the current request's body. */ - public byte[] getByteData(); + byte[] getByteData(); /** * Return the current request's body as a string * * @return an String representation of the current request's body. */ - public String getStringData(); + String getStringData(); /** * Return the current request's body as an InputStream * * @return an InputStream representation of the current request's body. */ - public InputStream getStreamData(); + InputStream getStreamData(); /** * Return the current request's body as an EntityWriter * * @return an EntityWriter representation of the current request's body. */ - public EntityWriter getEntityWriter(); + EntityWriter getEntityWriter(); /** * Return the current request's body generator. * * @return A generator for the request body. */ - public BodyGenerator getBodyGenerator(); + BodyGenerator getBodyGenerator(); /** * Return the current size of the content-lenght header based on the body's size. @@ -144,100 +144,100 @@ public static interface EntityWriter { * @return the current size of the content-lenght header based on the body's size. * @deprecated */ - public long getLength(); + long getLength(); /** * Return the current size of the content-lenght header based on the body's size. * * @return the current size of the content-lenght header based on the body's size. */ - public long getContentLength(); + long getContentLength(); /** * Return the current parameters. * * @return a {@link FluentStringsMap} of parameters. */ - public FluentStringsMap getParams(); + FluentStringsMap getParams(); /** * Return the current {@link Part} * * @return the current {@link Part} */ - public List getParts(); + List getParts(); /** * Return the virtual host value. * * @return the virtual host value. */ - public String getVirtualHost(); + String getVirtualHost(); /** * Return the query params. * * @return {@link FluentStringsMap} of query string */ - public FluentStringsMap getQueryParams(); + FluentStringsMap getQueryParams(); /** * Return the {@link ProxyServer} * * @return the {@link ProxyServer} */ - public ProxyServer getProxyServer(); + ProxyServer getProxyServer(); /** * Return the {@link Realm} * * @return the {@link Realm} */ - public Realm getRealm(); + Realm getRealm(); /** * Return the {@link File} to upload. * * @return the {@link File} to upload. */ - public File getFile(); + File getFile(); /** * Return the true> to follow redirect * * @return the true> to follow redirect */ - public boolean isRedirectEnabled(); + boolean isRedirectEnabled(); /** * * @return true> if request's redirectEnabled setting * should be used in place of client's */ - public boolean isRedirectOverrideSet(); + boolean isRedirectOverrideSet(); /** * Return Per request configuration. * * @return Per request configuration. */ - public PerRequestConfig getPerRequestConfig(); + PerRequestConfig getPerRequestConfig(); /** * Return the HTTP Range header value, or * * @return the range header value, or 0 is not set. */ - public long getRangeOffset(); + long getRangeOffset(); /** * Return the encoding value used when encoding the request's body. * * @return the encoding value used when encoding the request's body. */ - public String getBodyEncoding(); + String getBodyEncoding(); - public boolean isUseRawUrl(); + boolean isUseRawUrl(); ConnectionPoolKeyStrategy getConnectionPoolKeyStrategy(); } diff --git a/src/main/java/com/ning/http/client/Response.java b/src/main/java/com/ning/http/client/Response.java index 4d355e156c..30228bcdf7 100644 --- a/src/main/java/com/ning/http/client/Response.java +++ b/src/main/java/com/ning/http/client/Response.java @@ -36,14 +36,14 @@ public interface Response { * * @return The status code */ - public int getStatusCode(); + int getStatusCode(); /** * Returns the status text for the request. * * @return The status text */ - public String getStatusText(); + String getStatusText(); /** * Return the entire response body as a byte[]. @@ -51,7 +51,7 @@ public interface Response { * @return the entire response body as a byte[]. * @throws IOException */ - public byte[] getResponseBodyAsBytes() throws IOException; + byte[] getResponseBodyAsBytes() throws IOException; /** * Return the entire response body as a ByteBuffer. @@ -59,7 +59,7 @@ public interface Response { * @return the entire response body as a ByteBuffer. * @throws IOException */ - public ByteBuffer getResponseBodyAsByteBuffer() throws IOException; + ByteBuffer getResponseBodyAsByteBuffer() throws IOException; /** * Returns an input stream for the response body. Note that you should not try to get this more than once, @@ -68,7 +68,7 @@ public interface Response { * @return The input stream * @throws java.io.IOException */ - public InputStream getResponseBodyAsStream() throws IOException; + InputStream getResponseBodyAsStream() throws IOException; /** * Returns the first maxLength bytes of the response body as a string. Note that this does not check @@ -80,7 +80,7 @@ public interface Response { * @return The response body * @throws java.io.IOException */ - public String getResponseBodyExcerpt(int maxLength, String charset) throws IOException; + String getResponseBodyExcerpt(int maxLength, String charset) throws IOException; /** * Return the entire response body as a String. @@ -89,7 +89,7 @@ public interface Response { * @return the entire response body as a String. * @throws IOException */ - public String getResponseBody(String charset) throws IOException; + String getResponseBody(String charset) throws IOException; /** * Returns the first maxLength bytes of the response body as a string. Note that this does not check @@ -100,7 +100,7 @@ public interface Response { * @return The response body * @throws java.io.IOException */ - public String getResponseBodyExcerpt(int maxLength) throws IOException; + String getResponseBodyExcerpt(int maxLength) throws IOException; /** * Return the entire response body as a String. @@ -108,7 +108,7 @@ public interface Response { * @return the entire response body as a String. * @throws IOException */ - public String getResponseBody() throws IOException; + String getResponseBody() throws IOException; /** * Return the request {@link URI}. Note that if the request got redirected, the value of the {@link URI} will be @@ -117,30 +117,30 @@ public interface Response { * @return the request {@link URI}. * @throws MalformedURLException */ - public URI getUri() throws MalformedURLException; + URI getUri() throws MalformedURLException; /** * Return the content-type header value. * * @return the content-type header value. */ - public String getContentType(); + String getContentType(); /** * Return the response header * * @return the response header */ - public String getHeader(String name); + String getHeader(String name); /** * Return a {@link List} of the response header value. * * @return the response header */ - public List getHeaders(String name); + List getHeaders(String name); - public FluentCaseInsensitiveStringsMap getHeaders(); + FluentCaseInsensitiveStringsMap getHeaders(); /** * Return true if the response redirects to another object. @@ -154,19 +154,19 @@ public interface Response { * * @return The textual representation */ - public String toString(); + String toString(); /** * Return the list of {@link Cookie}. */ - public List getCookies(); + List getCookies(); /** * Return true if the response's status has been computed by an {@link AsyncHandler} * * @return true if the response's status has been computed by an {@link AsyncHandler} */ - public boolean hasResponseStatus(); + boolean hasResponseStatus(); /** * Return true if the response's headers has been computed by an {@link AsyncHandler} It will return false if the @@ -175,7 +175,7 @@ public interface Response { * * @return true if the response's headers has been computed by an {@link AsyncHandler} */ - public boolean hasResponseHeaders(); + boolean hasResponseHeaders(); /** * Return true if the response's body has been computed by an {@link AsyncHandler}. It will return false if the @@ -184,7 +184,7 @@ public interface Response { * * @return true if the response's body has been computed by an {@link AsyncHandler} */ - public boolean hasResponseBody(); + boolean hasResponseBody(); public static class ResponseBuilder { @@ -230,5 +230,4 @@ public void reset() { headers = null; } } - -} \ No newline at end of file +} diff --git a/src/main/java/com/ning/http/client/ResumableBodyConsumer.java b/src/main/java/com/ning/http/client/ResumableBodyConsumer.java index 018bd648e4..531a9c1ddc 100644 --- a/src/main/java/com/ning/http/client/ResumableBodyConsumer.java +++ b/src/main/java/com/ning/http/client/ResumableBodyConsumer.java @@ -33,6 +33,4 @@ public interface ResumableBodyConsumer extends BodyConsumer { * @throws IOException */ long getTransferredBytes() throws IOException; - - } diff --git a/src/main/java/com/ning/http/client/SignatureCalculator.java b/src/main/java/com/ning/http/client/SignatureCalculator.java index 8c31cc8d0d..8826684658 100644 --- a/src/main/java/com/ning/http/client/SignatureCalculator.java +++ b/src/main/java/com/ning/http/client/SignatureCalculator.java @@ -35,6 +35,7 @@ public interface SignatureCalculator { * @param request Request that is being built; needed to access content to * be signed */ - public void calculateAndAddSignature(String url, Request request, - RequestBuilderBase requestBuilder); + void calculateAndAddSignature(String url, + Request request, + RequestBuilderBase requestBuilder); } diff --git a/src/main/java/com/ning/http/client/ThrowableHandler.java b/src/main/java/com/ning/http/client/ThrowableHandler.java index 5f017fd4b7..d7c13eecbf 100644 --- a/src/main/java/com/ning/http/client/ThrowableHandler.java +++ b/src/main/java/com/ning/http/client/ThrowableHandler.java @@ -19,5 +19,4 @@ public interface ThrowableHandler { void onThrowable(Throwable t); - } diff --git a/src/main/java/com/ning/http/client/UpgradeHandler.java b/src/main/java/com/ning/http/client/UpgradeHandler.java index 861e3abe0a..3eee98659c 100644 --- a/src/main/java/com/ning/http/client/UpgradeHandler.java +++ b/src/main/java/com/ning/http/client/UpgradeHandler.java @@ -33,5 +33,4 @@ public interface UpgradeHandler { * @param t a {@link Throwable} */ void onFailure(Throwable t); - } diff --git a/src/main/java/com/ning/http/client/filter/IOExceptionFilter.java b/src/main/java/com/ning/http/client/filter/IOExceptionFilter.java index 59f5cdc6f0..645587df47 100644 --- a/src/main/java/com/ning/http/client/filter/IOExceptionFilter.java +++ b/src/main/java/com/ning/http/client/filter/IOExceptionFilter.java @@ -25,5 +25,5 @@ public interface IOExceptionFilter { * @return {@link FilterContext}. The {@link FilterContext} instance may not the same as the original one. * @throws FilterException to interrupt the filter processing. */ - public FilterContext filter(FilterContext ctx) throws FilterException; + FilterContext filter(FilterContext ctx) throws FilterException; } diff --git a/src/main/java/com/ning/http/client/filter/RequestFilter.java b/src/main/java/com/ning/http/client/filter/RequestFilter.java index 31d0749b9b..9f405aaded 100644 --- a/src/main/java/com/ning/http/client/filter/RequestFilter.java +++ b/src/main/java/com/ning/http/client/filter/RequestFilter.java @@ -26,6 +26,5 @@ public interface RequestFilter { * @return {@link FilterContext}. The {@link FilterContext} instance may not the same as the original one. * @throws FilterException to interrupt the filter processing. */ - public FilterContext filter(FilterContext ctx) throws FilterException; - + FilterContext filter(FilterContext ctx) throws FilterException; } diff --git a/src/main/java/com/ning/http/client/filter/ResponseFilter.java b/src/main/java/com/ning/http/client/filter/ResponseFilter.java index 3175dfe399..3edf3d9126 100644 --- a/src/main/java/com/ning/http/client/filter/ResponseFilter.java +++ b/src/main/java/com/ning/http/client/filter/ResponseFilter.java @@ -29,6 +29,5 @@ public interface ResponseFilter { * @return {@link FilterContext}. The {@link FilterContext} instance may not the same as the original one. * @throws FilterException to interrupt the filter processing. */ - public FilterContext filter(FilterContext ctx) throws FilterException; - + FilterContext filter(FilterContext ctx) throws FilterException; } diff --git a/src/main/java/com/ning/http/client/listener/TransferListener.java b/src/main/java/com/ning/http/client/listener/TransferListener.java index 580c3cba53..1b0b76fbe7 100644 --- a/src/main/java/com/ning/http/client/listener/TransferListener.java +++ b/src/main/java/com/ning/http/client/listener/TransferListener.java @@ -25,36 +25,36 @@ public interface TransferListener { /** * Invoked when the request bytes are starting to get send. */ - public void onRequestHeadersSent(FluentCaseInsensitiveStringsMap headers); + void onRequestHeadersSent(FluentCaseInsensitiveStringsMap headers); /** * Invoked when the response bytes are starting to get received. */ - public void onResponseHeadersReceived(FluentCaseInsensitiveStringsMap headers); + void onResponseHeadersReceived(FluentCaseInsensitiveStringsMap headers); /** * Invoked every time response's chunk are received. * * @param buffer a {@link ByteBuffer} */ - public void onBytesReceived(ByteBuffer buffer) throws IOException; + void onBytesReceived(ByteBuffer buffer) throws IOException; /** * Invoked every time request's chunk are sent. * * @param buffer a {@link ByteBuffer} */ - public void onBytesSent(ByteBuffer buffer); + void onBytesSent(ByteBuffer buffer); /** * Invoked when the response bytes are been fully received. */ - public void onRequestResponseCompleted(); + void onRequestResponseCompleted(); /** * Invoked when there is an unexpected issue. * * @param t a {@link Throwable} */ - public void onThrowable(Throwable t); + void onThrowable(Throwable t); } diff --git a/src/main/java/com/ning/http/client/providers/netty/spnego/SpnegoTokenGenerator.java b/src/main/java/com/ning/http/client/providers/netty/spnego/SpnegoTokenGenerator.java index 1eca8af21a..136d1330da 100644 --- a/src/main/java/com/ning/http/client/providers/netty/spnego/SpnegoTokenGenerator.java +++ b/src/main/java/com/ning/http/client/providers/netty/spnego/SpnegoTokenGenerator.java @@ -51,5 +51,4 @@ public interface SpnegoTokenGenerator { byte[] generateSpnegoDERObject(byte[] kerberosTicket) throws IOException; - } 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 ac023a28c2..5e87b28d7d 100644 --- a/src/main/java/com/ning/http/client/resumable/ResumableAsyncHandler.java +++ b/src/main/java/com/ning/http/client/resumable/ResumableAsyncHandler.java @@ -255,14 +255,14 @@ public static interface ResumableProcessor { * @param key a key. The recommended way is to use an url. * @param transferredBytes The number of bytes sucessfully transferred. */ - public void put(String key, long transferredBytes); + void put(String key, long transferredBytes); /** * Remove the key associate value. * * @param key key from which the value will be discarted */ - public void remove(String key); + void remove(String key); /** * Save the current {@link Map} instance which contains information about the current transfer state. @@ -270,15 +270,14 @@ public static interface ResumableProcessor { * * @param map */ - public void save(Map map); + void save(Map map); /** * Load the {@link Map} in memory, contains information about the transferred bytes. * * @return {@link Map} */ - public Map load(); - + Map load(); } private static class NULLResumableHandler implements ResumableProcessor { @@ -311,6 +310,5 @@ public void onAllBytesReceived() { public long length() { return length; } - } } diff --git a/src/main/java/com/ning/http/client/resumable/ResumableListener.java b/src/main/java/com/ning/http/client/resumable/ResumableListener.java index 0b55ac2257..5092899a9b 100644 --- a/src/main/java/com/ning/http/client/resumable/ResumableListener.java +++ b/src/main/java/com/ning/http/client/resumable/ResumableListener.java @@ -26,18 +26,17 @@ public interface ResumableListener { * @param byteBuffer the current bytes * @throws IOException */ - public void onBytesReceived(ByteBuffer byteBuffer) throws IOException; + void onBytesReceived(ByteBuffer byteBuffer) throws IOException; /** * Invoked when all the bytes has been sucessfully transferred. */ - public void onAllBytesReceived(); + void onAllBytesReceived(); /** * Return the length of previously downloaded bytes. * * @return the length of previously downloaded bytes */ - public long length(); - -} \ No newline at end of file + long length(); +} diff --git a/src/main/java/com/ning/http/client/simple/SimpleAHCTransferListener.java b/src/main/java/com/ning/http/client/simple/SimpleAHCTransferListener.java index 39d780c32f..726e770043 100644 --- a/src/main/java/com/ning/http/client/simple/SimpleAHCTransferListener.java +++ b/src/main/java/com/ning/http/client/simple/SimpleAHCTransferListener.java @@ -75,5 +75,5 @@ public interface SimpleAHCTransferListener { * @param statusText the received status text. */ void onCompleted(String url, int statusCode, String statusText); - } + 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 ae7183fe48..ef045289d8 100644 --- a/src/main/java/com/ning/http/client/websocket/WebSocket.java +++ b/src/main/java/com/ning/http/client/websocket/WebSocket.java @@ -108,3 +108,4 @@ public interface WebSocket extends Closeable { */ void close(); } + diff --git a/src/main/java/com/ning/http/client/websocket/WebSocketByteListener.java b/src/main/java/com/ning/http/client/websocket/WebSocketByteListener.java index e4f9362f1a..5a5c99f4d6 100644 --- a/src/main/java/com/ning/http/client/websocket/WebSocketByteListener.java +++ b/src/main/java/com/ning/http/client/websocket/WebSocketByteListener.java @@ -23,7 +23,6 @@ public interface WebSocketByteListener extends WebSocketListener { */ void onMessage(byte[] message); - /** * Invoked when bytes of a fragmented message are available. * @@ -31,5 +30,4 @@ public interface WebSocketByteListener extends WebSocketListener { * @param last if this fragment is the last in the series. */ void onFragment(byte[] fragment, boolean last); - } diff --git a/src/main/java/com/ning/http/client/websocket/WebSocketListener.java b/src/main/java/com/ning/http/client/websocket/WebSocketListener.java index 360f66cf21..83da93ebbd 100644 --- a/src/main/java/com/ning/http/client/websocket/WebSocketListener.java +++ b/src/main/java/com/ning/http/client/websocket/WebSocketListener.java @@ -37,5 +37,4 @@ public interface WebSocketListener { * @param t a {@link Throwable} */ void onError(Throwable t); - } diff --git a/src/main/java/com/ning/http/client/websocket/WebSocketPingListener.java b/src/main/java/com/ning/http/client/websocket/WebSocketPingListener.java index 5980c67b9e..f2a7d69ee6 100644 --- a/src/main/java/com/ning/http/client/websocket/WebSocketPingListener.java +++ b/src/main/java/com/ning/http/client/websocket/WebSocketPingListener.java @@ -22,5 +22,4 @@ public interface WebSocketPingListener extends WebSocketListener { * @param message a byte array */ void onPing(byte[] message); - } diff --git a/src/main/java/com/ning/http/client/websocket/WebSocketPongListener.java b/src/main/java/com/ning/http/client/websocket/WebSocketPongListener.java index 559abc97b3..44e4548888 100644 --- a/src/main/java/com/ning/http/client/websocket/WebSocketPongListener.java +++ b/src/main/java/com/ning/http/client/websocket/WebSocketPongListener.java @@ -22,5 +22,4 @@ public interface WebSocketPongListener extends WebSocketListener { * @param message a byte array */ void onPong(byte[] message); - } diff --git a/src/main/java/com/ning/http/client/websocket/WebSocketTextListener.java b/src/main/java/com/ning/http/client/websocket/WebSocketTextListener.java index 1b56319a85..e5456cb112 100644 --- a/src/main/java/com/ning/http/client/websocket/WebSocketTextListener.java +++ b/src/main/java/com/ning/http/client/websocket/WebSocketTextListener.java @@ -30,5 +30,4 @@ public interface WebSocketTextListener extends WebSocketListener { * @param last if this fragment is the last of the series. */ void onFragment(String fragment, boolean last); - } diff --git a/src/main/java/com/ning/http/multipart/PartSource.java b/src/main/java/com/ning/http/multipart/PartSource.java index eecf859c3f..06fcc8044f 100644 --- a/src/main/java/com/ning/http/multipart/PartSource.java +++ b/src/main/java/com/ning/http/multipart/PartSource.java @@ -48,5 +48,5 @@ public interface PartSource { * @throws java.io.IOException if an error occurs when creating the InputStream */ InputStream createInputStream() throws IOException; - } + diff --git a/src/main/java/com/ning/http/multipart/RequestEntity.java b/src/main/java/com/ning/http/multipart/RequestEntity.java index 823c8aaf43..ee7fda03e5 100644 --- a/src/main/java/com/ning/http/multipart/RequestEntity.java +++ b/src/main/java/com/ning/http/multipart/RequestEntity.java @@ -51,5 +51,5 @@ public interface RequestEntity { * @return the entity's content type */ String getContentType(); - } + From 07a41954e041d99c37281bd462b6de4af06b75de Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 11 Jun 2014 12:38:29 +0200 Subject: [PATCH 306/701] Upgrade Netty 3.9.2, close #568 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 702ecb1f16..6cf521ae45 100644 --- a/pom.xml +++ b/pom.xml @@ -81,7 +81,7 @@ io.netty netty - 3.9.1.Final + 3.9.2.Final From 3a002896791fa322c36276f14b447736415228bd Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 11 Jun 2014 14:33:12 +0200 Subject: [PATCH 307/701] Me idiot --- .../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 145bf0ecc5..1feabcd579 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 @@ -266,7 +266,7 @@ public boolean removeAll(Channel channel) { * {@inheritDoc} */ public boolean canCacheConnection() { - return !isClosed.get() && (maxTotalConnections != -1 || channel2IdleChannel.size() < maxTotalConnections); + return !isClosed.get() && (maxTotalConnections == -1 || channel2IdleChannel.size() < maxTotalConnections); } /** From 1b211cd526ca61369a6ab95b99b925ca817a8d42 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 11 Jun 2014 14:34:25 +0200 Subject: [PATCH 308/701] [maven-release-plugin] prepare release async-http-client-1.8.10 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 6cf521ae45..72707c9a47 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.8.10-SNAPSHOT + 1.8.10 jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From fadedec6418bd7bc4ab62b164ffe11b803792156 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 11 Jun 2014 14:34:31 +0200 Subject: [PATCH 309/701] [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 72707c9a47..2e4abceb26 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.8.10 + 1.8.11-SNAPSHOT jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From 619bda469c4ba067931d2c6e814de307a811691c Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 12 Jun 2014 10:20:47 +0200 Subject: [PATCH 310/701] Make NPE message more explicit when passing a null hostname to avoid proxy, close #560, close #561 --- src/main/java/com/ning/http/util/ProxyUtils.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/ning/http/util/ProxyUtils.java b/src/main/java/com/ning/http/util/ProxyUtils.java index a9c8f7b0cd..eb3ee711d8 100644 --- a/src/main/java/com/ning/http/util/ProxyUtils.java +++ b/src/main/java/com/ning/http/util/ProxyUtils.java @@ -108,12 +108,15 @@ public static boolean avoidProxy(final ProxyServer proxyServer, final Request re * See http://download.oracle.com/javase/1.4.2/docs/guide/net/properties.html * * @param proxyServer - * @param target the hostname + * @param hostname the hostname * @return true if we have to avoid proxy use (obeying non-proxy hosts settings), false otherwise. */ - public static boolean avoidProxy(final ProxyServer proxyServer, final String target) { + public static boolean avoidProxy(final ProxyServer proxyServer, final String hostname) { if (proxyServer != null) { - final String targetHost = target.toLowerCase(Locale.ENGLISH); + if (hostname == null) + throw new NullPointerException("hostname"); + + final String targetHost = hostname.toLowerCase(Locale.ENGLISH); List nonProxyHosts = proxyServer.getNonProxyHosts(); From a1f779fb842d65f66408179b15c768de3a8ed3c8 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 12 Jun 2014 12:38:02 +0200 Subject: [PATCH 311/701] minor clean up, properly use NPE instead of IAE --- .../com/ning/http/client/AsyncHttpClient.java | 16 ++++++++-------- .../com/ning/http/client/RequestBuilder.java | 16 ++++++++-------- .../ning/http/client/RequestBuilderBase.java | 16 ++++++++-------- .../http/client/SimpleAsyncHttpClient.java | 16 ++++++++-------- .../client/generators/FileBodyGenerator.java | 10 ++++------ .../providers/netty/BodyChunkedInput.java | 5 ++--- .../providers/netty/BodyFileRegion.java | 5 ++--- .../com/ning/http/multipart/FilePart.java | 5 ++--- .../http/multipart/MultipartEncodingUtil.java | 10 ++++------ .../multipart/MultipartRequestEntity.java | 5 ++--- .../java/com/ning/http/multipart/Part.java | 19 +++++++------------ .../com/ning/http/multipart/PartBase.java | 5 ++--- .../com/ning/http/multipart/StringPart.java | 5 ++--- .../java/com/ning/http/util/DateUtil.java | 9 ++++----- 14 files changed, 63 insertions(+), 79 deletions(-) diff --git a/src/main/java/com/ning/http/client/AsyncHttpClient.java b/src/main/java/com/ning/http/client/AsyncHttpClient.java index 10eb77d984..dba9147698 100755 --- a/src/main/java/com/ning/http/client/AsyncHttpClient.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClient.java @@ -234,7 +234,7 @@ public ListenableFuture execute() throws IOException { // access these methods - see Clojure tickets 126 and 259 @Override - public BoundRequestBuilder addBodyPart(Part part) throws IllegalArgumentException { + public BoundRequestBuilder addBodyPart(Part part) { return super.addBodyPart(part); } @@ -249,7 +249,7 @@ public BoundRequestBuilder addHeader(String name, String value) { } @Override - public BoundRequestBuilder addParameter(String key, String value) throws IllegalArgumentException { + public BoundRequestBuilder addParameter(String key, String value) { return super.addParameter(key, value); } @@ -264,12 +264,12 @@ public Request build() { } @Override - public BoundRequestBuilder setBody(byte[] data) throws IllegalArgumentException { + public BoundRequestBuilder setBody(byte[] data) { return super.setBody(data); } @Override - public BoundRequestBuilder setBody(EntityWriter dataWriter, long length) throws IllegalArgumentException { + public BoundRequestBuilder setBody(EntityWriter dataWriter, long length) { return super.setBody(dataWriter, length); } @@ -279,12 +279,12 @@ public BoundRequestBuilder setBody(EntityWriter dataWriter) { } @Override - public BoundRequestBuilder setBody(InputStream stream) throws IllegalArgumentException { + public BoundRequestBuilder setBody(InputStream stream) { return super.setBody(stream); } @Override - public BoundRequestBuilder setBody(String data) throws IllegalArgumentException { + public BoundRequestBuilder setBody(String data) { return super.setBody(data); } @@ -304,12 +304,12 @@ public BoundRequestBuilder setHeaders(Map> headers) { } @Override - public BoundRequestBuilder setParameters(Map> parameters) throws IllegalArgumentException { + public BoundRequestBuilder setParameters(Map> parameters) { return super.setParameters(parameters); } @Override - public BoundRequestBuilder setParameters(FluentStringsMap parameters) throws IllegalArgumentException { + public BoundRequestBuilder setParameters(FluentStringsMap parameters) { return super.setParameters(parameters); } diff --git a/src/main/java/com/ning/http/client/RequestBuilder.java b/src/main/java/com/ning/http/client/RequestBuilder.java index 32d8ef5357..47bbd5fdf8 100644 --- a/src/main/java/com/ning/http/client/RequestBuilder.java +++ b/src/main/java/com/ning/http/client/RequestBuilder.java @@ -50,7 +50,7 @@ public RequestBuilder(Request prototype) { // access these methods - see Clojure tickets 126 and 259 @Override - public RequestBuilder addBodyPart(Part part) throws IllegalArgumentException { + public RequestBuilder addBodyPart(Part part) { return super.addBodyPart(part); } @@ -65,7 +65,7 @@ public RequestBuilder addHeader(String name, String value) { } @Override - public RequestBuilder addParameter(String key, String value) throws IllegalArgumentException { + public RequestBuilder addParameter(String key, String value) { return super.addParameter(key, value); } @@ -85,12 +85,12 @@ public Request build() { } @Override - public RequestBuilder setBody(byte[] data) throws IllegalArgumentException { + public RequestBuilder setBody(byte[] data) { return super.setBody(data); } @Override - public RequestBuilder setBody(EntityWriter dataWriter, long length) throws IllegalArgumentException { + public RequestBuilder setBody(EntityWriter dataWriter, long length) { return super.setBody(dataWriter, length); } @@ -111,12 +111,12 @@ public RequestBuilder setBody(EntityWriter dataWriter) { */ @Override @Deprecated - public RequestBuilder setBody(InputStream stream) throws IllegalArgumentException { + public RequestBuilder setBody(InputStream stream) { return super.setBody(stream); } @Override - public RequestBuilder setBody(String data) throws IllegalArgumentException { + public RequestBuilder setBody(String data) { return super.setBody(data); } @@ -136,12 +136,12 @@ public RequestBuilder setHeaders(Map> headers) { } @Override - public RequestBuilder setParameters(Map> parameters) throws IllegalArgumentException { + public RequestBuilder setParameters(Map> parameters) { return super.setParameters(parameters); } @Override - public RequestBuilder setParameters(FluentStringsMap parameters) throws IllegalArgumentException { + public RequestBuilder setParameters(FluentStringsMap parameters) { return super.setParameters(parameters); } diff --git a/src/main/java/com/ning/http/client/RequestBuilderBase.java b/src/main/java/com/ning/http/client/RequestBuilderBase.java index 748f893a9c..89a6fba3cf 100644 --- a/src/main/java/com/ning/http/client/RequestBuilderBase.java +++ b/src/main/java/com/ning/http/client/RequestBuilderBase.java @@ -490,7 +490,7 @@ public T setBody(File file) { return derived.cast(this); } - public T setBody(byte[] data) throws IllegalArgumentException { + public T setBody(byte[] data) { resetParameters(); resetNonMultipartData(); resetMultipartData(); @@ -498,7 +498,7 @@ public T setBody(byte[] data) throws IllegalArgumentException { return derived.cast(this); } - public T setBody(String data) throws IllegalArgumentException { + public T setBody(String data) { resetParameters(); resetNonMultipartData(); resetMultipartData(); @@ -506,7 +506,7 @@ public T setBody(String data) throws IllegalArgumentException { return derived.cast(this); } - public T setBody(InputStream stream) throws IllegalArgumentException { + public T setBody(InputStream stream) { resetParameters(); resetNonMultipartData(); resetMultipartData(); @@ -518,7 +518,7 @@ public T setBody(EntityWriter dataWriter) { return setBody(dataWriter, -1); } - public T setBody(EntityWriter dataWriter, long length) throws IllegalArgumentException { + public T setBody(EntityWriter dataWriter, long length) { resetParameters(); resetNonMultipartData(); resetMultipartData(); @@ -549,7 +549,7 @@ public T setQueryParameters(FluentStringsMap parameters) { return derived.cast(this); } - public T addParameter(String key, String value) throws IllegalArgumentException { + public T addParameter(String key, String value) { resetNonMultipartData(); resetMultipartData(); if (request.params == null) { @@ -559,21 +559,21 @@ public T addParameter(String key, String value) throws IllegalArgumentException return derived.cast(this); } - public T setParameters(FluentStringsMap parameters) throws IllegalArgumentException { + public T setParameters(FluentStringsMap parameters) { resetNonMultipartData(); resetMultipartData(); request.params = new FluentStringsMap(parameters); return derived.cast(this); } - public T setParameters(Map> parameters) throws IllegalArgumentException { + public T setParameters(Map> parameters) { resetNonMultipartData(); resetMultipartData(); request.params = new FluentStringsMap(parameters); return derived.cast(this); } - public T addBodyPart(Part part) throws IllegalArgumentException { + public T addBodyPart(Part part) { resetParameters(); resetNonMultipartData(); if (request.parts == null) { diff --git a/src/main/java/com/ning/http/client/SimpleAsyncHttpClient.java b/src/main/java/com/ning/http/client/SimpleAsyncHttpClient.java index 711dbdf269..09b371edfe 100644 --- a/src/main/java/com/ning/http/client/SimpleAsyncHttpClient.java +++ b/src/main/java/com/ning/http/client/SimpleAsyncHttpClient.java @@ -367,9 +367,9 @@ public interface DerivedBuilder { DerivedBuilder setUrl(String url); - DerivedBuilder setParameters(FluentStringsMap parameters) throws IllegalArgumentException; + DerivedBuilder setParameters(FluentStringsMap parameters); - DerivedBuilder setParameters(Map> parameters) throws IllegalArgumentException; + DerivedBuilder setParameters(Map> parameters); DerivedBuilder setHeaders(Map> headers); @@ -379,13 +379,13 @@ public interface DerivedBuilder { DerivedBuilder addQueryParameter(String name, String value); - DerivedBuilder addParameter(String key, String value) throws IllegalArgumentException; + DerivedBuilder addParameter(String key, String value); DerivedBuilder addHeader(String name, String value); DerivedBuilder addCookie(Cookie cookie); - DerivedBuilder addBodyPart(Part part) throws IllegalArgumentException; + DerivedBuilder addBodyPart(Part part); DerivedBuilder setResumableDownload(boolean resume); @@ -422,7 +422,7 @@ private Builder(SimpleAsyncHttpClient client) { this.listener = client.listener; } - public Builder addBodyPart(Part part) throws IllegalArgumentException { + public Builder addBodyPart(Part part) { requestBuilder.addBodyPart(part); return this; } @@ -437,7 +437,7 @@ public Builder addHeader(String name, String value) { return this; } - public Builder addParameter(String key, String value) throws IllegalArgumentException { + public Builder addParameter(String key, String value) { requestBuilder.addParameter(key, value); return this; } @@ -462,12 +462,12 @@ public Builder setHeaders(Map> headers) { return this; } - public Builder setParameters(Map> parameters) throws IllegalArgumentException { + public Builder setParameters(Map> parameters) { requestBuilder.setParameters(parameters); return this; } - public Builder setParameters(FluentStringsMap parameters) throws IllegalArgumentException { + public Builder setParameters(FluentStringsMap parameters) { requestBuilder.setParameters(parameters); return this; } diff --git a/src/main/java/com/ning/http/client/generators/FileBodyGenerator.java b/src/main/java/com/ning/http/client/generators/FileBodyGenerator.java index c1ff9ef88a..4c81a7271e 100644 --- a/src/main/java/com/ning/http/client/generators/FileBodyGenerator.java +++ b/src/main/java/com/ning/http/client/generators/FileBodyGenerator.java @@ -33,18 +33,16 @@ public class FileBodyGenerator private final long regionLength; public FileBodyGenerator(File file) { - if (file == null) { - throw new IllegalArgumentException("no file specified"); - } + if (file == null) + throw new NullPointerException("file"); this.file = file; this.regionLength = file.length(); this.regionSeek = 0; } public FileBodyGenerator(File file, long regionSeek, long regionLength) { - if (file == null) { - throw new IllegalArgumentException("no file specified"); - } + if (file == null) + throw new NullPointerException("file"); this.file = file; this.regionLength = regionLength; this.regionSeek = regionSeek; 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 1cf8282b2c..2b0003d21f 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 @@ -32,9 +32,8 @@ class BodyChunkedInput implements ChunkedInput { private boolean endOfInput; public BodyChunkedInput(Body body) { - if (body == null) { - throw new IllegalArgumentException("no body specified"); - } + if (body == null) + throw new NullPointerException("body"); this.body = body; contentLength = (int) body.getContentLength(); if (contentLength <= 0) diff --git a/src/main/java/com/ning/http/client/providers/netty/BodyFileRegion.java b/src/main/java/com/ning/http/client/providers/netty/BodyFileRegion.java index 9679ba43f1..267051878c 100644 --- a/src/main/java/com/ning/http/client/providers/netty/BodyFileRegion.java +++ b/src/main/java/com/ning/http/client/providers/netty/BodyFileRegion.java @@ -27,9 +27,8 @@ class BodyFileRegion private final RandomAccessBody body; public BodyFileRegion(RandomAccessBody body) { - if (body == null) { - throw new IllegalArgumentException("no body specified"); - } + if (body == null) + throw new NullPointerException("body"); this.body = body; } diff --git a/src/main/java/com/ning/http/multipart/FilePart.java b/src/main/java/com/ning/http/multipart/FilePart.java index d43aac9e4e..aef2c64c8d 100644 --- a/src/main/java/com/ning/http/multipart/FilePart.java +++ b/src/main/java/com/ning/http/multipart/FilePart.java @@ -64,9 +64,8 @@ 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, DEFAULT_TRANSFER_ENCODING, contentId); - if (partSource == null) { - throw new IllegalArgumentException("Source may not be null"); - } + if (partSource == null) + throw new NullPointerException("parSource"); this.source = partSource; } diff --git a/src/main/java/com/ning/http/multipart/MultipartEncodingUtil.java b/src/main/java/com/ning/http/multipart/MultipartEncodingUtil.java index 1185100ec4..d249babae3 100644 --- a/src/main/java/com/ning/http/multipart/MultipartEncodingUtil.java +++ b/src/main/java/com/ning/http/multipart/MultipartEncodingUtil.java @@ -33,9 +33,8 @@ public static byte[] getAsciiBytes(String data) { } public static String getAsciiString(final byte[] data) { - if (data == null) { - throw new IllegalArgumentException("Parameter may not be null"); - } + if (data == null) + throw new NullPointerException("data"); try { return new String(data, "US-ASCII"); @@ -46,9 +45,8 @@ public static String getAsciiString(final byte[] data) { public static byte[] getBytes(final String data, String charset) { - if (data == null) { - throw new IllegalArgumentException("data may not be null"); - } + if (data == null) + throw new NullPointerException("data"); if (charset == null || charset.length() == 0) { throw new IllegalArgumentException("charset may not be null or empty"); diff --git a/src/main/java/com/ning/http/multipart/MultipartRequestEntity.java b/src/main/java/com/ning/http/multipart/MultipartRequestEntity.java index 87531211ee..66e43174be 100644 --- a/src/main/java/com/ning/http/multipart/MultipartRequestEntity.java +++ b/src/main/java/com/ning/http/multipart/MultipartRequestEntity.java @@ -70,9 +70,8 @@ public static byte[] generateMultipartBoundary() { * @param parts The parts to include. */ public MultipartRequestEntity(Part[] parts, FluentCaseInsensitiveStringsMap requestHeaders) { - if (parts == null) { - throw new IllegalArgumentException("parts cannot be null"); - } + if (parts == null) + throw new NullPointerException("parts"); this.parts = parts; String contentTypeHeader = requestHeaders.getFirstValue("Content-Type"); if (isNonEmpty(contentTypeHeader)) { diff --git a/src/main/java/com/ning/http/multipart/Part.java b/src/main/java/com/ning/http/multipart/Part.java index c66da43428..99e0a0047d 100644 --- a/src/main/java/com/ning/http/multipart/Part.java +++ b/src/main/java/com/ning/http/multipart/Part.java @@ -439,12 +439,10 @@ public String toString() { */ public static void sendParts(OutputStream out, Part[] parts, byte[] partBoundary) throws IOException { - if (parts == null) { - throw new IllegalArgumentException("Parts may not be null"); - } - if (partBoundary == null || partBoundary.length == 0) { + if (parts == null) + throw new NullPointerException("partsl"); + if (partBoundary == null || partBoundary.length == 0) throw new IllegalArgumentException("partBoundary may not be empty"); - } for (Part part : parts) { part.send(out, partBoundary); } @@ -475,10 +473,8 @@ public static void sendMessageEnd(OutputStream out, byte[] partBoundary) throws * @since N/A */ public static void sendPart(OutputStream out, Part part, byte[] partBoundary) throws IOException { - - if (part == null) { - throw new IllegalArgumentException("Parts may not be null"); - } + if (part == null) + throw new NullPointerException("parts"); part.send(out, partBoundary); } @@ -495,9 +491,8 @@ public static void sendPart(OutputStream out, Part part, byte[] partBoundary) th public static long getLengthOfParts(Part[] parts, byte[] partBoundary) { try { - if (parts == null) { - throw new IllegalArgumentException("Parts may not be null"); - } + if (parts == null) + throw new NullPointerException("parts"); long total = 0; for (Part part : parts) { long l = part.length(partBoundary); diff --git a/src/main/java/com/ning/http/multipart/PartBase.java b/src/main/java/com/ning/http/multipart/PartBase.java index 32a3a256eb..67a75a3ab6 100644 --- a/src/main/java/com/ning/http/multipart/PartBase.java +++ b/src/main/java/com/ning/http/multipart/PartBase.java @@ -120,9 +120,8 @@ public void setContentType(String contentType) { * @param name */ public void setName(String name) { - if (name == null) { - throw new IllegalArgumentException("Name must not be null"); - } + if (name == null) + throw new NullPointerException("name"); this.name = name; } diff --git a/src/main/java/com/ning/http/multipart/StringPart.java b/src/main/java/com/ning/http/multipart/StringPart.java index b9bb149bd9..c2c6765f62 100644 --- a/src/main/java/com/ning/http/multipart/StringPart.java +++ b/src/main/java/com/ning/http/multipart/StringPart.java @@ -60,9 +60,8 @@ public class StringPart extends PartBase { public StringPart(String name, String value, String charset, String contentId) { 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"); - } + if (value == null) + throw new NullPointerException("value"); if (value.indexOf(0) != -1) { // See RFC 2048, 2.8. "8bit Data" throw new IllegalArgumentException("NULs may not be present in string parts"); diff --git a/src/main/java/com/ning/http/util/DateUtil.java b/src/main/java/com/ning/http/util/DateUtil.java index 8e5e3fe6fe..03ef393ad3 100644 --- a/src/main/java/com/ning/http/util/DateUtil.java +++ b/src/main/java/com/ning/http/util/DateUtil.java @@ -135,9 +135,8 @@ public static Date parseDate( Date startDate ) throws DateParseException { - if (dateValue == null) { - throw new IllegalArgumentException("dateValue is null"); - } + if (dateValue == null) + throw new NullPointerException("dateValue"); if (dateFormats == null) { dateFormats = DEFAULT_PATTERNS; } @@ -199,8 +198,8 @@ public static String formatDate(Date date) { * @see java.text.SimpleDateFormat */ public static String formatDate(Date date, String pattern) { - if (date == null) throw new IllegalArgumentException("date is null"); - if (pattern == null) throw new IllegalArgumentException("pattern is null"); + if (date == null) throw new NullPointerException("date"); + if (pattern == null) throw new NullPointerException("pattern"); SimpleDateFormat formatter = new SimpleDateFormat(pattern, Locale.US); formatter.setTimeZone(GMT); From 7a6145340904231bedfc82cad88dc43d3d233a48 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 12 Jun 2014 12:42:01 +0200 Subject: [PATCH 312/701] RequestBuilder.setUrl shouldn't accept an URI without a host, close #571 --- .../java/com/ning/http/client/RequestBuilderBase.java | 4 +++- .../ning/http/client/async/AsyncProvidersBasicTest.java | 9 ++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/ning/http/client/RequestBuilderBase.java b/src/main/java/com/ning/http/client/RequestBuilderBase.java index 89a6fba3cf..2ebf744578 100644 --- a/src/main/java/com/ning/http/client/RequestBuilderBase.java +++ b/src/main/java/com/ning/http/client/RequestBuilderBase.java @@ -379,8 +379,10 @@ public T setUrl(String url) { } public T setURI(URI uri) { + if (uri.getHost() == null) + throw new NullPointerException("uri.host"); if (uri.getPath() == null) - throw new IllegalArgumentException("Unsupported uri format: " + uri); + throw new NullPointerException("uri.path"); 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 b181a447ef..933dd21cae 100755 --- a/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java +++ b/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java @@ -393,14 +393,13 @@ public void onThrowable(Throwable t) { } } - @Test(groups = { "online", "default_provider", "async" }) + @Test(groups = { "online", "default_provider", "async" }, expectedExceptions = { NullPointerException.class }) public void asyncNullSchemeTest() throws Throwable { AsyncHttpClient client = getAsyncHttpClient(null); try { client.prepareGet("www.sun.com").execute(); - Assert.fail(); - } catch (IllegalArgumentException ex) { - Assert.assertTrue(true); + } finally { + client.close();; } } @@ -1654,7 +1653,7 @@ protected String getBrokenTargetUrl() { return String.format("http:127.0.0.1:%d/foo/test", port1); } - @Test(groups = { "standalone", "default_provider" }, expectedExceptions = { IllegalArgumentException.class }) + @Test(groups = { "standalone", "default_provider" }, expectedExceptions = { NullPointerException.class }) public void invalidUri() throws Exception { AsyncHttpClient client = getAsyncHttpClient(null); try { From 16b1c2d67b605fdeb83c56506cb86e3f61564bcc Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 12 Jun 2014 13:19:16 +0200 Subject: [PATCH 313/701] Minor ProxyUtils.matchNonProxyHost clean up, still very incomplete --- .../java/com/ning/http/util/ProxyUtils.java | 36 ++++++++++--------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/src/main/java/com/ning/http/util/ProxyUtils.java b/src/main/java/com/ning/http/util/ProxyUtils.java index eb3ee711d8..d7e821193c 100644 --- a/src/main/java/com/ning/http/util/ProxyUtils.java +++ b/src/main/java/com/ning/http/util/ProxyUtils.java @@ -35,7 +35,7 @@ * * @author cstamas */ -public class ProxyUtils { +public final class ProxyUtils { private final static Logger log = LoggerFactory.getLogger(ProxyUtils.class); @@ -71,6 +71,9 @@ public class ProxyUtils { */ public static final String PROXY_PASSWORD = PROPERTY_PREFIX + "password"; + private ProxyUtils() { + } + /** * @param config the global config * @param request the request @@ -88,19 +91,25 @@ public static ProxyServer getProxyServer(AsyncHttpClientConfig config, Request r } /** - * 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 - * should avoid to use it. Simple hostname pattern matching using "*" are supported, but only as prefixes. - * See http://download.oracle.com/javase/1.4.2/docs/guide/net/properties.html - * - * @param proxyServer - * @param request - * @return true if we have to avoid proxy use (obeying non-proxy hosts settings), false otherwise. + * @see #avoidProxy(ProxyServer, String) */ public static boolean avoidProxy(final ProxyServer proxyServer, final Request request) { return avoidProxy(proxyServer, AsyncHttpProviderUtils.getHost(request.getOriginalURI())); } + private static boolean matchNonProxyHost(String targetHost, String nonProxyHost) { + + if (nonProxyHost.length() > 1) { + if (nonProxyHost.charAt(0) == '*') + return targetHost.regionMatches(true, targetHost.length() - nonProxyHost.length() + 1, nonProxyHost, 1, + nonProxyHost.length() - 1); + else if (nonProxyHost.charAt(nonProxyHost.length() - 1) == '*') + return targetHost.regionMatches(true, 0, nonProxyHost, 0, nonProxyHost.length() - 1); + } + + return nonProxyHost.equalsIgnoreCase(targetHost); + } + /** * 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 @@ -122,15 +131,8 @@ public static boolean avoidProxy(final ProxyServer proxyServer, final String hos if (nonProxyHosts != null) { for (String nonProxyHost : nonProxyHosts) { - 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))) { + if (matchNonProxyHost(targetHost, nonProxyHost)) return true; - } else if (nonProxyHost.equalsIgnoreCase(targetHost)) { - return true; - } } } From 77e7a42430c680b9dc2faeb28d7afb3bde18e72f Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 12 Jun 2014 13:24:29 +0200 Subject: [PATCH 314/701] minor clean up --- src/main/java/com/ning/http/util/ProxyUtils.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/main/java/com/ning/http/util/ProxyUtils.java b/src/main/java/com/ning/http/util/ProxyUtils.java index d7e821193c..4b6e3eedc4 100644 --- a/src/main/java/com/ning/http/util/ProxyUtils.java +++ b/src/main/java/com/ning/http/util/ProxyUtils.java @@ -24,7 +24,6 @@ import java.net.ProxySelector; import java.net.URI; import java.util.List; -import java.util.Locale; import java.util.Properties; import org.slf4j.Logger; @@ -125,13 +124,11 @@ public static boolean avoidProxy(final ProxyServer proxyServer, final String hos if (hostname == null) throw new NullPointerException("hostname"); - final String targetHost = hostname.toLowerCase(Locale.ENGLISH); - List nonProxyHosts = proxyServer.getNonProxyHosts(); if (nonProxyHosts != null) { for (String nonProxyHost : nonProxyHosts) { - if (matchNonProxyHost(targetHost, nonProxyHost)) + if (matchNonProxyHost(hostname, nonProxyHost)) return true; } } From 8d9a8ba1d02901f169ee9e7ab5406dcf9282a430 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 16 Jun 2014 15:12:53 +0200 Subject: [PATCH 315/701] [maven-release-plugin] prepare release async-http-client-1.8.11 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 2e4abceb26..a5d5985d99 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.8.11-SNAPSHOT + 1.8.11 jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From 28c83d49e7a51aa7b91f252d4292b9b326f9cfd1 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 16 Jun 2014 15:12:57 +0200 Subject: [PATCH 316/701] [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 a5d5985d99..45db7b2fc2 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.8.11 + 1.8.12-SNAPSHOT jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From 4845ce2b7ff771f9a97d5c528d5a36af275437f2 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 16 Jun 2014 15:47:09 +0200 Subject: [PATCH 317/701] remove comment --- .../ning/http/client/providers/netty/NettyAsyncHttpProvider.java | 1 - 1 file changed, 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 fb75198aa5..1b99f556d5 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 @@ -1536,7 +1536,6 @@ private void markAsDone(final NettyResponseFuture future, final ChannelHandle log.debug(t.getMessage(), t); } - // FIXME why isReadable and not isConnected if (!future.getKeepAlive() || !ctx.getChannel().isReadable()) { closeChannel(ctx); } From 815b7a2ca1d628ca66cb5d21eeb3e0fcb6a50311 Mon Sep 17 00:00:00 2001 From: oleksiys Date: Tue, 17 Jun 2014 01:29:33 -0700 Subject: [PATCH 318/701] [1.8.x] + fix issue #1691 https://java.net/jira/browse/GRIZZLY-1691 "Support RFC 7238, HTTP Status Code "308 Permanent Redirect"" --- pom.xml | 2 +- .../providers/grizzly/GrizzlyAsyncHttpProvider.java | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index 45db7b2fc2..a8f3659e8d 100644 --- a/pom.xml +++ b/pom.xml @@ -591,7 +591,7 @@ com/ning/http/client/providers/grizzly/*.java com/ning/http/client/async/grizzly/*.java com.ning.http.client.providers.grizzly - 2.3.13 + 2.3.14 1.5 1.5 2.12 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 9cd861b909..cad6b22449 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 @@ -1127,7 +1127,8 @@ private void addQueryString(final Request request, private static final class AsyncHttpClientEventFilter extends HttpClientFilter { - private final Map HANDLER_MAP = new HashMap(); + private final Map HANDLER_MAP = + new HashMap(); private final GrizzlyAsyncHttpProvider provider; @@ -1145,8 +1146,12 @@ private static final class AsyncHttpClientEventFilter extends HttpClientFilter { RedirectHandler.INSTANCE); HANDLER_MAP.put(HttpStatus.FOUND_302.getStatusCode(), RedirectHandler.INSTANCE); + HANDLER_MAP.put(HttpStatus.SEE_OTHER_303.getStatusCode(), + RedirectHandler.INSTANCE); HANDLER_MAP.put(HttpStatus.TEMPORARY_REDIRECT_307.getStatusCode(), RedirectHandler.INSTANCE); + HANDLER_MAP.put(HttpStatus.PERMANENT_REDIRECT_308.getStatusCode(), + RedirectHandler.INSTANCE); } @@ -1557,7 +1562,8 @@ private static boolean isRedirect(final int status) { return HttpStatus.MOVED_PERMANENTLY_301.statusMatches(status) || HttpStatus.FOUND_302.statusMatches(status) || HttpStatus.SEE_OTHER_303.statusMatches(status) - || HttpStatus.TEMPORARY_REDIRECT_307.statusMatches(status); + || HttpStatus.TEMPORARY_REDIRECT_307.statusMatches(status) + || HttpStatus.PERMANENT_REDIRECT_308.statusMatches(status); } From 91ea232210edf7aba9f67085787c9e094690bf38 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 18 Jun 2014 09:45:07 +0200 Subject: [PATCH 319/701] InputStream shouldn't be fully read, this is streaming! close #576 --- .../providers/netty/NettyAsyncHttpProvider.java | 11 +++++------ 1 file changed, 5 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 1b99f556d5..c45730dc25 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 @@ -487,6 +487,11 @@ protected final void writeRequest(final Channel channel, final AsyncHttpClie Body body = null; if (!nettyRequest.getMethod().equals(HttpMethod.CONNECT)) { BodyGenerator bg = future.getRequest().getBodyGenerator(); + + if (bg == null && future.getRequest().getStreamData() != null) { + bg = new InputStreamBodyGenerator(future.getRequest().getStreamData()); + } + if (bg != null) { // Netty issue with chunking. if (bg instanceof InputStreamBodyGenerator) { @@ -834,12 +839,6 @@ else if (uri.getRawQuery() != null) 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); - int length = lengthWrapper[0]; - nettyRequest.setHeader(HttpHeaders.Names.CONTENT_LENGTH, String.valueOf(length)); - nettyRequest.setContent(ChannelBuffers.wrappedBuffer(bytes, 0, length)); } else if (isNonEmpty(request.getParams())) { StringBuilder sb = new StringBuilder(); for (final Entry> paramEntry : request.getParams()) { From cced1d4e9b6016fadb38049721d519898b0d08cb Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 20 Jun 2014 14:05:44 +0200 Subject: [PATCH 320/701] Fixed omit query, backport #578 --- .../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 c45730dc25..994e77e280 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 @@ -2035,7 +2035,7 @@ private final String computeRealmURI(Realm realm, URI requestURI) throws URISynt return requestURI.toString(); } } else { - if (realm.isOmitQuery() && MiscUtil.isNonEmpty(requestURI.getQuery())) { + if (realm.isOmitQuery() || !MiscUtil.isNonEmpty(requestURI.getQuery())) { return requestURI.getPath(); } else { return requestURI.getPath() + "?" + requestURI.getQuery(); From c86f415bcd61b1566148e53572346689ec8babaf Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 1 Jul 2014 10:50:58 +0200 Subject: [PATCH 321/701] Fix Fluent(CaseInsensitive)StringsMap.add javadocs, backport #581 --- .../ning/http/client/FluentCaseInsensitiveStringsMap.java | 3 +-- src/main/java/com/ning/http/client/FluentStringsMap.java | 6 ++---- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/ning/http/client/FluentCaseInsensitiveStringsMap.java b/src/main/java/com/ning/http/client/FluentCaseInsensitiveStringsMap.java index 16ad85572a..77d5e97206 100644 --- a/src/main/java/com/ning/http/client/FluentCaseInsensitiveStringsMap.java +++ b/src/main/java/com/ning/http/client/FluentCaseInsensitiveStringsMap.java @@ -64,8 +64,7 @@ public FluentCaseInsensitiveStringsMap(Map> src) { * Adds the specified values and returns this object. * * @param key The key - * @param values The value(s); if null then this method has no effect. Use the empty string to - * generate an empty value + * @param values The value(s); if the array is null then this method has no effect. Individual null values are turned into empty strings * @return This object */ public FluentCaseInsensitiveStringsMap add(String key, String... values) { diff --git a/src/main/java/com/ning/http/client/FluentStringsMap.java b/src/main/java/com/ning/http/client/FluentStringsMap.java index 22a2ccb6bb..a7282137a6 100644 --- a/src/main/java/com/ning/http/client/FluentStringsMap.java +++ b/src/main/java/com/ning/http/client/FluentStringsMap.java @@ -58,8 +58,7 @@ public FluentStringsMap(Map> src) { * Adds the specified values and returns this object. * * @param key The key - * @param values The value(s); if null then this method has no effect. Use the empty string to - * generate an empty value + * @param values The value(s); if the array is null then this method has no effect * @return This object */ public FluentStringsMap add(String key, String... values) { @@ -73,8 +72,7 @@ public FluentStringsMap add(String key, String... values) { * Adds the specified values and returns this object. * * @param key The key - * @param values The value(s); if null then this method has no effect. Use an empty collection - * to generate an empty value + * @param values The value(s); if the array is null then this method has no effect * @return This object */ public FluentStringsMap add(String key, Collection values) { From 23fbae00b1b2fd475b0f547dea6796c7f2a97c8f Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 1 Jul 2014 10:52:36 +0200 Subject: [PATCH 322/701] Optimize Fluent(CaseInsensitive)StringsMap for single value, backport #580 --- .../FluentCaseInsensitiveStringsMap.java | 20 +++++++++++++++++++ .../ning/http/client/FluentStringsMap.java | 13 ++++++++++++ 2 files changed, 33 insertions(+) diff --git a/src/main/java/com/ning/http/client/FluentCaseInsensitiveStringsMap.java b/src/main/java/com/ning/http/client/FluentCaseInsensitiveStringsMap.java index 77d5e97206..2b634011a0 100644 --- a/src/main/java/com/ning/http/client/FluentCaseInsensitiveStringsMap.java +++ b/src/main/java/com/ning/http/client/FluentCaseInsensitiveStringsMap.java @@ -60,6 +60,26 @@ public FluentCaseInsensitiveStringsMap(Map> src) { } } + public FluentCaseInsensitiveStringsMap add(String key, String value) { + if (key != null) { + String lcKey = key.toLowerCase(Locale.ENGLISH); + String realKey = keyLookup.get(lcKey); + + List curValues = null; + if (realKey == null) { + keyLookup.put(lcKey, key); + curValues = new ArrayList(); + values.put(key, curValues); + } else { + curValues = values.get(realKey); + } + + String nonNullValue = value != null? value : ""; + curValues.add(nonNullValue); + } + return this; + } + /** * Adds the specified values and returns this object. * diff --git a/src/main/java/com/ning/http/client/FluentStringsMap.java b/src/main/java/com/ning/http/client/FluentStringsMap.java index a7282137a6..6df70f018d 100644 --- a/src/main/java/com/ning/http/client/FluentStringsMap.java +++ b/src/main/java/com/ning/http/client/FluentStringsMap.java @@ -54,6 +54,19 @@ public FluentStringsMap(Map> src) { } } + public FluentStringsMap add(String key, String value) { + if (key != null) { + List curValues = values.get(key); + + if (curValues == null) { + curValues = new ArrayList(1); + values.put(key, curValues); + } + curValues.add(value); + } + return this; + } + /** * Adds the specified values and returns this object. * From 7fc54eec2981940d9125070de0a4adb9cc54265c Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 1 Jul 2014 11:11:54 +0200 Subject: [PATCH 323/701] [maven-release-plugin] prepare release async-http-client-1.8.12 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index a8f3659e8d..26a2c2e649 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.8.12-SNAPSHOT + 1.8.12 jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From cdeb468d47ae326447c32ff08d28e33cfefc2216 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 1 Jul 2014 11:11:58 +0200 Subject: [PATCH 324/701] [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 26a2c2e649..3f51f1ef8e 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.8.12 + 1.8.13-SNAPSHOT jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From 8a67808c0d5a17133f422ef497e26da3631d75e4 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 1 Jul 2014 16:41:50 +0200 Subject: [PATCH 325/701] Minor clean up --- src/main/java/com/ning/http/client/ProxyServer.java | 2 +- .../com/ning/http/client/RequestBuilderBase.java | 2 +- .../providers/apache/ApacheAsyncHttpProvider.java | 4 ++-- .../client/providers/jdk/JDKAsyncHttpProvider.java | 4 ++-- .../providers/netty/NettyAsyncHttpProvider.java | 8 ++------ .../com/ning/http/util/AsyncHttpProviderUtils.java | 12 +++--------- 6 files changed, 11 insertions(+), 21 deletions(-) diff --git a/src/main/java/com/ning/http/client/ProxyServer.java b/src/main/java/com/ning/http/client/ProxyServer.java index 784ba97e44..dc037820d9 100644 --- a/src/main/java/com/ning/http/client/ProxyServer.java +++ b/src/main/java/com/ning/http/client/ProxyServer.java @@ -63,7 +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()); + uri = AsyncHttpProviderUtils.createNonEmptyPathURI(toString()); } public ProxyServer(final String host, final int port, String principal, String password) { diff --git a/src/main/java/com/ning/http/client/RequestBuilderBase.java b/src/main/java/com/ning/http/client/RequestBuilderBase.java index 2ebf744578..654182ff06 100644 --- a/src/main/java/com/ning/http/client/RequestBuilderBase.java +++ b/src/main/java/com/ning/http/client/RequestBuilderBase.java @@ -298,7 +298,7 @@ public File getFile() { } public boolean isRedirectEnabled() { - return (followRedirects != null && followRedirects); + return followRedirects != null && followRedirects; } public boolean isRedirectOverrideSet() { 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 319deac4d3..27d6738353 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 @@ -465,9 +465,9 @@ public T call() { try { URI uri = null; try { - uri = AsyncHttpProviderUtils.createUri(request.getRawUrl()); + uri = AsyncHttpProviderUtils.createNonEmptyPathURI(request.getRawUrl()); } catch (IllegalArgumentException u) { - uri = AsyncHttpProviderUtils.createUri(request.getUrl()); + uri = AsyncHttpProviderUtils.createNonEmptyPathURI(request.getUrl()); } int delay = requestTimeout(config, future.getRequest().getPerRequestConfig()); 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 eb665e5ede..06e898b4d6 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 @@ -231,9 +231,9 @@ public T call() throws Exception { URI uri = null; // Encoding with URLConnection is a bit bogus so we need to try both way before setting it try { - uri = AsyncHttpProviderUtils.createUri(request.getRawUrl()); + uri = AsyncHttpProviderUtils.createNonEmptyPathURI(request.getRawUrl()); } catch (IllegalArgumentException u) { - uri = AsyncHttpProviderUtils.createUri(request.getUrl()); + uri = AsyncHttpProviderUtils.createNonEmptyPathURI(request.getUrl()); } configure(uri, urlConnection, request); 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 994e77e280..e156f731c4 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 @@ -995,12 +995,8 @@ private ListenableFuture doConnect(final Request request, final AsyncHand boolean resultOfAConnect = f != null && f.getNettyRequest() != null && f.getNettyRequest().getMethod().equals(HttpMethod.CONNECT); boolean useProxy = proxyServer != null && !resultOfAConnect; - URI uri; - if (useRawUrl) { - uri = request.getRawURI(); - } else { - uri = request.getURI(); - } + URI uri = useRawUrl ? request.getRawURI() : request.getURI(); + ChannelBuffer bufferedBytes = null; if (f != null && f.getRequest().getFile() == null && !f.getNettyRequest().getMethod().getName().equals(HttpMethod.CONNECT.getName())) { bufferedBytes = f.getNettyRequest().getContent(); diff --git a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java index 39c9dc30f9..8a29027b5c 100644 --- a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java +++ b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java @@ -57,17 +57,15 @@ public static final void validateSupportedScheme(URI uri) { } } - public final static URI createUri(String u) { + public final static URI createNonEmptyPathURI(String u) { URI uri = URI.create(u); validateSupportedScheme(uri); String path = uri.getPath(); if (path == null) { - throw new IllegalArgumentException("The URI path, of the URI " + uri - + ", must be non-null"); + throw new IllegalArgumentException("The URI path, of the URI " + uri + ", must be non-null"); } else if (isNonEmpty(path) && path.charAt(0) != '/') { - throw new IllegalArgumentException("The URI path, of the URI " + uri - + ". must start with a '/'"); + throw new IllegalArgumentException("The URI path, of the URI " + uri + ". must start with a '/'"); } else if (!isNonEmpty(path)) { return URI.create(u + "/"); } @@ -75,10 +73,6 @@ public final static URI createUri(String u) { return uri; } - public static String getBaseUrl(String url) { - return getBaseUrl(createUri(url)); - } - public final static String getBaseUrl(URI uri) { String url = uri.getScheme() + "://" + uri.getAuthority(); int port = uri.getPort(); From 914453deb58b547782937c2fc9e04b107d26cb50 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 1 Jul 2014 17:32:19 +0200 Subject: [PATCH 326/701] minor clean up --- .../ning/http/client/RequestBuilderBase.java | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/ning/http/client/RequestBuilderBase.java b/src/main/java/com/ning/http/client/RequestBuilderBase.java index 654182ff06..b49446b8f4 100644 --- a/src/main/java/com/ning/http/client/RequestBuilderBase.java +++ b/src/main/java/com/ning/http/client/RequestBuilderBase.java @@ -174,8 +174,10 @@ private URI toURI(boolean encode) { AsyncHttpProviderUtils.validateSupportedScheme(originalUri); - StringBuilder builder = new StringBuilder(); - builder.append(originalUri.getScheme()).append("://").append(originalUri.getRawAuthority()); + StringBuilder builder = new StringBuilder()// + .append(originalUri.getScheme())// + .append("://")// + .append(originalUri.getRawAuthority()); if (isNonEmpty(originalUri.getRawPath())) { builder.append(originalUri.getRawPath()); } else { @@ -630,8 +632,7 @@ public T setSignatureCalculator(SignatureCalculator signatureCalculator) { return derived.cast(this); } - public Request build() { - + private void executeSignatureCalculator() { /* Let's first calculate and inject signature, before finalizing actual build * (order does not matter with current implementation but may in future) */ @@ -644,7 +645,9 @@ public Request build() { } signatureCalculator.calculateAndAddSignature(url, request, this); } - + } + + private void computeRequestCharset() { try { final String contentType = request.headers.getFirstValue("Content-Type"); if (contentType != null) { @@ -658,6 +661,9 @@ public Request build() { } catch (Throwable e) { // NoOp -- we can't fix the Content-Type or charset from here } + } + + private void computeRequestLength() { if (request.length < 0 && request.streamData == null) { // can't concatenate content-length final String contentLength = request.headers.getFirstValue("Content-Length"); @@ -670,6 +676,12 @@ public Request build() { } } } + } + + public Request build() { + executeSignatureCalculator(); + computeRequestCharset(); + computeRequestLength(); return request; } From a1b8674588b3fbbef45bb681a3ea1c683832e380 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 1 Jul 2014 18:37:28 +0200 Subject: [PATCH 327/701] Remove useless calls to Request.getUrl, close #582 --- .../netty/NettyAsyncHttpProvider.java | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 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 e156f731c4..e18eabae0a 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 @@ -986,7 +986,9 @@ private ListenableFuture doConnect(final Request request, final AsyncHand throw new IOException("Closed"); } - if (request.getUrl().startsWith(WEBSOCKET) && !validateWebSocketRequest(request, asyncHandler)) { + URI uri = useRawUrl ? request.getRawURI() : request.getURI(); + + if (uri.getScheme().startsWith(WEBSOCKET) && !validateWebSocketRequest(request, asyncHandler)) { throw new IOException("WebSocket method must be a GET"); } @@ -995,8 +997,6 @@ private ListenableFuture doConnect(final Request request, final AsyncHand boolean resultOfAConnect = f != null && f.getNettyRequest() != null && f.getNettyRequest().getMethod().equals(HttpMethod.CONNECT); boolean useProxy = proxyServer != null && !resultOfAConnect; - URI uri = useRawUrl ? request.getRawURI() : request.getURI(); - ChannelBuffer bufferedBytes = null; if (f != null && f.getRequest().getFile() == null && !f.getNettyRequest().getMethod().getName().equals(HttpMethod.CONNECT.getName())) { bufferedBytes = f.getNettyRequest().getContent(); @@ -1069,7 +1069,7 @@ private ListenableFuture doConnect(final Request request, final AsyncHand } ChannelFuture channelFuture; - ClientBootstrap bootstrap = (request.getUrl().startsWith(WEBSOCKET) && !useProxy) ? (useSSl ? secureWebSocketBootstrap : webSocketBootstrap) : (useSSl ? secureBootstrap + ClientBootstrap bootstrap = (request.getURI().getScheme().startsWith(WEBSOCKET) && !useProxy) ? (useSSl ? secureWebSocketBootstrap : webSocketBootstrap) : (useSSl ? secureBootstrap : plainBootstrap); bootstrap.setOption("connectTimeoutMillis", config.getConnectionTimeoutInMs()); @@ -1977,7 +1977,7 @@ private boolean redirect(Request request, NettyResponseFuture future, HttpRes final String initialPoolKey = getPoolKey(future); future.setURI(uri); String newUrl = uri.toString(); - if (request.getUrl().startsWith(WEBSOCKET)) { + if (request.getURI().getScheme().startsWith(WEBSOCKET)) { newUrl = newUrl.replace(HTTP, WEBSOCKET); } @@ -2128,7 +2128,7 @@ public void handle(final ChannelHandlerContext ctx, final MessageEvent e) throws String realmURI = computeRealmURI(newRealm, request.getURI()); final Realm nr = new Realm.RealmBuilder().clone(newRealm).setUri(realmURI).build(); - log.debug("Sending authentication to {}", request.getUrl()); + log.debug("Sending authentication to {}", request.getURI()); AsyncCallable ac = new AsyncCallable(future) { public Object call() throws Exception { drainChannel(ctx, future); @@ -2156,7 +2156,7 @@ public Object call() throws Exception { List proxyAuth = getAuthorizationToken(response.getHeaders(), HttpHeaders.Names.PROXY_AUTHENTICATE); if (statusCode == 407 && realm != null && !proxyAuth.isEmpty() && !future.getAndSetAuth(true)) { - log.debug("Sending proxy authentication to {}", request.getUrl()); + log.debug("Sending proxy authentication to {}", request.getURI()); future.setState(NettyResponseFuture.STATE.NEW); Realm newRealm = null; @@ -2188,8 +2188,9 @@ public Object call() throws Exception { } try { - log.debug("Connecting to proxy {} for scheme {}", proxyServer, request.getUrl()); - upgradeProtocol(ctx.getChannel().getPipeline(), request.getURI().getScheme()); + String scheme = request.getURI().getScheme(); + log.debug("Connecting to proxy {} for scheme {}", proxyServer, scheme); + upgradeProtocol(ctx.getChannel().getPipeline(), scheme); } catch (Throwable ex) { abort(future, ex); } From 6ff459afb43f50acfed176dfca644f12b37ecd38 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 1 Jul 2014 20:25:56 +0200 Subject: [PATCH 328/701] Only extract charset from Content-Type header when it wasn't set explicitly --- .../ning/http/client/RequestBuilderBase.java | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/ning/http/client/RequestBuilderBase.java b/src/main/java/com/ning/http/client/RequestBuilderBase.java index b49446b8f4..07f21fab7f 100644 --- a/src/main/java/com/ning/http/client/RequestBuilderBase.java +++ b/src/main/java/com/ning/http/client/RequestBuilderBase.java @@ -648,18 +648,20 @@ private void executeSignatureCalculator() { } private void computeRequestCharset() { - try { - final String contentType = request.headers.getFirstValue("Content-Type"); - if (contentType != null) { - final String charset = AsyncHttpProviderUtils.parseCharset(contentType); - if (charset != null) { - // ensure that if charset is provided with the Content-Type header, - // we propagate that down to the charset of the Request object - request.charset = charset; + if (request.charset == null) { + try { + final String contentType = request.headers.getFirstValue("Content-Type"); + if (contentType != null) { + final String charset = AsyncHttpProviderUtils.parseCharset(contentType); + if (charset != null) { + // ensure that if charset is provided with the Content-Type header, + // we propagate that down to the charset of the Request object + request.charset = charset; + } } + } catch (Throwable e) { + // NoOp -- we can't fix the Content-Type or charset from here } - } catch (Throwable e) { - // NoOp -- we can't fix the Content-Type or charset from here } } From 8bb9849604178fee0e72083503517b1bbc4527e8 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 1 Jul 2014 21:20:08 +0200 Subject: [PATCH 329/701] Lazy init Request cookies list, add set(Collection) method, close #584 --- .../ning/http/client/RequestBuilderBase.java | 62 +++++++++++-------- 1 file changed, 37 insertions(+), 25 deletions(-) diff --git a/src/main/java/com/ning/http/client/RequestBuilderBase.java b/src/main/java/com/ning/http/client/RequestBuilderBase.java index 07f21fab7f..8a875ab52f 100644 --- a/src/main/java/com/ning/http/client/RequestBuilderBase.java +++ b/src/main/java/com/ning/http/client/RequestBuilderBase.java @@ -57,7 +57,7 @@ private static final class RequestImpl implements Request { private InetAddress address; private InetAddress localAddress; private FluentCaseInsensitiveStringsMap headers = new FluentCaseInsensitiveStringsMap(); - private Collection cookies = new ArrayList(); + private ArrayList cookies; private byte[] byteData; private String stringData; private InputStream streamData; @@ -226,7 +226,7 @@ public FluentCaseInsensitiveStringsMap getHeaders() { /* @Override */ public Collection getCookies() { - return Collections.unmodifiableCollection(cookies); + return cookies != null ? Collections.unmodifiableCollection(cookies) : Collections. emptyList(); } /* @Override */ @@ -460,17 +460,49 @@ public T setContentLength(int length) { return derived.cast(this); } + private void lazyInitCookies() { + if (request.cookies == null) + request.cookies = new ArrayList(3); + } + + public T setCookies(Collection cookies) { + request.cookies = new ArrayList(cookies); + return derived.cast(this); + } + public T addCookie(Cookie cookie) { + lazyInitCookies(); request.cookies.add(cookie); return derived.cast(this); } - public void resetQueryParameters() { - request.queryParams = null; + public T addOrReplaceCookie(Cookie cookie) { + String cookieKey = cookie.getName(); + boolean replace = false; + int index = 0; + lazyInitCookies(); + for (Cookie c : request.cookies) { + if (c.getName().equals(cookieKey)) { + replace = true; + break; + } + + index++; + } + if (replace) + request.cookies.set(index, cookie); + else + request.cookies.add(cookie); + return derived.cast(this); } public void resetCookies() { - request.cookies.clear();; + if (request.cookies != null) + request.cookies.clear(); + } + + public void resetQueryParameters() { + request.queryParams = null; } public void resetParameters() { @@ -686,24 +718,4 @@ public Request build() { computeRequestLength(); return request; } - - public T addOrReplaceCookie(Cookie cookie) { - String cookieKey = cookie.getName(); - boolean replace = false; - int index = 0; - for (Cookie c : request.cookies) { - if (c.getName().equals(cookieKey)) { - replace = true; - break; - } - - index++; - } - if (replace) { - ((ArrayList) request.cookies).set(index, cookie); - } else { - request.cookies.add(cookie); - } - return derived.cast(this); - } } From 8bbd4d3f1f900e04cd571d1de6de2866bade54c4 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 2 Jul 2014 13:00:12 +0200 Subject: [PATCH 330/701] minor clean up --- .../java/com/ning/http/util/AsyncHttpProviderUtils.java | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java index 8a29027b5c..cf5416dd5b 100644 --- a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java +++ b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java @@ -74,13 +74,7 @@ public final static URI createNonEmptyPathURI(String u) { } public final static String getBaseUrl(URI uri) { - String url = uri.getScheme() + "://" + uri.getAuthority(); - int port = uri.getPort(); - if (port == -1) { - port = getPort(uri); - url += ":" + port; - } - return url; + return uri.getScheme() + "://" + getAuthority(uri); } public final static String getAuthority(URI uri) { From 7373be55a31bdd66020dabea407df800c5696ece Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 2 Jul 2014 13:44:19 +0200 Subject: [PATCH 331/701] Drop Proxy.getURI, close #586 --- .../java/com/ning/http/client/ProxyServer.java | 17 +++++++---------- .../grizzly/GrizzlyAsyncHttpProvider.java | 5 +---- .../providers/netty/NettyAsyncHttpProvider.java | 2 +- 3 files changed, 9 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/ning/http/client/ProxyServer.java b/src/main/java/com/ning/http/client/ProxyServer.java index dc037820d9..e069ea0ace 100644 --- a/src/main/java/com/ning/http/client/ProxyServer.java +++ b/src/main/java/com/ning/http/client/ProxyServer.java @@ -16,13 +16,10 @@ */ 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. */ @@ -53,7 +50,7 @@ public String toString() { private final String principal; private final String password; private final int port; - private final URI uri; + private final String url; private String encoding = "UTF-8"; private String ntlmDomain = System.getProperty("http.auth.ntlm.domain", ""); @@ -63,7 +60,7 @@ public ProxyServer(final Protocol protocol, final String host, final int port, S this.port = port; this.principal = principal; this.password = password; - uri = AsyncHttpProviderUtils.createNonEmptyPathURI(toString()); + this.url = protocol + "://" + host + ":" + port; } public ProxyServer(final String host, final int port, String principal, String password) { @@ -102,10 +99,6 @@ public String getPassword() { return password; } - public URI getURI() { - return uri; - } - public ProxyServer setEncoding(String encoding) { this.encoding = encoding; return this; @@ -138,9 +131,13 @@ public String getNtlmDomain() { return ntlmDomain; } + public String getUrl() { + return url; + } + @Override public String toString() { - return protocol + "://" + host + ":" + port; + return url; } } 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 cad6b22449..6893afbeb7 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 @@ -2590,10 +2590,7 @@ public void updated(Connection result) { private static String getPoolKey(Request request, ProxyServer proxyServer) { String serverPart = request.getConnectionPoolKeyStrategy().getKey(request.getURI()); - return proxyServer != null - ? AsyncHttpProviderUtils.getBaseUrl(proxyServer.getURI()) - + serverPart - : serverPart; + return proxyServer != null ? proxyServer.getUrl() + serverPart : serverPart; } // ------------------------------------------------------ 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 e18eabae0a..e8dbe8987b 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 @@ -1329,7 +1329,7 @@ private String getPoolKey(NettyResponseFuture future) { private String getPoolKey(URI uri, ProxyServer proxy, ConnectionPoolKeyStrategy strategy) { String serverPart = strategy.getKey(uri); - return proxy != null ? AsyncHttpProviderUtils.getBaseUrl(proxy.getURI()) + serverPart : serverPart; + return proxy != null ? proxy.getUrl() + serverPart : serverPart; } private void drainChannel(final ChannelHandlerContext ctx, final NettyResponseFuture future) { From 832243fb11bdd6b405f41658a8ffbf1a64612de5 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 2 Jul 2014 16:40:09 +0200 Subject: [PATCH 332/701] Replace java.net.URI with our own parser, close #587 --- .../client/ConnectionPoolKeyStrategy.java | 4 +- .../client/DefaultConnectionPoolStrategy.java | 7 +- .../com/ning/http/client/HttpContent.java | 14 +- .../http/client/HttpResponseBodyPart.java | 5 +- .../ning/http/client/HttpResponseHeaders.java | 6 +- .../ning/http/client/HttpResponseStatus.java | 4 +- .../ning/http/client/ProxyServerSelector.java | 7 +- .../java/com/ning/http/client/Request.java | 8 +- .../ning/http/client/RequestBuilderBase.java | 76 ++-- .../java/com/ning/http/client/Response.java | 10 +- .../apache/ApacheAsyncHttpProvider.java | 7 +- .../providers/apache/ApacheResponse.java | 9 +- .../apache/ApacheResponseBodyPart.java | 4 +- .../apache/ApacheResponseHeaders.java | 5 +- .../apache/ApacheResponseStatus.java | 6 +- .../grizzly/GrizzlyAsyncHttpProvider.java | 28 +- .../providers/grizzly/GrizzlyResponse.java | 7 +- .../grizzly/GrizzlyResponseBodyPart.java | 4 +- .../grizzly/GrizzlyResponseHeaders.java | 6 +- .../grizzly/GrizzlyResponseStatus.java | 5 +- .../providers/jdk/JDKAsyncHttpProvider.java | 19 +- .../client/providers/jdk/JDKResponse.java | 9 +- .../providers/jdk/ResponseBodyPart.java | 4 +- .../client/providers/jdk/ResponseHeaders.java | 4 +- .../client/providers/jdk/ResponseStatus.java | 4 +- .../netty/NettyAsyncHttpProvider.java | 79 ++-- .../providers/netty/NettyConnectListener.java | 4 +- .../client/providers/netty/NettyResponse.java | 7 +- .../providers/netty/NettyResponseFuture.java | 10 +- .../providers/netty/ResponseBodyPart.java | 7 +- .../providers/netty/ResponseHeaders.java | 7 +- .../providers/netty/ResponseStatus.java | 6 +- .../IdleConnectionTimeoutTimerTask.java | 19 +- .../timeout/RequestTimeoutTimerTask.java | 19 +- .../netty/timeout/TimeoutTimerTask.java | 19 +- .../netty/timeout/TimeoutsHolder.java | 19 +- .../resumable/ResumableAsyncHandler.java | 2 +- .../ning/http/client/uri/UriComponents.java | 182 ++++++++++ .../http/client/uri/UriComponentsParser.java | 341 ++++++++++++++++++ .../webdav/WebDavCompletionHandlerBase.java | 2 +- .../http/client/webdav/WebDavResponse.java | 5 +- .../http/util/AsyncHttpProviderUtils.java | 81 +---- .../java/com/ning/http/util/ProxyUtils.java | 27 +- .../client/async/AsyncProvidersBasicTest.java | 2 +- .../async/PerRequestRelative302Test.java | 8 +- .../http/client/async/PostWithQSTest.java | 8 +- .../http/client/async/Relative302Test.java | 7 +- .../http/client/uri/UrlComponentsTest.java | 87 +++++ .../http/util/AsyncHttpProviderUtilsTest.java | 45 --- 49 files changed, 874 insertions(+), 381 deletions(-) create mode 100644 src/main/java/com/ning/http/client/uri/UriComponents.java create mode 100644 src/main/java/com/ning/http/client/uri/UriComponentsParser.java create mode 100644 src/test/java/com/ning/http/client/uri/UrlComponentsTest.java delete mode 100644 src/test/java/com/ning/http/util/AsyncHttpProviderUtilsTest.java diff --git a/src/main/java/com/ning/http/client/ConnectionPoolKeyStrategy.java b/src/main/java/com/ning/http/client/ConnectionPoolKeyStrategy.java index 3beb10d3ec..11e4401433 100644 --- a/src/main/java/com/ning/http/client/ConnectionPoolKeyStrategy.java +++ b/src/main/java/com/ning/http/client/ConnectionPoolKeyStrategy.java @@ -15,9 +15,9 @@ */ package com.ning.http.client; -import java.net.URI; +import com.ning.http.client.uri.UriComponents; public interface ConnectionPoolKeyStrategy { - String getKey(URI uri); + String getKey(UriComponents uri); } diff --git a/src/main/java/com/ning/http/client/DefaultConnectionPoolStrategy.java b/src/main/java/com/ning/http/client/DefaultConnectionPoolStrategy.java index 3d248e869f..f77b77dc79 100644 --- a/src/main/java/com/ning/http/client/DefaultConnectionPoolStrategy.java +++ b/src/main/java/com/ning/http/client/DefaultConnectionPoolStrategy.java @@ -15,15 +15,14 @@ */ package com.ning.http.client; -import java.net.URI; - +import com.ning.http.client.uri.UriComponents; import com.ning.http.util.AsyncHttpProviderUtils; public enum DefaultConnectionPoolStrategy implements ConnectionPoolKeyStrategy { INSTANCE; - public String getKey(URI uri) { + public String getKey(UriComponents uri) { return AsyncHttpProviderUtils.getBaseUrl(uri); } -} \ No newline at end of file +} diff --git a/src/main/java/com/ning/http/client/HttpContent.java b/src/main/java/com/ning/http/client/HttpContent.java index 334def9239..fff00b9280 100644 --- a/src/main/java/com/ning/http/client/HttpContent.java +++ b/src/main/java/com/ning/http/client/HttpContent.java @@ -15,18 +15,18 @@ */ package com.ning.http.client; -import java.net.URI; +import com.ning.http.client.uri.UriComponents; /** * Base class for callback class used by {@link com.ning.http.client.AsyncHandler} */ public class HttpContent { protected final AsyncHttpProvider provider; - protected final URI uri; + protected final UriComponents uri; - protected HttpContent(URI url, AsyncHttpProvider provider) { + protected HttpContent(UriComponents uri, AsyncHttpProvider provider) { this.provider = provider; - this.uri = url; + this.uri = uri; } /** @@ -39,11 +39,11 @@ public final AsyncHttpProvider provider() { } /** - * Return the request {@link URI} + * Return the request {@link UriComponents} * - * @return the request {@link URI} + * @return the request {@link UriComponents} */ - public final URI getUrl() { + public final UriComponents getUri() { return uri; } } diff --git a/src/main/java/com/ning/http/client/HttpResponseBodyPart.java b/src/main/java/com/ning/http/client/HttpResponseBodyPart.java index 140c60983f..c310f37942 100644 --- a/src/main/java/com/ning/http/client/HttpResponseBodyPart.java +++ b/src/main/java/com/ning/http/client/HttpResponseBodyPart.java @@ -15,9 +15,10 @@ */ package com.ning.http.client; +import com.ning.http.client.uri.UriComponents; + import java.io.IOException; import java.io.OutputStream; -import java.net.URI; import java.nio.ByteBuffer; /** @@ -25,7 +26,7 @@ */ public abstract class HttpResponseBodyPart extends HttpContent { - public HttpResponseBodyPart(URI uri, AsyncHttpProvider provider) { + public HttpResponseBodyPart(UriComponents uri, AsyncHttpProvider provider) { super(uri, provider); } diff --git a/src/main/java/com/ning/http/client/HttpResponseHeaders.java b/src/main/java/com/ning/http/client/HttpResponseHeaders.java index c3842cf122..e6dcf13d23 100644 --- a/src/main/java/com/ning/http/client/HttpResponseHeaders.java +++ b/src/main/java/com/ning/http/client/HttpResponseHeaders.java @@ -15,7 +15,7 @@ */ package com.ning.http.client; -import java.net.URI; +import com.ning.http.client.uri.UriComponents; /** * A class that represent the HTTP headers. @@ -24,12 +24,12 @@ public abstract class HttpResponseHeaders extends HttpContent { private final boolean traillingHeaders; - public HttpResponseHeaders(URI uri, AsyncHttpProvider provider) { + public HttpResponseHeaders(UriComponents uri, AsyncHttpProvider provider) { super(uri, provider); this.traillingHeaders = false; } - public HttpResponseHeaders(URI uri, AsyncHttpProvider provider, boolean traillingHeaders) { + public HttpResponseHeaders(UriComponents uri, AsyncHttpProvider provider, boolean traillingHeaders) { super(uri, provider); this.traillingHeaders = traillingHeaders; } diff --git a/src/main/java/com/ning/http/client/HttpResponseStatus.java b/src/main/java/com/ning/http/client/HttpResponseStatus.java index f90b30c5a7..8084d9f97d 100644 --- a/src/main/java/com/ning/http/client/HttpResponseStatus.java +++ b/src/main/java/com/ning/http/client/HttpResponseStatus.java @@ -16,14 +16,14 @@ */ package com.ning.http.client; -import java.net.URI; +import com.ning.http.client.uri.UriComponents; /** * A class that represent the HTTP response' status line (code + text) */ public abstract class HttpResponseStatus extends HttpContent { - public HttpResponseStatus(URI uri, AsyncHttpProvider provider) { + public HttpResponseStatus(UriComponents uri, AsyncHttpProvider provider) { super(uri, provider); } diff --git a/src/main/java/com/ning/http/client/ProxyServerSelector.java b/src/main/java/com/ning/http/client/ProxyServerSelector.java index 68e5d70ff3..194f268426 100644 --- a/src/main/java/com/ning/http/client/ProxyServerSelector.java +++ b/src/main/java/com/ning/http/client/ProxyServerSelector.java @@ -1,6 +1,6 @@ package com.ning.http.client; -import java.net.URI; +import com.ning.http.client.uri.UriComponents; /** * Selector for a proxy server @@ -13,15 +13,14 @@ public interface ProxyServerSelector { * @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); + ProxyServer select(UriComponents uri); /** * A selector that always selects no proxy. */ static final ProxyServerSelector NO_PROXY_SELECTOR = new ProxyServerSelector() { - public ProxyServer select(URI uri) { + public ProxyServer select(UriComponents uri) { return null; } }; } - diff --git a/src/main/java/com/ning/http/client/Request.java b/src/main/java/com/ning/http/client/Request.java index 1250974078..303deac4b4 100644 --- a/src/main/java/com/ning/http/client/Request.java +++ b/src/main/java/com/ning/http/client/Request.java @@ -21,11 +21,11 @@ import java.io.InputStream; import java.io.OutputStream; import java.net.InetAddress; -import java.net.URI; import java.util.Collection; import java.util.List; import com.ning.http.client.cookie.Cookie; +import com.ning.http.client.uri.UriComponents; /** * The Request class can be used to construct HTTP request: @@ -69,9 +69,9 @@ public static interface EntityWriter { */ String getUrl(); - URI getOriginalURI(); - URI getURI(); - URI getRawURI(); + UriComponents getOriginalURI(); + UriComponents getURI(); + UriComponents 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 8a875ab52f..c0f57080f4 100644 --- a/src/main/java/com/ning/http/client/RequestBuilderBase.java +++ b/src/main/java/com/ning/http/client/RequestBuilderBase.java @@ -21,7 +21,6 @@ import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.net.InetAddress; -import java.net.URI; import java.net.URLDecoder; import java.util.ArrayList; import java.util.Collection; @@ -36,6 +35,7 @@ import com.ning.http.client.Request.EntityWriter; import com.ning.http.client.cookie.Cookie; +import com.ning.http.client.uri.UriComponents; import com.ning.http.util.AsyncHttpProviderUtils; import com.ning.http.util.UTF8UrlEncoder; @@ -47,13 +47,13 @@ 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 UriComponents DEFAULT_REQUEST_URL = UriComponents.create("http://localhost"); private static final class RequestImpl implements Request { private String method; - private URI originalUri; - private URI uri; - private URI rawUri; + private UriComponents originalUri; + private UriComponents uri; + private UriComponents rawUri; private InetAddress address; private InetAddress localAddress; private FluentCaseInsensitiveStringsMap headers = new FluentCaseInsensitiveStringsMap(); @@ -130,7 +130,7 @@ public InetAddress getLocalAddress() { return localAddress; } - private String removeTrailingSlash(URI uri) { + private String removeTrailingSlash(UriComponents uri) { String uriString = uri.toString(); if (uriString.endsWith("/")) { return uriString.substring(0, uriString.length() - 1); @@ -149,23 +149,23 @@ public String getRawUrl() { return removeTrailingSlash(getRawURI()); } - public URI getOriginalURI() { + public UriComponents getOriginalURI() { return originalUri; } - public URI getURI() { + public UriComponents getURI() { if (uri == null) - uri = toURI(true); + uri = toUriComponents(true); return uri; } - public URI getRawURI() { + public UriComponents getRawURI() { if (rawUri == null) - rawUri = toURI(false); + rawUri = toUriComponents(false); return rawUri; } - private URI toURI(boolean encode) { + private UriComponents toUriComponents(boolean encode) { if (originalUri == null) { logger.debug("setUrl hasn't been invoked. Using http://localhost"); @@ -174,49 +174,47 @@ private URI toURI(boolean encode) { AsyncHttpProviderUtils.validateSupportedScheme(originalUri); - StringBuilder builder = new StringBuilder()// - .append(originalUri.getScheme())// - .append("://")// - .append(originalUri.getRawAuthority()); - if (isNonEmpty(originalUri.getRawPath())) { - builder.append(originalUri.getRawPath()); - } else { - builder.append("/"); - } - + String newPath = isNonEmpty(originalUri.getPath())? originalUri.getPath() : "/"; + String newQuery = null; if (isNonEmpty(queryParams)) { - - builder.append("?"); - + StringBuilder sb = new StringBuilder(); for (Iterator>> i = queryParams.iterator(); i.hasNext();) { Map.Entry> param = i.next(); String name = param.getKey(); for (Iterator j = param.getValue().iterator(); j.hasNext();) { String value = j.next(); if (encode) { - UTF8UrlEncoder.appendEncoded(builder, name); + UTF8UrlEncoder.appendEncoded(sb, name); } else { - builder.append(name); + sb.append(name); } if (value != null) { - builder.append('='); + sb.append('='); if (encode) { - UTF8UrlEncoder.appendEncoded(builder, value); + UTF8UrlEncoder.appendEncoded(sb, value); } else { - builder.append(value); + sb.append(value); } } if (j.hasNext()) { - builder.append('&'); + sb.append('&'); } } if (i.hasNext()) { - builder.append('&'); + sb.append('&'); } } + + newQuery = sb.toString(); } - return URI.create(builder.toString()); + return new UriComponents(// + originalUri.getScheme(),// + originalUri.getUserInfo(),// + originalUri.getHost(),// + originalUri.getPort(),// + newPath,// + newQuery); } /* @Override */ @@ -377,12 +375,10 @@ protected RequestBuilderBase(Class derived, Request prototype) { public T setUrl(String url) { this.baseURL = url; - return setURI(URI.create(url)); + return setURI(UriComponents.create(url)); } - public T setURI(URI uri) { - if (uri.getHost() == null) - throw new NullPointerException("uri.host"); + public T setURI(UriComponents uri) { if (uri.getPath() == null) throw new NullPointerException("uri.path"); request.originalUri = uri; @@ -402,9 +398,9 @@ public T setLocalInetAddress(InetAddress address) { return derived.cast(this); } - private void addQueryParameters(URI uri) { - if (isNonEmpty(uri.getRawQuery())) { - String[] queries = uri.getRawQuery().split("&"); + private void addQueryParameters(UriComponents uri) { + if (isNonEmpty(uri.getQuery())) { + String[] queries = uri.getQuery().split("&"); int pos; for (String query : queries) { pos = query.indexOf("="); diff --git a/src/main/java/com/ning/http/client/Response.java b/src/main/java/com/ning/http/client/Response.java index 30228bcdf7..55d8fc86ed 100644 --- a/src/main/java/com/ning/http/client/Response.java +++ b/src/main/java/com/ning/http/client/Response.java @@ -18,14 +18,13 @@ import java.io.IOException; 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; import com.ning.http.client.cookie.Cookie; +import com.ning.http.client.uri.UriComponents; /** * Represents the asynchronous HTTP response callback for an {@link com.ning.http.client.AsyncCompletionHandler} @@ -111,13 +110,12 @@ public interface Response { String getResponseBody() throws IOException; /** - * Return the request {@link URI}. Note that if the request got redirected, the value of the {@link URI} will be + * Return the request {@link UriComponents}. Note that if the request got redirected, the value of the {@link UriComponents} will be * the last valid redirect url. * - * @return the request {@link URI}. - * @throws MalformedURLException + * @return the request {@link UriComponents}. */ - URI getUri() throws MalformedURLException; + UriComponents getUri(); /** * Return the content-type header value. 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 27d6738353..6986725b26 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 @@ -42,6 +42,7 @@ import com.ning.http.client.filter.ResponseFilter; import com.ning.http.client.listener.TransferCompletionHandler; import com.ning.http.client.resumable.ResumableAsyncHandler; +import com.ning.http.client.uri.UriComponents; import com.ning.http.util.AsyncHttpProviderUtils; import com.ning.http.util.ProxyUtils; import com.ning.http.util.UTF8UrlEncoder; @@ -97,7 +98,6 @@ import java.net.ConnectException; import java.net.InetAddress; import java.net.Socket; -import java.net.URI; import java.net.UnknownHostException; import java.nio.ByteBuffer; import java.security.KeyManagementException; @@ -121,7 +121,6 @@ import static com.ning.http.util.AsyncHttpProviderUtils.DEFAULT_CHARSET; - /** * An {@link com.ning.http.client.AsyncHttpProvider} for Apache Http Client 3.1 */ @@ -463,7 +462,7 @@ public T call() { terminate = true; AsyncHandler.STATE state = AsyncHandler.STATE.ABORT; try { - URI uri = null; + UriComponents uri = null; try { uri = AsyncHttpProviderUtils.createNonEmptyPathURI(request.getRawUrl()); } catch (IllegalArgumentException u) { @@ -517,7 +516,7 @@ public T call() { if (currentRedirectCount++ < config.getMaxRedirects()) { String location = method.getResponseHeader("Location").getValue(); - URI rediUri = AsyncHttpProviderUtils.getRedirectUri(uri, location); + UriComponents rediUri = UriComponents.create(uri, location); String newUrl = rediUri.toString(); if (!newUrl.equals(uri.toString())) { 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 1f73128fd7..0865b25834 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 @@ -16,8 +16,6 @@ import java.io.IOException; import java.io.InputStream; -import java.net.MalformedURLException; -import java.net.URI; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Collections; @@ -31,12 +29,13 @@ import com.ning.http.client.Response; import com.ning.http.client.cookie.Cookie; import com.ning.http.client.cookie.CookieDecoder; +import com.ning.http.client.uri.UriComponents; import com.ning.http.util.AsyncHttpProviderUtils; public class ApacheResponse implements Response { private final static String DEFAULT_CHARSET = "ISO-8859-1"; - private final URI uri; + private final UriComponents uri; private final List bodyParts; private final HttpResponseHeaders headers; private final HttpResponseStatus status; @@ -50,7 +49,7 @@ public ApacheResponse(HttpResponseStatus status, this.headers = headers; this.status = status; - uri = this.status.getUrl(); + uri = this.status.getUri(); } /* @Override */ @@ -114,7 +113,7 @@ private String computeCharset(String charset) { /* @Override */ - public URI getUri() throws MalformedURLException { + public UriComponents getUri() { return uri; } diff --git a/src/main/java/com/ning/http/client/providers/apache/ApacheResponseBodyPart.java b/src/main/java/com/ning/http/client/providers/apache/ApacheResponseBodyPart.java index 0e87dd0587..395d8e1aeb 100644 --- a/src/main/java/com/ning/http/client/providers/apache/ApacheResponseBodyPart.java +++ b/src/main/java/com/ning/http/client/providers/apache/ApacheResponseBodyPart.java @@ -14,10 +14,10 @@ import com.ning.http.client.AsyncHttpProvider; import com.ning.http.client.HttpResponseBodyPart; +import com.ning.http.client.uri.UriComponents; import java.io.IOException; import java.io.OutputStream; -import java.net.URI; import java.nio.ByteBuffer; /** @@ -29,7 +29,7 @@ public class ApacheResponseBodyPart extends HttpResponseBodyPart { private final boolean isLast; private boolean closeConnection; - public ApacheResponseBodyPart(URI uri, byte[] chunk, AsyncHttpProvider provider, boolean last) { + public ApacheResponseBodyPart(UriComponents uri, byte[] chunk, AsyncHttpProvider provider, boolean last) { super(uri, provider); this.chunk = chunk; isLast = last; diff --git a/src/main/java/com/ning/http/client/providers/apache/ApacheResponseHeaders.java b/src/main/java/com/ning/http/client/providers/apache/ApacheResponseHeaders.java index 1940f4c971..c3723acf74 100644 --- a/src/main/java/com/ning/http/client/providers/apache/ApacheResponseHeaders.java +++ b/src/main/java/com/ning/http/client/providers/apache/ApacheResponseHeaders.java @@ -15,11 +15,10 @@ import com.ning.http.client.AsyncHttpProvider; import com.ning.http.client.FluentCaseInsensitiveStringsMap; import com.ning.http.client.HttpResponseHeaders; +import com.ning.http.client.uri.UriComponents; import org.apache.commons.httpclient.Header; import org.apache.commons.httpclient.HttpMethodBase; -import java.net.URI; - /** * A class that represent the HTTP headers. */ @@ -28,7 +27,7 @@ public class ApacheResponseHeaders extends HttpResponseHeaders { private final HttpMethodBase method; private final FluentCaseInsensitiveStringsMap headers; - public ApacheResponseHeaders(URI uri, HttpMethodBase method, AsyncHttpProvider provider) { + public ApacheResponseHeaders(UriComponents uri, HttpMethodBase method, AsyncHttpProvider provider) { super(uri, provider, false); this.method = method; headers = computerHeaders(); diff --git a/src/main/java/com/ning/http/client/providers/apache/ApacheResponseStatus.java b/src/main/java/com/ning/http/client/providers/apache/ApacheResponseStatus.java index 64702c75a8..7edda57f2e 100644 --- a/src/main/java/com/ning/http/client/providers/apache/ApacheResponseStatus.java +++ b/src/main/java/com/ning/http/client/providers/apache/ApacheResponseStatus.java @@ -14,9 +14,9 @@ import com.ning.http.client.AsyncHttpProvider; import com.ning.http.client.HttpResponseStatus; -import org.apache.commons.httpclient.HttpMethodBase; +import com.ning.http.client.uri.UriComponents; -import java.net.URI; +import org.apache.commons.httpclient.HttpMethodBase; /** * A class that represent the HTTP response' status line (code + text) @@ -25,7 +25,7 @@ public class ApacheResponseStatus extends HttpResponseStatus { private final HttpMethodBase method; - public ApacheResponseStatus(URI uri, HttpMethodBase method, AsyncHttpProvider provider) { + public ApacheResponseStatus(UriComponents uri, HttpMethodBase method, AsyncHttpProvider provider) { super(uri, provider); this.method = method; } 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 6893afbeb7..550ddd372c 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 @@ -133,6 +133,7 @@ import com.ning.http.client.filter.ResponseFilter; import com.ning.http.client.listener.TransferCompletionHandler; import com.ning.http.client.ntlm.NTLMEngine; +import com.ning.http.client.uri.UriComponents; import com.ning.http.client.websocket.WebSocket; import com.ning.http.client.websocket.WebSocketByteListener; import com.ning.http.client.websocket.WebSocketCloseCodeReasonListener; @@ -147,6 +148,7 @@ import com.ning.http.util.AuthenticatorUtils; import com.ning.http.util.ProxyUtils; import com.ning.http.util.SslUtils; + import org.glassfish.grizzly.CloseListener; import org.glassfish.grizzly.CloseType; import org.glassfish.grizzly.Closeable; @@ -525,7 +527,7 @@ void timeout(final Connection c) { } - static int getPort(final URI uri, final int p) { + static int getPort(final UriComponents uri, final int p) { int port = p; if (port == -1) { final String protocol = uri.getScheme().toLowerCase(Locale.ENGLISH); @@ -848,7 +850,7 @@ private boolean sendAsGrizzlyRequest(final Request request, convertToUpgradeRequest(httpCtx); } final Request req = httpCtx.request; - final URI uri = req.isUseRawUrl() ? req.getRawURI() : req.getURI(); + final UriComponents uri = req.isUseRawUrl() ? req.getRawURI() : req.getURI(); final Method method = Method.valueOf(request.getMethod()); final HttpRequestPacket.Builder builder = HttpRequestPacket.builder(); boolean secure = "https".equals(uri.getScheme()); @@ -915,7 +917,7 @@ private boolean sendAsGrizzlyRequest(final Request request, ctx.notifyDownstream(new SwitchingSSLFilter.SSLSwitchingEvent(secure, connection)); if (!useProxy && !httpCtx.isWSRequest) { - requestPacket.setQueryString(uri.getRawQuery()); + requestPacket.setQueryString(uri.getQuery()); //addQueryString(request, requestPacket); } addHeaders(request, requestPacket); @@ -1693,16 +1695,16 @@ public boolean handleStatus(final HttpResponsePacket responsePacket, throw new IllegalStateException("redirect received, but no location header was present"); } - URI orig; + UriComponents orig; if (httpTransactionContext.lastRedirectURI == null) { orig = httpTransactionContext.request.getURI(); } else { - orig = AsyncHttpProviderUtils.getRedirectUri(httpTransactionContext.request.getURI(), - httpTransactionContext.lastRedirectURI); + orig = UriComponents.create(httpTransactionContext.request.getURI(), + httpTransactionContext.lastRedirectURI); } httpTransactionContext.lastRedirectURI = redirectURL; Request requestToSend; - URI uri = AsyncHttpProviderUtils.getRedirectUri(orig, redirectURL); + UriComponents uri = UriComponents.create(orig, redirectURL); if (!uri.toString().equalsIgnoreCase(orig.toString())) { requestToSend = newRequest(uri, responsePacket, @@ -1764,8 +1766,8 @@ private boolean sendAsGet(final HttpResponsePacket response, } - private boolean switchingSchemes(final URI oldUri, - final URI newUri) { + private boolean switchingSchemes(final UriComponents oldUri, + final UriComponents newUri) { return !oldUri.getScheme().equals(newUri.getScheme()); @@ -1773,7 +1775,7 @@ private boolean switchingSchemes(final URI oldUri, private void notifySchemeSwitch(final FilterChainContext ctx, final Connection c, - final URI uri) throws IOException { + final UriComponents uri) throws IOException { ctx.notifyDownstream(new SwitchingSSLFilter.SSLSwitchingEvent( "https".equals(uri.getScheme()), c)); @@ -1785,7 +1787,7 @@ private void notifySchemeSwitch(final FilterChainContext ctx, // ----------------------------------------------------- Private Methods - private static Request newRequest(final URI uri, + private static Request newRequest(final UriComponents uri, final HttpResponsePacket response, final HttpTransactionContext ctx, boolean asGet) { @@ -2488,7 +2490,7 @@ void doAsyncConnect(final Request request, throws IOException, ExecutionException, InterruptedException { ProxyServer proxy = requestFuture.getProxy(); - final URI uri = request.getURI(); + final UriComponents uri = request.getURI(); String host = ((proxy != null) ? proxy.getHost() : uri.getHost()); int port = ((proxy != null) ? proxy.getPort() : uri.getPort()); if(request.getLocalAddress()!=null) { @@ -2505,7 +2507,7 @@ private Connection obtainConnection0(final Request request, final GrizzlyResponseFuture requestFuture) throws IOException, ExecutionException, InterruptedException, TimeoutException { - final URI uri = request.getURI(); + final UriComponents uri = request.getURI(); final ProxyServer proxy = requestFuture.getProxy(); String host = (proxy != null) ? proxy.getHost() : uri.getHost(); int port = (proxy != null) ? proxy.getPort() : uri.getPort(); 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 f9eecf49cc..3e83f1bc94 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 @@ -17,8 +17,6 @@ import java.io.IOException; 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; @@ -40,6 +38,7 @@ import com.ning.http.client.HttpResponseStatus; import com.ning.http.client.Response; import com.ning.http.client.cookie.Cookie; +import com.ning.http.client.uri.UriComponents; import com.ning.http.util.AsyncHttpProviderUtils; /** @@ -197,9 +196,9 @@ private Buffer getResponseBodyAsBuffer() { /** * {@inheritDoc} */ - public URI getUri() throws MalformedURLException { + public UriComponents getUri() { - return status.getUrl(); + return status.getUri(); } diff --git a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponseBodyPart.java b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponseBodyPart.java index d304f1164f..d269f20a53 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponseBodyPart.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponseBodyPart.java @@ -15,6 +15,7 @@ import com.ning.http.client.AsyncHttpProvider; import com.ning.http.client.HttpResponseBodyPart; +import com.ning.http.client.uri.UriComponents; import org.glassfish.grizzly.Buffer; import org.glassfish.grizzly.Connection; @@ -22,7 +23,6 @@ import java.io.IOException; import java.io.OutputStream; -import java.net.URI; import java.nio.ByteBuffer; import java.util.concurrent.atomic.AtomicReference; @@ -47,7 +47,7 @@ public class GrizzlyResponseBodyPart extends HttpResponseBodyPart { public GrizzlyResponseBodyPart(final HttpContent content, - final URI uri, + final UriComponents uri, final Connection connection, final AsyncHttpProvider provider) { super(uri, provider); diff --git a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponseHeaders.java b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponseHeaders.java index 03e175f1ab..9720a78964 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponseHeaders.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponseHeaders.java @@ -16,13 +16,11 @@ import com.ning.http.client.AsyncHttpProvider; import com.ning.http.client.FluentCaseInsensitiveStringsMap; import com.ning.http.client.HttpResponseHeaders; +import com.ning.http.client.uri.UriComponents; import org.glassfish.grizzly.http.HttpResponsePacket; import org.glassfish.grizzly.http.util.MimeHeaders; -import java.net.URI; - - /** * {@link HttpResponseHeaders} implementation using the Grizzly 2.0 HTTP client * codec. @@ -41,7 +39,7 @@ public class GrizzlyResponseHeaders extends HttpResponseHeaders { public GrizzlyResponseHeaders(final HttpResponsePacket response, - final URI uri, + final UriComponents uri, final AsyncHttpProvider provider) { super(uri, provider); diff --git a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponseStatus.java b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponseStatus.java index 7774f10ac7..c6f4d747f8 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponseStatus.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponseStatus.java @@ -15,11 +15,10 @@ import com.ning.http.client.AsyncHttpProvider; import com.ning.http.client.HttpResponseStatus; +import com.ning.http.client.uri.UriComponents; import org.glassfish.grizzly.http.HttpResponsePacket; -import java.net.URI; - /** * {@link HttpResponseStatus} implementation using the Grizzly 2.0 HTTP client * codec. @@ -36,7 +35,7 @@ public class GrizzlyResponseStatus extends HttpResponseStatus { public GrizzlyResponseStatus(final HttpResponsePacket response, - final URI uri, + final UriComponents uri, final AsyncHttpProvider provider) { super(uri, provider); 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 06e898b4d6..972b627b4e 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 @@ -31,6 +31,7 @@ import java.net.SocketAddress; import java.net.SocketTimeoutException; import java.net.URI; +import java.net.URISyntaxException; import java.net.UnknownHostException; import java.nio.ByteBuffer; import java.security.GeneralSecurityException; @@ -75,6 +76,7 @@ import com.ning.http.client.filter.IOExceptionFilter; import com.ning.http.client.filter.ResponseFilter; import com.ning.http.client.listener.TransferCompletionHandler; +import com.ning.http.client.uri.UriComponents; import com.ning.http.multipart.MultipartRequestEntity; import com.ning.http.util.AsyncHttpProviderUtils; import com.ning.http.util.AuthenticatorUtils; @@ -144,7 +146,12 @@ public ListenableFuture execute(Request request, AsyncHandler handler, } } - HttpURLConnection urlConnection = createUrlConnection(request); + HttpURLConnection urlConnection; + try { + urlConnection = createUrlConnection(request); + } catch (URISyntaxException e) { + throw new IOException(e.getMessage()); + } PerRequestConfig conf = request.getPerRequestConfig(); int requestTimeout = (conf != null && conf.getRequestTimeoutInMs() != 0) ? @@ -164,7 +171,7 @@ public ListenableFuture execute(Request request, AsyncHandler handler, return f; } - private HttpURLConnection createUrlConnection(Request request) throws IOException { + private HttpURLConnection createUrlConnection(Request request) throws IOException, URISyntaxException { ProxyServer proxyServer = ProxyUtils.getProxyServer(config, request); Realm realm = request.getRealm() != null ? request.getRealm() : config.getRealm(); Proxy proxy = null; @@ -177,7 +184,7 @@ private HttpURLConnection createUrlConnection(Request request) throws IOExceptio } HttpURLConnection urlConnection = (HttpURLConnection) - request.getURI().toURL().openConnection(proxy == null ? Proxy.NO_PROXY : proxy); + request.getURI().toURI().toURL().openConnection(proxy == null ? Proxy.NO_PROXY : proxy); if (request.getUrl().startsWith("https")) { HttpsURLConnection secure = (HttpsURLConnection) urlConnection; @@ -228,7 +235,7 @@ public AsyncHttpUrlConnection(HttpURLConnection urlConnection, Request request, public T call() throws Exception { AsyncHandler.STATE state = AsyncHandler.STATE.ABORT; try { - URI uri = null; + UriComponents uri = null; // Encoding with URLConnection is a bit bogus so we need to try both way before setting it try { uri = AsyncHttpProviderUtils.createNonEmptyPathURI(request.getRawUrl()); @@ -269,7 +276,7 @@ public T call() throws Exception { if (currentRedirectCount++ < config.getMaxRedirects()) { String location = urlConnection.getHeaderField("Location"); - URI redirUri = AsyncHttpProviderUtils.getRedirectUri(uri, location); + UriComponents redirUri = UriComponents.create(uri, location); String newUrl = redirUri.toString(); if (!newUrl.equals(uri.toString())) { @@ -443,7 +450,7 @@ private Throwable filterException(Throwable t) { return t; } - private void configure(URI uri, HttpURLConnection urlConnection, Request request) throws IOException, AuthenticationException { + private void configure(UriComponents uri, HttpURLConnection urlConnection, Request request) throws IOException, AuthenticationException { PerRequestConfig conf = request.getPerRequestConfig(); int requestTimeout = (conf != null && conf.getRequestTimeoutInMs() != 0) ? 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 9a4bd687f1..ef0735956c 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 @@ -17,8 +17,6 @@ import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; -import java.net.MalformedURLException; -import java.net.URI; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Collections; @@ -33,13 +31,14 @@ import com.ning.http.client.Response; import com.ning.http.client.cookie.Cookie; import com.ning.http.client.cookie.CookieDecoder; +import com.ning.http.client.uri.UriComponents; import com.ning.http.util.AsyncHttpProviderUtils; public class JDKResponse implements Response { private final static String DEFAULT_CHARSET = "ISO-8859-1"; - private final URI uri; + private final UriComponents uri; private final List bodyParts; private final HttpResponseHeaders headers; private final HttpResponseStatus status; @@ -55,7 +54,7 @@ public JDKResponse(HttpResponseStatus status, this.headers = headers; this.status = status; - uri = this.status.getUrl(); + uri = this.status.getUri(); } /* @Override */ @@ -129,7 +128,7 @@ private String computeCharset(String charset) { /* @Override */ - public URI getUri() throws MalformedURLException { + public UriComponents getUri() { return uri; } diff --git a/src/main/java/com/ning/http/client/providers/jdk/ResponseBodyPart.java b/src/main/java/com/ning/http/client/providers/jdk/ResponseBodyPart.java index 89faefd938..c0f03de905 100644 --- a/src/main/java/com/ning/http/client/providers/jdk/ResponseBodyPart.java +++ b/src/main/java/com/ning/http/client/providers/jdk/ResponseBodyPart.java @@ -14,10 +14,10 @@ import com.ning.http.client.AsyncHttpProvider; import com.ning.http.client.HttpResponseBodyPart; +import com.ning.http.client.uri.UriComponents; import java.io.IOException; import java.io.OutputStream; -import java.net.URI; import java.nio.ByteBuffer; /** @@ -29,7 +29,7 @@ public class ResponseBodyPart extends HttpResponseBodyPart { private final boolean isLast; private boolean closeConnection; - public ResponseBodyPart(URI uri, byte[] chunk, AsyncHttpProvider provider, boolean last) { + public ResponseBodyPart(UriComponents uri, byte[] chunk, AsyncHttpProvider provider, boolean last) { super(uri, provider); this.chunk = chunk; isLast = last; diff --git a/src/main/java/com/ning/http/client/providers/jdk/ResponseHeaders.java b/src/main/java/com/ning/http/client/providers/jdk/ResponseHeaders.java index c4f3fe4865..64c939ccd4 100644 --- a/src/main/java/com/ning/http/client/providers/jdk/ResponseHeaders.java +++ b/src/main/java/com/ning/http/client/providers/jdk/ResponseHeaders.java @@ -15,9 +15,9 @@ import com.ning.http.client.AsyncHttpProvider; import com.ning.http.client.FluentCaseInsensitiveStringsMap; import com.ning.http.client.HttpResponseHeaders; +import com.ning.http.client.uri.UriComponents; import java.net.HttpURLConnection; -import java.net.URI; import java.util.List; import java.util.Map; @@ -29,7 +29,7 @@ public class ResponseHeaders extends HttpResponseHeaders { private final HttpURLConnection urlConnection; private final FluentCaseInsensitiveStringsMap headers; - public ResponseHeaders(URI uri, HttpURLConnection urlConnection, AsyncHttpProvider provider) { + public ResponseHeaders(UriComponents uri, HttpURLConnection urlConnection, AsyncHttpProvider provider) { super(uri, provider, false); this.urlConnection = urlConnection; headers = computerHeaders(); diff --git a/src/main/java/com/ning/http/client/providers/jdk/ResponseStatus.java b/src/main/java/com/ning/http/client/providers/jdk/ResponseStatus.java index 7f27e2dc5d..175d25ab28 100644 --- a/src/main/java/com/ning/http/client/providers/jdk/ResponseStatus.java +++ b/src/main/java/com/ning/http/client/providers/jdk/ResponseStatus.java @@ -14,10 +14,10 @@ import com.ning.http.client.AsyncHttpProvider; import com.ning.http.client.HttpResponseStatus; +import com.ning.http.client.uri.UriComponents; import java.io.IOException; import java.net.HttpURLConnection; -import java.net.URI; /** * A class that represent the HTTP response' status line (code + text) @@ -26,7 +26,7 @@ public class ResponseStatus extends HttpResponseStatus { private final HttpURLConnection urlConnection; - public ResponseStatus(URI uri, HttpURLConnection urlConnection, AsyncHttpProvider provider) { + public ResponseStatus(UriComponents uri, HttpURLConnection urlConnection, AsyncHttpProvider provider) { super(uri, provider); this.urlConnection = urlConnection; } 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 e8dbe8987b..911a9ebe82 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 @@ -39,8 +39,6 @@ import java.net.ConnectException; import java.net.InetSocketAddress; import java.net.MalformedURLException; -import java.net.URI; -import java.net.URISyntaxException; import java.nio.channels.ClosedChannelException; import java.nio.channels.FileChannel; import java.nio.channels.WritableByteChannel; @@ -147,6 +145,7 @@ import com.ning.http.client.providers.netty.timeout.IdleConnectionTimeoutTimerTask; import com.ning.http.client.providers.netty.timeout.RequestTimeoutTimerTask; import com.ning.http.client.providers.netty.timeout.TimeoutsHolder; +import com.ning.http.client.uri.UriComponents; import com.ning.http.client.websocket.WebSocketUpgradeHandler; import com.ning.http.multipart.MultipartBody; import com.ning.http.multipart.MultipartRequestEntity; @@ -425,7 +424,7 @@ public ChannelPipeline getPipeline() throws Exception { } } - private Channel lookupInCache(URI uri, ProxyServer proxy, ConnectionPoolKeyStrategy strategy) { + private Channel lookupInCache(UriComponents uri, ProxyServer proxy, ConnectionPoolKeyStrategy strategy) { final Channel channel = connectionsPool.poll(getPoolKey(uri, proxy, strategy)); if (channel != null) { @@ -645,7 +644,7 @@ public void operationComplete(ChannelFuture cf) { } } - protected final static HttpRequest buildRequest(AsyncHttpClientConfig config, Request request, URI uri, boolean allowConnect, ChannelBuffer buffer, ProxyServer proxyServer) + protected final static HttpRequest buildRequest(AsyncHttpClientConfig config, Request request, UriComponents uri, boolean allowConnect, ChannelBuffer buffer, ProxyServer proxyServer) throws IOException { String method = request.getMethod(); @@ -661,15 +660,9 @@ private static SpnegoEngine getSpnegoEngine() { 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, UriComponents uri, ChannelBuffer buffer, ProxyServer proxyServer) throws IOException { - String host = null; - - if (request.getVirtualHost() != null) { - host = request.getVirtualHost(); - } else { - host = AsyncHttpProviderUtils.getHost(uri); - } + String host = request.getVirtualHost() != null ? request.getVirtualHost() : uri.getHost(); HttpRequest nettyRequest; if (m.equals(HttpMethod.CONNECT)) { @@ -678,10 +671,10 @@ private static HttpRequest construct(AsyncHttpClientConfig config, Request reque String path = null; if (proxyServer != null && !(isSecure(uri) && config.isUseRelativeURIsWithSSLProxies())) path = uri.toString(); - else if (uri.getRawQuery() != null) - path = uri.getRawPath() + "?" + uri.getRawQuery(); + else if (uri.getQuery() != null) + path = uri.getPath() + "?" + uri.getQuery(); else - path = uri.getRawPath(); + path = uri.getPath(); nettyRequest = new DefaultHttpRequest(HttpVersion.HTTP_1_1, m, path); } boolean webSocket = isWebSocket(uri.getScheme()); @@ -939,7 +932,7 @@ private void execute(final Request request, final NettyResponseFuture f, } private NettyResponseFuture buildNettyResponseFutureWithCachedChannel(Request request, AsyncHandler asyncHandler, NettyResponseFuture f, ProxyServer proxyServer, - URI uri, ChannelBuffer bufferedBytes, int maxTry) throws IOException { + UriComponents uri, ChannelBuffer bufferedBytes, int maxTry) throws IOException { for (int i = 0; i < maxTry; i++) { if (maxTry == 0) @@ -986,7 +979,7 @@ private ListenableFuture doConnect(final Request request, final AsyncHand throw new IOException("Closed"); } - URI uri = useRawUrl ? request.getRawURI() : request.getURI(); + UriComponents uri = useRawUrl ? request.getRawURI() : request.getURI(); if (uri.getScheme().startsWith(WEBSOCKET) && !validateWebSocketRequest(request, asyncHandler)) { throw new IOException("WebSocket method must be a GET"); @@ -1081,9 +1074,9 @@ private ListenableFuture doConnect(final Request request, final AsyncHand try { InetSocketAddress remoteAddress; if (request.getInetAddress() != null) { - remoteAddress = new InetSocketAddress(request.getInetAddress(), AsyncHttpProviderUtils.getPort(uri)); + remoteAddress = new InetSocketAddress(request.getInetAddress(), AsyncHttpProviderUtils.getDefaultPort(uri)); } else if (!useProxy) { - remoteAddress = new InetSocketAddress(AsyncHttpProviderUtils.getHost(uri), AsyncHttpProviderUtils.getPort(uri)); + remoteAddress = new InetSocketAddress(uri.getHost(), AsyncHttpProviderUtils.getDefaultPort(uri)); } else { remoteAddress = new InetSocketAddress(proxyServer.getHost(), proxyServer.getPort()); } @@ -1226,8 +1219,8 @@ public void messageReceived(final ChannelHandlerContext ctx, MessageEvent e) thr private Realm kerberosChallenge(List proxyAuth, Request request, ProxyServer proxyServer, FluentCaseInsensitiveStringsMap headers, Realm realm, NettyResponseFuture future, boolean proxyInd) throws NTLMEngineException { - URI uri = request.getURI(); - String host = request.getVirtualHost() == null ? AsyncHttpProviderUtils.getHost(uri) : request.getVirtualHost(); + UriComponents uri = request.getURI(); + String host = request.getVirtualHost() != null ? request.getVirtualHost(): uri.getHost(); String server = proxyServer == null ? host : proxyServer.getHost(); try { String challengeHeader = getSpnegoEngine().generateToken(server); @@ -1240,7 +1233,7 @@ private Realm kerberosChallenge(List proxyAuth, Request request, ProxySe } else { realmBuilder = new Realm.RealmBuilder(); } - return realmBuilder.setUri(uri.getRawPath()).setMethodName(request.getMethod()).setScheme(Realm.AuthScheme.KERBEROS).build(); + return realmBuilder.setUri(uri.getPath()).setMethodName(request.getMethod()).setScheme(Realm.AuthScheme.KERBEROS).build(); } catch (Throwable throwable) { if (isNTLM(proxyAuth)) { return ntlmChallenge(proxyAuth, request, proxyServer, headers, realm, future, proxyInd); @@ -1284,9 +1277,9 @@ private Realm ntlmChallenge(List wwwAuth, Request request, ProxyServer p if (realm != null && !realm.isNtlmMessageType2Received()) { String challengeHeader = ntlmEngine.generateType1Msg(ntlmDomain, ntlmHost); - URI uri = request.getURI(); + UriComponents uri = request.getURI(); addNTLMAuthorization(headers, challengeHeader, proxyInd); - newRealm = new Realm.RealmBuilder().clone(realm).setScheme(realm.getAuthScheme()).setUri(uri.getRawPath()).setMethodName(request.getMethod()) + newRealm = new Realm.RealmBuilder().clone(realm).setScheme(realm.getAuthScheme()).setUri(uri.getPath()).setMethodName(request.getMethod()) .setNtlmMessageType2Received(true).build(); future.getAndSetAuth(false); } else { @@ -1327,7 +1320,7 @@ private String getPoolKey(NettyResponseFuture future) { return getPoolKey(future.getURI(), future.getProxyServer(), future.getConnectionPoolKeyStrategy()); } - private String getPoolKey(URI uri, ProxyServer proxy, ConnectionPoolKeyStrategy strategy) { + private String getPoolKey(UriComponents uri, ProxyServer proxy, ConnectionPoolKeyStrategy strategy) { String serverPart = strategy.getKey(uri); return proxy != null ? proxy.getUrl() + serverPart : serverPart; } @@ -1711,7 +1704,7 @@ protected static boolean abortOnWriteCloseException(Throwable cause) { return false; } - public static NettyResponseFuture newFuture(URI uri, Request request, AsyncHandler asyncHandler, HttpRequest nettyRequest, AsyncHttpClientConfig config, + public static NettyResponseFuture newFuture(UriComponents uri, Request request, AsyncHandler asyncHandler, HttpRequest nettyRequest, AsyncHttpClientConfig config, NettyAsyncHttpProvider provider, ProxyServer proxyServer) { NettyResponseFuture f = new NettyResponseFuture(uri,// @@ -1965,23 +1958,28 @@ private boolean redirect(Request request, NettyResponseFuture future, HttpRes future.getAndSetAuth(false); String location = response.getHeader(HttpHeaders.Names.LOCATION); - 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()); + UriComponents uri = UriComponents.create(future.getURI(), location); + if (!uri.equals(future.getURI())) { + final RequestBuilder nBuilder = new RequestBuilder(future.getRequest()); + if (config.isRemoveQueryParamOnRedirect()) + nBuilder.setQueryParameters(null); + if (!(statusCode < 302 || statusCode > 303) && !(statusCode == 302 && config.isStrict302Handling())) { nBuilder.setMethod("GET"); } final boolean initialConnectionKeepAlive = future.getKeepAlive(); final String initialPoolKey = getPoolKey(future); future.setURI(uri); - String newUrl = uri.toString(); - if (request.getURI().getScheme().startsWith(WEBSOCKET)) { - newUrl = newUrl.replace(HTTP, WEBSOCKET); + UriComponents newURI = uri; + String targetScheme = request.getURI().getScheme(); + if (targetScheme.equals(WEBSOCKET)) { + newURI = newURI.withNewScheme(WEBSOCKET); + }if (targetScheme.equals(WEBSOCKET_SSL)) { + newURI = newURI.withNewScheme(WEBSOCKET_SSL); } - log.debug("Redirecting to {}", newUrl); + log.debug("Redirecting to {}", newURI); List setCookieHeaders = future.getHttpResponse().getHeaders(HttpHeaders.Names.SET_COOKIE2); if (!isNonEmpty(setCookieHeaders)) { setCookieHeaders = future.getHttpResponse().getHeaders(HttpHeaders.Names.SET_COOKIE); @@ -2007,7 +2005,7 @@ public Object call() throws Exception { } else { ac.call(); } - nextRequest(nBuilder.setUrl(newUrl).build(), future); + nextRequest(nBuilder.setURI(newURI).build(), future); return true; } } else { @@ -2017,16 +2015,11 @@ public Object call() throws Exception { return false; } - private final String computeRealmURI(Realm realm, URI requestURI) throws URISyntaxException { + private final String computeRealmURI(Realm realm, UriComponents requestURI) { if (realm.isUseAbsoluteURI()) { if (realm.isOmitQuery() && MiscUtil.isNonEmpty(requestURI.getQuery())) { - return new URI( - requestURI.getScheme(), - requestURI.getAuthority(), - requestURI.getPath(), - null, - null).toString(); + return requestURI.withNewQuery(null).toString(); } else { return requestURI.toString(); } @@ -2486,7 +2479,7 @@ private static boolean isSecure(String scheme) { return HTTPS.equalsIgnoreCase(scheme) || WEBSOCKET_SSL.equalsIgnoreCase(scheme); } - private static boolean isSecure(URI uri) { + private static boolean isSecure(UriComponents uri) { return isSecure(uri.getScheme()); } } 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 5542e3ae2c..de6ed82eb4 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 @@ -20,6 +20,7 @@ import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.ProxyServer; import com.ning.http.client.Request; +import com.ning.http.client.uri.UriComponents; import com.ning.http.util.AllowAllHostnameVerifier; import com.ning.http.util.ProxyUtils; @@ -37,7 +38,6 @@ import java.io.IOException; import java.net.ConnectException; import java.net.InetSocketAddress; -import java.net.URI; import java.nio.channels.ClosedChannelException; import java.util.concurrent.atomic.AtomicBoolean; @@ -139,7 +139,7 @@ public Builder(AsyncHttpClientConfig config, Request request, AsyncHandler as this.buffer = buffer; } - public NettyConnectListener build(final URI uri) throws IOException { + public NettyConnectListener build(final UriComponents uri) throws IOException { ProxyServer proxyServer = ProxyUtils.getProxyServer(config, request); HttpRequest nettyRequest = NettyAsyncHttpProvider.buildRequest(config, request, uri, true, buffer, proxyServer); if (future == null) { 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 3720683b47..02c8d48509 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 @@ -19,8 +19,6 @@ import java.io.IOException; 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; @@ -39,6 +37,7 @@ import com.ning.http.client.Response; import com.ning.http.client.cookie.Cookie; import com.ning.http.client.cookie.CookieDecoder; +import com.ning.http.client.uri.UriComponents; import com.ning.http.util.AsyncHttpProviderUtils; /** @@ -138,8 +137,8 @@ private Charset computeCharset(String charset) { /* @Override */ - public URI getUri() throws MalformedURLException { - return status.getUrl(); + public UriComponents getUri() { + return status.getUri(); } /* @Override */ 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 0d2d6355e2..b10823b193 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 @@ -18,7 +18,6 @@ import static com.ning.http.util.DateUtil.millisTime; import java.net.SocketAddress; -import java.net.URI; import java.util.concurrent.CancellationException; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutionException; @@ -42,6 +41,7 @@ import com.ning.http.client.Request; import com.ning.http.client.listenable.AbstractListenableFuture; import com.ning.http.client.providers.netty.timeout.TimeoutsHolder; +import com.ning.http.client.uri.UriComponents; /** * A {@link Future} that can be used to track when an asynchronous HTTP request has been fully processed. @@ -66,7 +66,7 @@ enum STATE { private Request request; private HttpRequest nettyRequest; private final AtomicReference content = new AtomicReference(); - private URI uri; + private UriComponents uri; private boolean keepAlive = true; private HttpResponse httpResponse; private final AtomicReference exEx = new AtomicReference(); @@ -92,7 +92,7 @@ enum STATE { private final ConnectionPoolKeyStrategy connectionPoolKeyStrategy; private final ProxyServer proxyServer; - public NettyResponseFuture(URI uri,// + public NettyResponseFuture(UriComponents uri,// Request request,// AsyncHandler asyncHandler,// HttpRequest nettyRequest,// @@ -121,11 +121,11 @@ public NettyResponseFuture(URI uri,// writeBody = true; } - protected URI getURI() { + protected UriComponents getURI() { return uri; } - protected void setURI(URI uri) { + protected void setURI(UriComponents uri) { this.uri = uri; } 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 6a914d1bf0..2820d877b0 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 @@ -17,13 +17,14 @@ import com.ning.http.client.AsyncHttpProvider; import com.ning.http.client.HttpResponseBodyPart; +import com.ning.http.client.uri.UriComponents; + import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.handler.codec.http.HttpChunk; import org.jboss.netty.handler.codec.http.HttpResponse; import java.io.IOException; import java.io.OutputStream; -import java.net.URI; import java.nio.ByteBuffer; import java.util.concurrent.atomic.AtomicReference; @@ -38,11 +39,11 @@ public class ResponseBodyPart extends HttpResponseBodyPart { private final int length; private boolean closeConnection = false; - public ResponseBodyPart(URI uri, HttpResponse response, AsyncHttpProvider provider, boolean last) { + public ResponseBodyPart(UriComponents uri, HttpResponse response, AsyncHttpProvider provider, boolean last) { this(uri, response, provider, null, last); } - public ResponseBodyPart(URI uri, HttpResponse response, AsyncHttpProvider provider, HttpChunk chunk, boolean last) { + public ResponseBodyPart(UriComponents uri, HttpResponse response, AsyncHttpProvider provider, HttpChunk chunk, boolean last) { super(uri, provider); content = chunk != null ? chunk.getContent() : response.getContent(); length = content.readableBytes(); 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 3e552c9da8..259e852c44 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 @@ -18,10 +18,11 @@ import com.ning.http.client.AsyncHttpProvider; import com.ning.http.client.FluentCaseInsensitiveStringsMap; import com.ning.http.client.HttpResponseHeaders; +import com.ning.http.client.uri.UriComponents; + import org.jboss.netty.handler.codec.http.HttpChunkTrailer; import org.jboss.netty.handler.codec.http.HttpResponse; -import java.net.URI; import java.util.Map; /** @@ -33,14 +34,14 @@ public class ResponseHeaders extends HttpResponseHeaders { private final HttpResponse response; private final FluentCaseInsensitiveStringsMap headers; - public ResponseHeaders(URI uri, HttpResponse response, AsyncHttpProvider provider) { + public ResponseHeaders(UriComponents uri, HttpResponse response, AsyncHttpProvider provider) { super(uri, provider, false); this.trailingHeaders = null; this.response = response; headers = computerHeaders(); } - public ResponseHeaders(URI uri, HttpResponse response, AsyncHttpProvider provider, HttpChunkTrailer traillingHeaders) { + public ResponseHeaders(UriComponents uri, HttpResponse response, AsyncHttpProvider provider, HttpChunkTrailer traillingHeaders) { super(uri, provider, true); this.trailingHeaders = traillingHeaders; this.response = response; diff --git a/src/main/java/com/ning/http/client/providers/netty/ResponseStatus.java b/src/main/java/com/ning/http/client/providers/netty/ResponseStatus.java index 12024ecaa6..9de7f8f928 100644 --- a/src/main/java/com/ning/http/client/providers/netty/ResponseStatus.java +++ b/src/main/java/com/ning/http/client/providers/netty/ResponseStatus.java @@ -18,9 +18,9 @@ import com.ning.http.client.AsyncHttpProvider; import com.ning.http.client.HttpResponseStatus; -import org.jboss.netty.handler.codec.http.HttpResponse; +import com.ning.http.client.uri.UriComponents; -import java.net.URI; +import org.jboss.netty.handler.codec.http.HttpResponse; /** * A class that represent the HTTP response' status line (code + text) @@ -29,7 +29,7 @@ public class ResponseStatus extends HttpResponseStatus { private final HttpResponse response; - public ResponseStatus(URI uri, HttpResponse response, AsyncHttpProvider provider) { + public ResponseStatus(UriComponents uri, HttpResponse response, AsyncHttpProvider provider) { super(uri, provider); this.response = response; } diff --git a/src/main/java/com/ning/http/client/providers/netty/timeout/IdleConnectionTimeoutTimerTask.java b/src/main/java/com/ning/http/client/providers/netty/timeout/IdleConnectionTimeoutTimerTask.java index 316e7505fc..1f6b78db91 100644 --- a/src/main/java/com/ning/http/client/providers/netty/timeout/IdleConnectionTimeoutTimerTask.java +++ b/src/main/java/com/ning/http/client/providers/netty/timeout/IdleConnectionTimeoutTimerTask.java @@ -1,17 +1,14 @@ /* - * Copyright 2010-2013 Ning, Inc. + * Copyright (c) 2014 AsyncHttpClient Project. All rights reserved. * - * 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: + * 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. * - * 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. + * 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.providers.netty.timeout; diff --git a/src/main/java/com/ning/http/client/providers/netty/timeout/RequestTimeoutTimerTask.java b/src/main/java/com/ning/http/client/providers/netty/timeout/RequestTimeoutTimerTask.java index fa200a4f0e..01272605b3 100644 --- a/src/main/java/com/ning/http/client/providers/netty/timeout/RequestTimeoutTimerTask.java +++ b/src/main/java/com/ning/http/client/providers/netty/timeout/RequestTimeoutTimerTask.java @@ -1,17 +1,14 @@ /* - * Copyright 2010-2013 Ning, Inc. + * Copyright (c) 2014 AsyncHttpClient Project. All rights reserved. * - * 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: + * 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. * - * 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. + * 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.providers.netty.timeout; diff --git a/src/main/java/com/ning/http/client/providers/netty/timeout/TimeoutTimerTask.java b/src/main/java/com/ning/http/client/providers/netty/timeout/TimeoutTimerTask.java index dbabeaa4f1..4d5888f810 100644 --- a/src/main/java/com/ning/http/client/providers/netty/timeout/TimeoutTimerTask.java +++ b/src/main/java/com/ning/http/client/providers/netty/timeout/TimeoutTimerTask.java @@ -1,17 +1,14 @@ /* - * Copyright 2010-2013 Ning, Inc. + * Copyright (c) 2014 AsyncHttpClient Project. All rights reserved. * - * 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: + * 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. * - * 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. + * 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.providers.netty.timeout; diff --git a/src/main/java/com/ning/http/client/providers/netty/timeout/TimeoutsHolder.java b/src/main/java/com/ning/http/client/providers/netty/timeout/TimeoutsHolder.java index 6cd4db8915..33797b80a2 100644 --- a/src/main/java/com/ning/http/client/providers/netty/timeout/TimeoutsHolder.java +++ b/src/main/java/com/ning/http/client/providers/netty/timeout/TimeoutsHolder.java @@ -1,17 +1,14 @@ /* - * Copyright 2010-2013 Ning, Inc. + * Copyright (c) 2014 AsyncHttpClient Project. All rights reserved. * - * 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: + * 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. * - * 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. + * 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.providers.netty.timeout; 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 5e87b28d7d..a928b93dd5 100644 --- a/src/main/java/com/ning/http/client/resumable/ResumableAsyncHandler.java +++ b/src/main/java/com/ning/http/client/resumable/ResumableAsyncHandler.java @@ -104,7 +104,7 @@ public ResumableAsyncHandler(ResumableProcessor resumableProcessor, boolean accu public AsyncHandler.STATE onStatusReceived(final HttpResponseStatus status) throws Exception { responseBuilder.accumulate(status); if (status.getStatusCode() == 200 || status.getStatusCode() == 206) { - url = status.getUrl().toURL().toString(); + url = status.getUri().toString(); } else { return AsyncHandler.STATE.ABORT; } diff --git a/src/main/java/com/ning/http/client/uri/UriComponents.java b/src/main/java/com/ning/http/client/uri/UriComponents.java new file mode 100644 index 0000000000..5ba4f30cc9 --- /dev/null +++ b/src/main/java/com/ning/http/client/uri/UriComponents.java @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2014 AsyncHttpClient Project. 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.uri; + +import java.net.URI; +import java.net.URISyntaxException; + +public class UriComponents { + + public static UriComponents create(String originalUrl) { + return create(null, originalUrl); + } + + public static UriComponents create(UriComponents context, final String originalUrl) { + UriComponentsParser parser = new UriComponentsParser(); + parser.parse(context, originalUrl); + + return new UriComponents( + parser.scheme,// + parser.userInfo,// + parser.host,// + parser.port,// + parser.path,// + parser.query); + } + + private final String scheme; + private final String userInfo; + private final String host; + private final int port; + private final String query; + private final String path; + + public UriComponents( + String scheme,// + String userInfo,// + String host,// + int port,// + String path,// + String query) { + + if (scheme == null) + throw new NullPointerException("scheme"); + if (host == null) + throw new NullPointerException("host"); + + this.scheme = scheme; + this.userInfo = userInfo; + this.host = host; + this.port = port; + this.path = path; + this.query = query; + } + + public String getQuery() { + return query; + } + + public String getPath() { + return path; + } + + public String getUserInfo() { + return userInfo; + } + + public int getPort() { + return port; + } + + public String getScheme() { + return scheme; + } + + public String getHost() { + return host; + } + + public URI toURI() throws URISyntaxException { + return new URI(scheme, userInfo, host, port, path, query, null); + } + + @Override + public String toString() { + + StringBuilder sb = new StringBuilder(); + sb.append(scheme).append("://"); + if (userInfo != null) + sb.append(userInfo).append('@'); + sb.append(host); + if (port != -1) + sb.append(':').append(port); + if (path != null) + sb.append(path); + if (query != null) + sb.append('?').append(query); + + return sb.toString(); + } + + public UriComponents withNewScheme(String newScheme) { + return new UriComponents( + newScheme,// + userInfo,// + host,// + port,// + path,// + query); + } + + public UriComponents withNewQuery(String newQuery) { + return new UriComponents( + scheme,// + userInfo,// + host,// + port,// + path,// + newQuery); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((host == null) ? 0 : host.hashCode()); + result = prime * result + ((path == null) ? 0 : path.hashCode()); + result = prime * result + port; + result = prime * result + ((query == null) ? 0 : query.hashCode()); + result = prime * result + ((scheme == null) ? 0 : scheme.hashCode()); + result = prime * result + ((userInfo == null) ? 0 : userInfo.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + UriComponents other = (UriComponents) obj; + if (host == null) { + if (other.host != null) + return false; + } else if (!host.equals(other.host)) + return false; + if (path == null) { + if (other.path != null) + return false; + } else if (!path.equals(other.path)) + return false; + if (port != other.port) + return false; + if (query == null) { + if (other.query != null) + return false; + } else if (!query.equals(other.query)) + return false; + if (scheme == null) { + if (other.scheme != null) + return false; + } else if (!scheme.equals(other.scheme)) + return false; + if (userInfo == null) { + if (other.userInfo != null) + return false; + } else if (!userInfo.equals(other.userInfo)) + return false; + return true; + } +} diff --git a/src/main/java/com/ning/http/client/uri/UriComponentsParser.java b/src/main/java/com/ning/http/client/uri/UriComponentsParser.java new file mode 100644 index 0000000000..2293b49ac8 --- /dev/null +++ b/src/main/java/com/ning/http/client/uri/UriComponentsParser.java @@ -0,0 +1,341 @@ +/* + * Copyright (c) 2014 AsyncHttpClient Project. 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.uri; + + +final class UriComponentsParser { + + public String scheme; + public String host; + public int port = -1; + public String query; + public String authority; + public String path; + public String userInfo; + + private int start, end = 0; + private String urlWithoutQuery; + + private void trimRight(String originalUrl) { + end = originalUrl.length(); + while (end > 0 && originalUrl.charAt(end - 1) <= ' ') + end--; + } + + private void trimLeft(String originalUrl) { + while (start < end && originalUrl.charAt(start) <= ' ') + start++; + + if (originalUrl.regionMatches(true, start, "url:", 0, 4)) + start += 4; + } + + private boolean isFragmentOnly(String originalUrl) { + return start < originalUrl.length() && originalUrl.charAt(start) == '#'; + } + + private boolean isValidProtocolChar(char c) { + return Character.isLetterOrDigit(c) && c != '.' && c != '+' && c != '-'; + } + + private boolean isValidProtocolChars(String protocol) { + for (int i = 1; i < protocol.length(); i++) { + if (!isValidProtocolChar(protocol.charAt(i))) + return false; + } + return true; + } + + private boolean isValidProtocol(String protocol) { + return protocol.length() > 0 && Character.isLetter(protocol.charAt(0)) && isValidProtocolChars(protocol); + } + + private void computeInitialScheme(String originalUrl) { + for (int i = start; i < end; i++) { + char c = originalUrl.charAt(i); + if (c == ':') { + String s = originalUrl.substring(start, i); + if (isValidProtocol(s)) { + scheme = s.toLowerCase(); + start = i + 1; + } + break; + } else if (c == '/') + break; + } + } + + private boolean overrideWithContext(UriComponents context, String originalUrl) { + + boolean isRelative = false; + + // only use context if the schemes match + if (context != null && (scheme == null || scheme.equalsIgnoreCase(context.getScheme()))) { + + // see RFC2396 5.2.3 + String contextPath = context.getPath(); + if (isNotEmpty(contextPath) && contextPath.charAt(0) == '/') + scheme = null; + + if (scheme == null) { + scheme = context.getScheme(); + userInfo = context.getUserInfo(); + host = context.getHost(); + port = context.getPort(); + path = contextPath; + isRelative = true; + } + } + return isRelative; + } + + private void computeFragment(String originalUrl) { + int charpPosition = originalUrl.indexOf('#', start); + if (charpPosition >= 0) { + end = charpPosition; + } + } + + private void inheritContextQuery(UriComponents context, boolean isRelative) { + // see RFC2396 5.2.2: query and fragment inheritance + if (isRelative && start == end) { + query = context.getQuery(); + } + } + + private boolean splitUrlAndQuery(String originalUrl) { + boolean queryOnly = false; + urlWithoutQuery = originalUrl; + if (start < end) { + int askPosition = originalUrl.indexOf('?'); + queryOnly = askPosition == start; + if (askPosition != -1 && askPosition < end) { + query = originalUrl.substring(askPosition + 1, end); + if (end > askPosition) + end = askPosition; + urlWithoutQuery = originalUrl.substring(0, askPosition); + } + } + + return queryOnly; + } + + private boolean currentPositionStartsWith4Slashes() { + return urlWithoutQuery.regionMatches(start, "////", 0, 4); + } + + private boolean currentPositionStartsWith2Slashes() { + return urlWithoutQuery.regionMatches(start, "//", 0, 2); + } + + private void computeAuthority() { + int authorityEndPosition = urlWithoutQuery.indexOf('/', start); + if (authorityEndPosition < 0) { + authorityEndPosition = urlWithoutQuery.indexOf('?', start); + if (authorityEndPosition < 0) + authorityEndPosition = end; + } + host = authority = urlWithoutQuery.substring(start, authorityEndPosition); + start = authorityEndPosition; + } + + private void computeUserInfo() { + int atPosition = authority.indexOf('@'); + if (atPosition != -1) { + userInfo = authority.substring(0, atPosition); + host = authority.substring(atPosition + 1); + } else + userInfo = null; + } + + private boolean isMaybeIPV6() { + // If the host is surrounded by [ and ] then its an IPv6 + // literal address as specified in RFC2732 + return host.length() > 0 && host.charAt(0) == '['; + } + + private void computeIPV6() { + int positionAfterClosingSquareBrace = host.indexOf(']') + 1; + if (positionAfterClosingSquareBrace > 1) { + + port = -1; + + if (host.length() > positionAfterClosingSquareBrace) { + if (host.charAt(positionAfterClosingSquareBrace) == ':') { + // see RFC2396: port can be null + int portPosition = positionAfterClosingSquareBrace + 1; + if (host.length() > portPosition) { + port = Integer.parseInt(host.substring(portPosition)); + } + } else + throw new IllegalArgumentException("Invalid authority field: " + authority); + } + + host = host.substring(0, positionAfterClosingSquareBrace); + + } else + throw new IllegalArgumentException("Invalid authority field: " + authority); + } + + private void computeRegularHostPort() { + int colonPosition = host.indexOf(':'); + port = -1; + if (colonPosition >= 0) { + // see RFC2396: port can be null + int portPosition = colonPosition + 1; + if (host.length() > portPosition) + port = Integer.parseInt(host.substring(portPosition)); + host = host.substring(0, colonPosition); + } + } + + // /./ + private void removeEmbeddedDot() { + path = path.replace("/./", ""); + } + + // /../ + private void removeEmbedded2Dots() { + int i = 0; + while ((i = path.indexOf("/../", i)) >= 0) { + if (i > 0) { + end = path.lastIndexOf('/', i - 1); + if (end >= 0 && path.indexOf("/../", end) != 0) { + path = path.substring(0, end) + path.substring(i + 3); + i = 0; + } + } else + i = i + 3; + } + } + + private void removeTailing2Dots() { + while (path.endsWith("/..")) { + end = path.lastIndexOf('/', path.length() - 4); + if (end >= 0) + path = path.substring(0, end + 1); + else + break; + } + } + + private void removeStartingDot() { + if (path.startsWith("./") && path.length() > 2) + path = path.substring(2); + } + + private void removeTrailingDot() { + if (path.endsWith("/.")) + path = path.substring(0, path.length() - 1); + } + + private void initRelativePath() { + int lastSlashPosition = path.lastIndexOf('/'); + String pathEnd = urlWithoutQuery.substring(start, end); + + if (lastSlashPosition == -1) + path = authority != null ? "/" + pathEnd : pathEnd; + else + path = path.substring(0, lastSlashPosition + 1) + pathEnd; + } + + private void handlePathDots() { + if (path.indexOf('.') != -1) { + removeEmbeddedDot(); + removeEmbedded2Dots(); + removeTailing2Dots(); + removeStartingDot(); + removeTrailingDot(); + } + } + + private void parseAuthority() { + if (!currentPositionStartsWith4Slashes() && currentPositionStartsWith2Slashes()) { + start += 2; + + computeAuthority(); + computeUserInfo(); + + if (host != null) { + if (isMaybeIPV6()) + computeIPV6(); + else + computeRegularHostPort(); + } + + if (port < -1) + throw new IllegalArgumentException("Invalid port number :" + port); + + // see RFC2396 5.2.4: ignore context path if authority is defined + if (isNotEmpty(authority)) + path = ""; + } + } + + private void handleRelativePath() { + initRelativePath(); + handlePathDots(); + } + + private void computeRegularPath() { + if (urlWithoutQuery.charAt(start) == '/') + path = urlWithoutQuery.substring(start, end); + + else if (isNotEmpty(path)) + handleRelativePath(); + + else { + String pathEnd = urlWithoutQuery.substring(start, end); + path = authority != null ? "/" + pathEnd : pathEnd; + } + } + + private void computeQueryOnlyPath() { + int lastSlashPosition = path.lastIndexOf('/'); + path = lastSlashPosition < 0 ? "/" : path.substring(0, lastSlashPosition) + "/"; + } + + private void computePath(boolean queryOnly) { + // Parse the file path if any + if (start < end) + computeRegularPath(); + else if (queryOnly && path != null) + computeQueryOnlyPath(); + else if (path == null) + path = ""; + } + + public void parse(UriComponents context, final String originalUrl) { + + if (originalUrl == null) + throw new NullPointerException("originalUrl"); + + boolean isRelative = false; + + trimRight(originalUrl); + trimLeft(originalUrl); + if (!isFragmentOnly(originalUrl)) + computeInitialScheme(originalUrl); + overrideWithContext(context, originalUrl); + computeFragment(originalUrl); + inheritContextQuery(context, isRelative); + + boolean queryOnly = splitUrlAndQuery(originalUrl); + parseAuthority(); + computePath(queryOnly); + } + + private static boolean isNotEmpty(String string) { + return string != null && string.length() > 0; + } +} \ No newline at end of file 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 d5264c6886..dc7981190b 100644 --- a/src/main/java/com/ning/http/client/webdav/WebDavCompletionHandlerBase.java +++ b/src/main/java/com/ning/http/client/webdav/WebDavCompletionHandlerBase.java @@ -118,7 +118,7 @@ private class HttpStatusWrapper extends HttpResponseStatus { private final int statusCode; public HttpStatusWrapper(HttpResponseStatus wrapper, String statusText, int statusCode) { - super(wrapper.getUrl(), wrapper.provider()); + super(wrapper.getUri(), wrapper.provider()); this.wrapper = wrapper; this.statusText = statusText; this.statusCode = statusCode; 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 fb8fdb2b9e..8f52ef6f2a 100644 --- a/src/main/java/com/ning/http/client/webdav/WebDavResponse.java +++ b/src/main/java/com/ning/http/client/webdav/WebDavResponse.java @@ -14,8 +14,6 @@ import java.io.IOException; import java.io.InputStream; -import java.net.MalformedURLException; -import java.net.URI; import java.nio.ByteBuffer; import java.util.List; @@ -24,6 +22,7 @@ import com.ning.http.client.FluentCaseInsensitiveStringsMap; import com.ning.http.client.Response; import com.ning.http.client.cookie.Cookie; +import com.ning.http.client.uri.UriComponents; /** * Customized {@link Response} which add support for getting the response's body as an XML document (@link WebDavResponse#getBodyAsXML} @@ -75,7 +74,7 @@ public String getResponseBody(String charset) throws IOException { return response.getResponseBody(charset); } - public URI getUri() throws MalformedURLException { + public UriComponents getUri() { return response.getUri(); } diff --git a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java index cf5416dd5b..8504ed736d 100644 --- a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java +++ b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java @@ -19,8 +19,6 @@ import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; -import java.net.URI; -import java.net.URISyntaxException; import java.util.List; import com.ning.http.client.AsyncHttpClientConfig; @@ -33,6 +31,7 @@ import com.ning.http.client.Part; import com.ning.http.client.Request; import com.ning.http.client.StringPart; +import com.ning.http.client.uri.UriComponents; import com.ning.http.multipart.ByteArrayPartSource; import com.ning.http.multipart.MultipartRequestEntity; import com.ning.http.multipart.PartSource; @@ -48,7 +47,7 @@ public class AsyncHttpProviderUtils { static final byte[] EMPTY_BYTE_ARRAY = "".getBytes(); - public static final void validateSupportedScheme(URI uri) { + public static final void validateSupportedScheme(UriComponents uri) { final String scheme = uri.getScheme(); if (scheme == null || !scheme.equalsIgnoreCase("http") && !scheme.equalsIgnoreCase("https") && !scheme.equalsIgnoreCase("ws") && !scheme.equalsIgnoreCase("wss")) { @@ -57,8 +56,8 @@ public static final void validateSupportedScheme(URI uri) { } } - public final static URI createNonEmptyPathURI(String u) { - URI uri = URI.create(u); + public final static UriComponents createNonEmptyPathURI(String u) { + UriComponents uri = UriComponents.create(u); validateSupportedScheme(uri); String path = uri.getPath(); @@ -67,24 +66,19 @@ public final static URI createNonEmptyPathURI(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 (!isNonEmpty(path)) { - return URI.create(u + "/"); + return UriComponents.create(u + "/"); } return uri; } - public final static String getBaseUrl(URI uri) { + public final static String getBaseUrl(UriComponents uri) { return uri.getScheme() + "://" + getAuthority(uri); } - public final static String getAuthority(URI uri) { - String url = uri.getAuthority(); - int port = uri.getPort(); - if (port == -1) { - port = getPort(uri); - url += ":" + port; - } - return url; + public final static String getAuthority(UriComponents uri) { + int port = uri.getPort() != -1? uri.getPort() : getDefaultPort(uri); + return uri.getHost() + ":" + port; } public final static String contentToString(List bodyParts, String charset) throws UnsupportedEncodingException { @@ -116,62 +110,7 @@ public final static InputStream contentToInputStream(List 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) { - host = uri.getAuthority(); - } - return host; - } - - public final static URI getRedirectUri(URI uri, String location) { - 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); - - 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.normalize(); - } - - public final static int getPort(URI uri) { + public final static int getDefaultPort(UriComponents uri) { int port = uri.getPort(); if (port == -1) port = uri.getScheme().equals("http") || uri.getScheme().equals("ws") ? 80 : 443; diff --git a/src/main/java/com/ning/http/util/ProxyUtils.java b/src/main/java/com/ning/http/util/ProxyUtils.java index 4b6e3eedc4..36e8c242b1 100644 --- a/src/main/java/com/ning/http/util/ProxyUtils.java +++ b/src/main/java/com/ning/http/util/ProxyUtils.java @@ -16,6 +16,7 @@ import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.ProxyServer; import com.ning.http.client.ProxyServer.Protocol; +import com.ning.http.client.uri.UriComponents; import com.ning.http.client.ProxyServerSelector; import com.ning.http.client.Request; @@ -23,6 +24,7 @@ import java.net.Proxy; import java.net.ProxySelector; import java.net.URI; +import java.net.URISyntaxException; import java.util.List; import java.util.Properties; @@ -93,7 +95,7 @@ public static ProxyServer getProxyServer(AsyncHttpClientConfig config, Request r * @see #avoidProxy(ProxyServer, String) */ public static boolean avoidProxy(final ProxyServer proxyServer, final Request request) { - return avoidProxy(proxyServer, AsyncHttpProviderUtils.getHost(request.getOriginalURI())); + return avoidProxy(proxyServer, request.getOriginalURI().getHost()); } private static boolean matchNonProxyHost(String targetHost, String nonProxyHost) { @@ -198,12 +200,15 @@ public static ProxyServerSelector getJdkDefaultProxyServerSelector() { */ 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()) { + public ProxyServer select(UriComponents uri) { + try { + URI javaUri = uri.toURI(); + + List proxies = proxySelector.select(javaUri); + 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()); @@ -217,10 +222,14 @@ public ProxyServer select(URI uri) { default: log.warn("ProxySelector returned proxy type that we don't know how to use: " + proxy.type()); break; + } } } + return null; + } catch (URISyntaxException e) { + log.warn(uri + " couldn't be turned into a java.net.URI", e); + return null; } - return null; } }; } @@ -233,7 +242,7 @@ public ProxyServer select(URI uri) { */ public static ProxyServerSelector createProxyServerSelector(final ProxyServer proxyServer) { return new ProxyServerSelector() { - public ProxyServer select(URI uri) { + public ProxyServer select(UriComponents uri) { return proxyServer; } }; 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 933dd21cae..c0897b718a 100755 --- a/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java +++ b/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java @@ -1652,7 +1652,7 @@ public void onThrowable(Throwable t) { protected String getBrokenTargetUrl() { return String.format("http:127.0.0.1:%d/foo/test", port1); } - + @Test(groups = { "standalone", "default_provider" }, expectedExceptions = { NullPointerException.class }) public void invalidUri() throws Exception { AsyncHttpClient client = getAsyncHttpClient(null); 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 a476d9adca..16d5a3c907 100644 --- a/src/test/java/com/ning/http/client/async/PerRequestRelative302Test.java +++ b/src/test/java/com/ning/http/client/async/PerRequestRelative302Test.java @@ -18,6 +18,8 @@ import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.Response; +import com.ning.http.client.uri.UriComponents; + import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.Server; @@ -29,9 +31,9 @@ import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; + import java.io.IOException; import java.net.ConnectException; -import java.net.URI; import java.util.Enumeration; import java.util.concurrent.ExecutionException; import java.util.concurrent.atomic.AtomicBoolean; @@ -122,7 +124,7 @@ public void notRedirected302Test() throws Throwable { } } - private String getBaseUrl(URI uri) { + private String getBaseUrl(UriComponents uri) { String url = uri.toString(); int port = uri.getPort(); if (port == -1) { @@ -132,7 +134,7 @@ private String getBaseUrl(URI uri) { return url.substring(0, url.lastIndexOf(":") + String.valueOf(port).length() + 1); } - private static int getPort(URI uri) { + private static int getPort(UriComponents uri) { int port = uri.getPort(); if (port == -1) port = uri.getScheme().equals("http") ? 80 : 443; 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 af49ee6728..69b21ed70a 100644 --- a/src/test/java/com/ning/http/client/async/PostWithQSTest.java +++ b/src/test/java/com/ning/http/client/async/PostWithQSTest.java @@ -92,8 +92,8 @@ 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=")) { - throw new IOException(status.getUrl().toURL().toString()); + if (!status.getUri().toString().equals("http://127.0.0.1:" + port1 + "/?a=")) { + throw new IOException(status.getUri().toString()); } return super.onStatusReceived(status); } @@ -115,7 +115,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.getUri().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); @@ -138,7 +138,7 @@ public void postWithEmptyParamsQS() throws IOException, ExecutionException, Time /* @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.getUri().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); 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 0d189048da..578585c9ad 100644 --- a/src/test/java/com/ning/http/client/async/Relative302Test.java +++ b/src/test/java/com/ning/http/client/async/Relative302Test.java @@ -18,6 +18,8 @@ import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.Response; +import com.ning.http.client.uri.UriComponents; + import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.Server; @@ -29,6 +31,7 @@ import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; + import java.io.IOException; import java.net.ConnectException; import java.net.URI; @@ -105,7 +108,7 @@ public void redirected302Test() throws Throwable { } } - private String getBaseUrl(URI uri) { + private String getBaseUrl(UriComponents uri) { String url = uri.toString(); int port = uri.getPort(); if (port == -1) { @@ -115,7 +118,7 @@ private String getBaseUrl(URI uri) { return url.substring(0, url.lastIndexOf(":") + String.valueOf(port).length() + 1); } - private static int getPort(URI uri) { + private static int getPort(UriComponents uri) { int port = uri.getPort(); if (port == -1) port = uri.getScheme().equals("http") ? 80 : 443; diff --git a/src/test/java/com/ning/http/client/uri/UrlComponentsTest.java b/src/test/java/com/ning/http/client/uri/UrlComponentsTest.java new file mode 100644 index 0000000000..229992fb8b --- /dev/null +++ b/src/test/java/com/ning/http/client/uri/UrlComponentsTest.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2014 AsyncHttpClient Project. 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.uri; + +import org.testng.annotations.Test; + +import static org.testng.Assert.assertEquals; + +public class UrlComponentsTest { + + @Test + public void testSimpleParsing() { + UriComponents url = UriComponents.create("https://graph.facebook.com/750198471659552/accounts/test-users?method=get&access_token=750198471659552lleveCvbUu_zqBa9tkT3tcgaPh4"); + assertEquals(url.getScheme(), "https"); + assertEquals(url.getHost(), "graph.facebook.com"); + assertEquals(url.getPort(), -1); + assertEquals(url.getPath(), "/750198471659552/accounts/test-users"); + assertEquals(url.getQuery(), "method=get&access_token=750198471659552lleveCvbUu_zqBa9tkT3tcgaPh4"); + } + + @Test + public void testRootRelativeURIWithRootContext() { + + UriComponents context = UriComponents.create("https://graph.facebook.com"); + + UriComponents url = UriComponents.create(context, "/750198471659552/accounts/test-users?method=get&access_token=750198471659552lleveCvbUu_zqBa9tkT3tcgaPh4"); + + assertEquals(url.getScheme(), "https"); + assertEquals(url.getHost(), "graph.facebook.com"); + assertEquals(url.getPort(), -1); + assertEquals(url.getPath(), "/750198471659552/accounts/test-users"); + assertEquals(url.getQuery(), "method=get&access_token=750198471659552lleveCvbUu_zqBa9tkT3tcgaPh4"); + } + + @Test + public void testRootRelativeURIWithNonRootContext() { + + UriComponents context = UriComponents.create("https://graph.facebook.com/foo/bar"); + + UriComponents url = UriComponents.create(context, "/750198471659552/accounts/test-users?method=get&access_token=750198471659552lleveCvbUu_zqBa9tkT3tcgaPh4"); + + assertEquals(url.getScheme(), "https"); + assertEquals(url.getHost(), "graph.facebook.com"); + assertEquals(url.getPort(), -1); + assertEquals(url.getPath(), "/750198471659552/accounts/test-users"); + assertEquals(url.getQuery(), "method=get&access_token=750198471659552lleveCvbUu_zqBa9tkT3tcgaPh4"); + } + + @Test + public void testNonRootRelativeURIWithNonRootContext() { + + UriComponents context = UriComponents.create("https://graph.facebook.com/foo/bar"); + + UriComponents url = UriComponents.create(context, "750198471659552/accounts/test-users?method=get&access_token=750198471659552lleveCvbUu_zqBa9tkT3tcgaPh4"); + + assertEquals(url.getScheme(), "https"); + assertEquals(url.getHost(), "graph.facebook.com"); + assertEquals(url.getPort(), -1); + assertEquals(url.getPath(), "/foo/750198471659552/accounts/test-users"); + assertEquals(url.getQuery(), "method=get&access_token=750198471659552lleveCvbUu_zqBa9tkT3tcgaPh4"); + } + + @Test + public void testAbsoluteURIWithContext() { + + UriComponents context = UriComponents.create("https://hello.com/foo/bar"); + + UriComponents url = UriComponents.create(context, "https://graph.facebook.com/750198471659552/accounts/test-users?method=get&access_token=750198471659552lleveCvbUu_zqBa9tkT3tcgaPh4"); + + assertEquals(url.getScheme(), "https"); + assertEquals(url.getHost(), "graph.facebook.com"); + assertEquals(url.getPort(), -1); + assertEquals(url.getPath(), "/750198471659552/accounts/test-users"); + assertEquals(url.getQuery(), "method=get&access_token=750198471659552lleveCvbUu_zqBa9tkT3tcgaPh4"); + } +} + diff --git a/src/test/java/com/ning/http/util/AsyncHttpProviderUtilsTest.java b/src/test/java/com/ning/http/util/AsyncHttpProviderUtilsTest.java deleted file mode 100644 index 7a1bdd26c5..0000000000 --- a/src/test/java/com/ning/http/util/AsyncHttpProviderUtilsTest.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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 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()); - } - - @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 d23f6f39c58468cc266df71fc10aa7df6f031a41 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 2 Jul 2014 18:33:05 +0200 Subject: [PATCH 333/701] Re-enable Content-Type charset extraction test --- .../com/ning/http/client/async/RequestBuilderTest.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/test/java/com/ning/http/client/async/RequestBuilderTest.java b/src/test/java/com/ning/http/client/async/RequestBuilderTest.java index b478e7a3ff..a0ddeab357 100644 --- a/src/test/java/com/ning/http/client/async/RequestBuilderTest.java +++ b/src/test/java/com/ning/http/client/async/RequestBuilderTest.java @@ -113,10 +113,11 @@ public void testPercentageEncodedUserInfo() { assertEquals(req.getUrl(), "http://hello:wor%20ld@foo.com"); } + @Test(groups = {"standalone", "default_provider"}) public void testContentTypeCharsetToBodyEncoding() { - final Request req = new RequestBuilder("GET").setHeader("Content-Type", "application/json; charset=utf-8").build(); - assertEquals(req.getBodyEncoding(), "utf-8"); - final Request req2 = new RequestBuilder("GET").setHeader("Content-Type", "application/json; charset=\"utf-8\"").build(); - assertEquals(req2.getBodyEncoding(), "utf-8"); + final Request req = new RequestBuilder("GET").setHeader("Content-Type", "application/json; charset=XXXX").build(); + assertEquals(req.getBodyEncoding(), "XXXX"); + final Request req2 = new RequestBuilder("GET").setHeader("Content-Type", "application/json; charset=\"XXXX\"").build(); + assertEquals(req2.getBodyEncoding(), "XXXX"); } } From 46d633dda65cd28e7a65874808a16e69e222c03e Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 2 Jul 2014 18:34:31 +0200 Subject: [PATCH 334/701] Add succeeding test from https://github.com/neotyk/http.async.client/issues/54, close #447 --- .../com/ning/http/client/async/RequestBuilderTest.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/test/java/com/ning/http/client/async/RequestBuilderTest.java b/src/test/java/com/ning/http/client/async/RequestBuilderTest.java index a0ddeab357..5371d9b98d 100644 --- a/src/test/java/com/ning/http/client/async/RequestBuilderTest.java +++ b/src/test/java/com/ning/http/client/async/RequestBuilderTest.java @@ -120,4 +120,14 @@ public void testContentTypeCharsetToBodyEncoding() { final Request req2 = new RequestBuilder("GET").setHeader("Content-Type", "application/json; charset=\"XXXX\"").build(); assertEquals(req2.getBodyEncoding(), "XXXX"); } + + @Test(groups = {"standalone", "default_provider"}) + public void testAddQueryParameterReadRawUrl() throws UnsupportedEncodingException { + RequestBuilder rb = new RequestBuilder("GET", true).setUrl("http://example.com/path") + .addQueryParameter("a", "1?&") + .addQueryParameter("b", "+ ="); + Request request = rb.build(); + assertEquals(request.getUrl(), "http://example.com/path?a=1%3F%26&b=%2B%20%3D"); + assertEquals(request.getRawUrl(), "http://example.com/path?a=1?&&b=+ ="); + } } From c926af55df499292c498b742e0b94c54fa756626 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 3 Jul 2014 01:07:21 +0200 Subject: [PATCH 335/701] typo --- .../uri/{UrlComponentsTest.java => UriComponentsTest.java} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename src/test/java/com/ning/http/client/uri/{UrlComponentsTest.java => UriComponentsTest.java} (99%) diff --git a/src/test/java/com/ning/http/client/uri/UrlComponentsTest.java b/src/test/java/com/ning/http/client/uri/UriComponentsTest.java similarity index 99% rename from src/test/java/com/ning/http/client/uri/UrlComponentsTest.java rename to src/test/java/com/ning/http/client/uri/UriComponentsTest.java index 229992fb8b..45e98ac9e9 100644 --- a/src/test/java/com/ning/http/client/uri/UrlComponentsTest.java +++ b/src/test/java/com/ning/http/client/uri/UriComponentsTest.java @@ -16,7 +16,7 @@ import static org.testng.Assert.assertEquals; -public class UrlComponentsTest { +public class UriComponentsTest { @Test public void testSimpleParsing() { From 340bc79137e6c7f2c6266338404278ae52c8ca72 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 4 Jul 2014 13:27:00 +0200 Subject: [PATCH 336/701] Bump 1.9.0-SNAPSHOT --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 3f51f1ef8e..201d84a35f 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.8.13-SNAPSHOT + 1.9.0-SNAPSHOT jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From ad77819eadbf1800c428a980fb48c56431655648 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 4 Jul 2014 14:02:16 +0200 Subject: [PATCH 337/701] Drop deprecated Request.getLength and getRequestType, close #590 --- src/main/java/com/ning/http/client/Request.java | 16 ---------------- .../com/ning/http/client/RequestBuilderBase.java | 14 -------------- 2 files changed, 30 deletions(-) diff --git a/src/main/java/com/ning/http/client/Request.java b/src/main/java/com/ning/http/client/Request.java index 303deac4b4..88669bc1d5 100644 --- a/src/main/java/com/ning/http/client/Request.java +++ b/src/main/java/com/ning/http/client/Request.java @@ -47,14 +47,6 @@ public static interface EntityWriter { void writeEntity(OutputStream out) throws IOException; } - /** - * Return the request's type (GET, POST, etc.) - * - * @return the request's type (GET, POST, etc.) - * @deprecated - use getMethod - */ - String getReqType(); - /** * Return the request's method name (GET, POST, etc.) * @@ -138,14 +130,6 @@ public static interface EntityWriter { */ BodyGenerator getBodyGenerator(); - /** - * Return the current size of the content-lenght header based on the body's size. - * - * @return the current size of the content-lenght header based on the body's size. - * @deprecated - */ - long getLength(); - /** * Return the current size of the content-lenght header based on the body's size. * diff --git a/src/main/java/com/ning/http/client/RequestBuilderBase.java b/src/main/java/com/ning/http/client/RequestBuilderBase.java index c0f57080f4..e703f0cba9 100644 --- a/src/main/java/com/ning/http/client/RequestBuilderBase.java +++ b/src/main/java/com/ning/http/client/RequestBuilderBase.java @@ -113,11 +113,6 @@ public RequestImpl(Request prototype) { } /* @Override */ - - public String getReqType() { - return getMethod(); - } - public String getMethod() { return method; } @@ -253,15 +248,6 @@ public BodyGenerator getBodyGenerator() { } /* @Override */ - - /** - * @return - * @deprecated - */ - public long getLength() { - return length; - } - public long getContentLength() { return length; } From feeb5042899adbcb4475205eefbb5dc4fe9fad90 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 4 Jul 2014 15:03:56 +0200 Subject: [PATCH 338/701] Drop PerRequestConfig, close #591 --- .../ning/http/client/PerRequestConfig.java | 48 ------------------- .../java/com/ning/http/client/Request.java | 7 ++- .../ning/http/client/RequestBuilderBase.java | 12 ++--- .../apache/ApacheAsyncHttpProvider.java | 28 ++--------- .../grizzly/GrizzlyAsyncHttpProvider.java | 23 ++++----- .../providers/jdk/JDKAsyncHttpProvider.java | 15 ++---- .../netty/NettyAsyncHttpProvider.java | 14 +----- .../http/util/AsyncHttpProviderUtils.java | 2 +- .../client/async/PerRequestTimeoutTest.java | 9 +--- .../NettyRequestThrottleTimeoutTest.java | 4 +- 10 files changed, 29 insertions(+), 133 deletions(-) delete mode 100644 src/main/java/com/ning/http/client/PerRequestConfig.java diff --git a/src/main/java/com/ning/http/client/PerRequestConfig.java b/src/main/java/com/ning/http/client/PerRequestConfig.java deleted file mode 100644 index 9f0d84395d..0000000000 --- a/src/main/java/com/ning/http/client/PerRequestConfig.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * 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; - -/** - * Per request configuration. - * - * @author Hubert Iwaniuk - * @deprecated Per request properties are set on request directly or via builder. This class will be gone in next major release. - */ -public class PerRequestConfig { - private final ProxyServer proxyServer; - private int requestTimeoutInMs; - - public PerRequestConfig() { - this(null, 0); - } - - public PerRequestConfig(ProxyServer proxyServer, int requestTimeoutInMs) { - this.proxyServer = proxyServer; - this.requestTimeoutInMs = requestTimeoutInMs; - } - - public ProxyServer getProxyServer() { - return proxyServer; - } - - public int getRequestTimeoutInMs() { - return requestTimeoutInMs; - } - - public void setRequestTimeoutInMs(int requestTimeoutInMs) { - this.requestTimeoutInMs = requestTimeoutInMs; - } -} diff --git a/src/main/java/com/ning/http/client/Request.java b/src/main/java/com/ning/http/client/Request.java index 88669bc1d5..7222cfe07d 100644 --- a/src/main/java/com/ning/http/client/Request.java +++ b/src/main/java/com/ning/http/client/Request.java @@ -201,11 +201,10 @@ public static interface EntityWriter { boolean isRedirectOverrideSet(); /** - * Return Per request configuration. - * - * @return Per request configuration. + * Overrides the config default value + * @return the request timeout */ - PerRequestConfig getPerRequestConfig(); + int getRequestTimeoutInMs(); /** * Return the HTTP Range header value, or diff --git a/src/main/java/com/ning/http/client/RequestBuilderBase.java b/src/main/java/com/ning/http/client/RequestBuilderBase.java index e703f0cba9..28c4515f5d 100644 --- a/src/main/java/com/ning/http/client/RequestBuilderBase.java +++ b/src/main/java/com/ning/http/client/RequestBuilderBase.java @@ -72,7 +72,7 @@ private static final class RequestImpl implements Request { private Realm realm; private File file; private Boolean followRedirects; - private PerRequestConfig perRequestConfig; + private int requestTimeoutInMs; private long rangeOffset; public String charset; private boolean useRawUrl; @@ -104,7 +104,7 @@ public RequestImpl(Request prototype) { this.realm = prototype.getRealm(); this.file = prototype.getFile(); this.followRedirects = prototype.isRedirectOverrideSet() ? prototype.isRedirectEnabled() : null; - this.perRequestConfig = prototype.getPerRequestConfig(); + this.requestTimeoutInMs = prototype.getRequestTimeoutInMs(); this.rangeOffset = prototype.getRangeOffset(); this.charset = prototype.getBodyEncoding(); this.useRawUrl = prototype.isUseRawUrl(); @@ -291,8 +291,8 @@ public boolean isRedirectOverrideSet() { return followRedirects != null; } - public PerRequestConfig getPerRequestConfig() { - return perRequestConfig; + public int getRequestTimeoutInMs() { + return requestTimeoutInMs; } public long getRangeOffset() { @@ -616,8 +616,8 @@ public T setFollowRedirects(boolean followRedirects) { return derived.cast(this); } - public T setPerRequestConfig(PerRequestConfig perRequestConfig) { - request.perRequestConfig = perRequestConfig; + public T setRequestTimeoutInMs(int requestTimeoutInMs) { + request.requestTimeoutInMs = requestTimeoutInMs; return derived.cast(this); } 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 6986725b26..d15c2fb02f 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 @@ -27,7 +27,6 @@ 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.ProgressAsyncHandler; import com.ning.http.client.ProxyServer; import com.ning.http.client.Realm; @@ -202,7 +201,7 @@ public ListenableFuture execute(Request request, AsyncHandler handler) idleConnectionTimeoutThread = null; } - int requestTimeout = requestTimeout(config, request.getPerRequestConfig()); + int requestTimeout = AsyncHttpProviderUtils.requestTimeout(config, request); if (config.getIdleConnectionTimeoutInMs() > 0 && requestTimeout != -1 && requestTimeout < config.getIdleConnectionTimeoutInMs()) { idleConnectionTimeoutThread = new IdleConnectionTimeoutThread(); idleConnectionTimeoutThread.setConnectionTimeout(config.getIdleConnectionTimeoutInMs()); @@ -469,7 +468,7 @@ public T call() { uri = AsyncHttpProviderUtils.createNonEmptyPathURI(request.getUrl()); } - int delay = requestTimeout(config, future.getRequest().getPerRequestConfig()); + int delay = AsyncHttpProviderUtils.requestTimeout(config, future.getRequest()); if (delay != -1) { ReaperFuture reaperFuture = new ReaperFuture(future); Future scheduledFuture = reaper.scheduleAtFixedRate(reaperFuture, delay, 500, TimeUnit.MILLISECONDS); @@ -665,11 +664,7 @@ private Throwable filterException(Throwable t) { t = new ConnectException(t.getMessage()); } else if (t instanceof NoHttpResponseException) { - int responseTimeoutInMs = config.getRequestTimeoutInMs(); - - if (request.getPerRequestConfig() != null && request.getPerRequestConfig().getRequestTimeoutInMs() != -1) { - responseTimeoutInMs = request.getPerRequestConfig().getRequestTimeoutInMs(); - } + int responseTimeoutInMs = AsyncHttpProviderUtils.requestTimeout(config, request); t = new TimeoutException(String.format("No response received after %s", responseTimeoutInMs)); } else if (t instanceof SSLHandshakeException) { @@ -876,26 +871,11 @@ public synchronized void run() { if (this.apacheResponseFuture != null && this.apacheResponseFuture.hasExpired()) { logger.debug("Request Timeout expired for " + this.apacheResponseFuture); - int requestTimeout = config.getRequestTimeoutInMs(); - PerRequestConfig p = this.apacheResponseFuture.getRequest().getPerRequestConfig(); - if (p != null && p.getRequestTimeoutInMs() != -1) { - requestTimeout = p.getRequestTimeoutInMs(); - } + int requestTimeout = AsyncHttpProviderUtils.requestTimeout(config, this.apacheResponseFuture.getRequest()); apacheResponseFuture.abort(new TimeoutException(String.format("No response received after %s", requestTimeout))); this.apacheResponseFuture = null; } } } - - protected static int requestTimeout(AsyncHttpClientConfig config, PerRequestConfig perRequestConfig) { - int result; - if (perRequestConfig != null) { - int prRequestTimeout = perRequestConfig.getRequestTimeoutInMs(); - result = (prRequestTimeout != 0 ? prRequestTimeout : config.getRequestTimeoutInMs()); - } else { - result = config.getRequestTimeoutInMs(); - } - return result; - } } 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 550ddd372c..65a3c4a4db 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 @@ -120,7 +120,6 @@ 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; import com.ning.http.client.Request; @@ -360,12 +359,9 @@ public long getTimeout(FilterChainContext ctx) { if (context.isWSRequest) { return clientConfig.getWebSocketIdleTimeoutInMs(); } - final PerRequestConfig config = context.request.getPerRequestConfig(); - if (config != null) { - final long timeout = config.getRequestTimeoutInMs(); - if (timeout > 0) { - return timeout; - } + final long timeout = context.request.getRequestTimeoutInMs(); + if (timeout > 0) { + return timeout; } } return timeout; @@ -441,14 +437,11 @@ public void onTimeout(Connection connection) { void touchConnection(final Connection c, final Request request) { - final PerRequestConfig config = request.getPerRequestConfig(); - if (config != null) { - final long timeout = config.getRequestTimeoutInMs(); - if (timeout > 0) { - final long newTimeout = System.currentTimeMillis() + timeout; - if (resolver != null) { - resolver.setTimeoutMillis(c, newTimeout); - } + final long perRequestTimeout = request.getRequestTimeoutInMs(); + if (perRequestTimeout > 0) { + final long newTimeout = System.currentTimeMillis() + perRequestTimeout; + if (resolver != null) { + resolver.setTimeoutMillis(c, newTimeout); } } else { final long timeout = clientConfig.getRequestTimeoutInMs(); 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 972b627b4e..f430e4c3c5 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 @@ -63,7 +63,6 @@ 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.Realm; @@ -153,9 +152,7 @@ public ListenableFuture execute(Request request, AsyncHandler handler, throw new IOException(e.getMessage()); } - PerRequestConfig conf = request.getPerRequestConfig(); - int requestTimeout = (conf != null && conf.getRequestTimeoutInMs() != 0) ? - conf.getRequestTimeoutInMs() : config.getRequestTimeoutInMs(); + int requestTimeout = AsyncHttpProviderUtils.requestTimeout(config, request); JDKDelegateFuture delegate = null; if (future != null) { @@ -434,11 +431,7 @@ private Throwable filterException(Throwable t) { t = new ConnectException(t.getMessage()); } else if (t instanceof SocketTimeoutException) { - int responseTimeoutInMs = config.getRequestTimeoutInMs(); - - if (request.getPerRequestConfig() != null && request.getPerRequestConfig().getRequestTimeoutInMs() != -1) { - responseTimeoutInMs = request.getPerRequestConfig().getRequestTimeoutInMs(); - } + int responseTimeoutInMs = AsyncHttpProviderUtils.requestTimeout(config, request); t = new TimeoutException(String.format("No response received after %s", responseTimeoutInMs)); } else if (t instanceof SSLHandshakeException) { @@ -452,9 +445,7 @@ private Throwable filterException(Throwable t) { private void configure(UriComponents uri, HttpURLConnection urlConnection, Request request) throws IOException, AuthenticationException { - PerRequestConfig conf = request.getPerRequestConfig(); - int requestTimeout = (conf != null && conf.getRequestTimeoutInMs() != 0) ? - conf.getRequestTimeoutInMs() : config.getRequestTimeoutInMs(); + int requestTimeout = AsyncHttpProviderUtils.requestTimeout(config, request); urlConnection.setConnectTimeout(config.getConnectionTimeoutInMs()); 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 911a9ebe82..64913f0486 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 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; @@ -1139,17 +1138,6 @@ private ListenableFuture doConnect(final Request request, final AsyncHand return c.future(); } - protected static int requestTimeoutInMs(AsyncHttpClientConfig config, PerRequestConfig perRequestConfig) { - int result; - if (perRequestConfig != null) { - int prRequestTimeout = perRequestConfig.getRequestTimeoutInMs(); - result = (prRequestTimeout != 0 ? prRequestTimeout : config.getRequestTimeoutInMs()); - } else { - result = config.getRequestTimeoutInMs(); - } - return result; - } - private void closeChannel(final ChannelHandlerContext ctx) { connectionsPool.removeAll(ctx.getChannel()); finishChannel(ctx); @@ -1711,7 +1699,7 @@ public static NettyResponseFuture newFuture(UriComponents uri, Request re request,// asyncHandler,// nettyRequest,// - requestTimeoutInMs(config, request.getPerRequestConfig()),// + AsyncHttpProviderUtils.requestTimeout(config, request),// config.getIdleConnectionTimeoutInMs(),// provider,// request.getConnectionPoolKeyStrategy(),// diff --git a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java index 8504ed736d..a8ac9bde3e 100644 --- a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java +++ b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java @@ -226,6 +226,6 @@ public static String keepAliveHeaderValue(AsyncHttpClientConfig config) { } public static int requestTimeout(AsyncHttpClientConfig config, Request request) { - return (request.getPerRequestConfig() != null && request.getPerRequestConfig().getRequestTimeoutInMs() != 0) ? request.getPerRequestConfig().getRequestTimeoutInMs() : config.getRequestTimeoutInMs(); + return request.getRequestTimeoutInMs() != 0 ? request.getRequestTimeoutInMs() : config.getRequestTimeoutInMs(); } } 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 599775a71b..d74316d545 100644 --- a/src/test/java/com/ning/http/client/async/PerRequestTimeoutTest.java +++ b/src/test/java/com/ning/http/client/async/PerRequestTimeoutTest.java @@ -21,7 +21,6 @@ import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.HttpResponseBodyPart; -import com.ning.http.client.PerRequestConfig; import com.ning.http.client.Response; import org.eclipse.jetty.continuation.Continuation; import org.eclipse.jetty.continuation.ContinuationSupport; @@ -98,10 +97,8 @@ public void run() { @Test(groups = { "standalone", "default_provider" }) public void testRequestTimeout() throws IOException { AsyncHttpClient client = getAsyncHttpClient(null); - PerRequestConfig requestConfig = new PerRequestConfig(); - requestConfig.setRequestTimeoutInMs(100); try { - Future responseFuture = client.prepareGet(getTargetUrl()).setPerRequestConfig(requestConfig).execute(); + Future responseFuture = client.prepareGet(getTargetUrl()).setRequestTimeoutInMs(100).execute(); Response response = responseFuture.get(2000, TimeUnit.MILLISECONDS); assertNull(response); client.close(); @@ -120,10 +117,8 @@ public void testRequestTimeout() throws IOException { @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); try { - Future responseFuture = client.prepareGet(getTargetUrl()).setPerRequestConfig(requestConfig).execute(); + Future responseFuture = client.prepareGet(getTargetUrl()).setRequestTimeoutInMs(-1).execute(); Response response = responseFuture.get(); assertNotNull(response); client.close(); 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 index 9608846d46..c47b0e76e5 100644 --- a/src/test/java/com/ning/http/client/async/netty/NettyRequestThrottleTimeoutTest.java +++ b/src/test/java/com/ning/http/client/async/netty/NettyRequestThrottleTimeoutTest.java @@ -86,12 +86,10 @@ public void testRequestTimeout() throws IOException { 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() { + client.prepareGet(getTargetUrl()).setRequestTimeoutInMs(SLEEPTIME_MS/2).execute(new AsyncCompletionHandler() { @Override public Response onCompleted(Response response) throws Exception { From 39a7b8d9333c2992fc3cf8b4bbe4933f0c714bfe Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 4 Jul 2014 15:30:54 +0200 Subject: [PATCH 339/701] Rename request.getParams into getFormParams, close #592 --- .../com/ning/http/client/AsyncHttpClient.java | 16 ++--- .../java/com/ning/http/client/Request.java | 4 +- .../com/ning/http/client/RequestBuilder.java | 20 +++--- .../ning/http/client/RequestBuilderBase.java | 66 +++++++++---------- .../http/client/SimpleAsyncHttpClient.java | 24 +++---- .../oauth/OAuthSignatureCalculator.java | 2 +- .../apache/ApacheAsyncHttpProvider.java | 4 +- .../grizzly/GrizzlyAsyncHttpProvider.java | 6 +- .../providers/jdk/JDKAsyncHttpProvider.java | 4 +- .../netty/NettyAsyncHttpProvider.java | 6 +- .../client/async/AsyncProvidersBasicTest.java | 8 +-- .../client/async/AsyncStreamHandlerTest.java | 8 +-- .../http/client/async/ParamEncodingTest.java | 2 +- .../client/async/PostRedirectGetTest.java | 4 +- .../client/async/QueryParametersTest.java | 2 +- .../http/client/async/RequestBuilderTest.java | 10 +-- .../client/async/RetryNonBlockingIssue.java | 6 +- 17 files changed, 95 insertions(+), 97 deletions(-) diff --git a/src/main/java/com/ning/http/client/AsyncHttpClient.java b/src/main/java/com/ning/http/client/AsyncHttpClient.java index dba9147698..ea5d24b025 100755 --- a/src/main/java/com/ning/http/client/AsyncHttpClient.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClient.java @@ -249,13 +249,13 @@ public BoundRequestBuilder addHeader(String name, String value) { } @Override - public BoundRequestBuilder addParameter(String key, String value) { - return super.addParameter(key, value); + public BoundRequestBuilder addFormParam(String key, String value) { + return super.addFormParam(key, value); } @Override - public BoundRequestBuilder addQueryParameter(String name, String value) { - return super.addQueryParameter(name, value); + public BoundRequestBuilder addQueryParam(String name, String value) { + return super.addQueryParam(name, value); } @Override @@ -304,13 +304,13 @@ public BoundRequestBuilder setHeaders(Map> headers) { } @Override - public BoundRequestBuilder setParameters(Map> parameters) { - return super.setParameters(parameters); + public BoundRequestBuilder setFormParams(Map> parameters) { + return super.setFormParams(parameters); } @Override - public BoundRequestBuilder setParameters(FluentStringsMap parameters) { - return super.setParameters(parameters); + public BoundRequestBuilder setFormParams(FluentStringsMap parameters) { + return super.setFormParams(parameters); } @Override diff --git a/src/main/java/com/ning/http/client/Request.java b/src/main/java/com/ning/http/client/Request.java index 7222cfe07d..dc4035ca42 100644 --- a/src/main/java/com/ning/http/client/Request.java +++ b/src/main/java/com/ning/http/client/Request.java @@ -138,11 +138,11 @@ public static interface EntityWriter { long getContentLength(); /** - * Return the current parameters. + * Return the current form parameters. * * @return a {@link FluentStringsMap} of parameters. */ - FluentStringsMap getParams(); + FluentStringsMap getFormParams(); /** * Return the current {@link Part} diff --git a/src/main/java/com/ning/http/client/RequestBuilder.java b/src/main/java/com/ning/http/client/RequestBuilder.java index 47bbd5fdf8..724a4b3a61 100644 --- a/src/main/java/com/ning/http/client/RequestBuilder.java +++ b/src/main/java/com/ning/http/client/RequestBuilder.java @@ -65,18 +65,18 @@ public RequestBuilder addHeader(String name, String value) { } @Override - public RequestBuilder addParameter(String key, String value) { - return super.addParameter(key, value); + public RequestBuilder addFormParam(String key, String value) { + return super.addFormParam(key, value); } @Override - public RequestBuilder addQueryParameter(String name, String value) { - return super.addQueryParameter(name, value); + public RequestBuilder addQueryParam(String name, String value) { + return super.addQueryParam(name, value); } @Override - public RequestBuilder setQueryParameters(FluentStringsMap parameters) { - return super.setQueryParameters(parameters); + public RequestBuilder setQueryParam(FluentStringsMap parameters) { + return super.setQueryParam(parameters); } @Override @@ -136,13 +136,13 @@ public RequestBuilder setHeaders(Map> headers) { } @Override - public RequestBuilder setParameters(Map> parameters) { - return super.setParameters(parameters); + public RequestBuilder setFormParams(Map> parameters) { + return super.setFormParams(parameters); } @Override - public RequestBuilder setParameters(FluentStringsMap parameters) { - return super.setParameters(parameters); + public RequestBuilder setFormParams(FluentStringsMap parameters) { + return super.setFormParams(parameters); } @Override diff --git a/src/main/java/com/ning/http/client/RequestBuilderBase.java b/src/main/java/com/ning/http/client/RequestBuilderBase.java index 28c4515f5d..48b15809ea 100644 --- a/src/main/java/com/ning/http/client/RequestBuilderBase.java +++ b/src/main/java/com/ning/http/client/RequestBuilderBase.java @@ -63,7 +63,7 @@ private static final class RequestImpl implements Request { private InputStream streamData; private EntityWriter entityWriter; private BodyGenerator bodyGenerator; - private FluentStringsMap params; + private FluentStringsMap formParams; private List parts; private String virtualHost; private long length = -1; @@ -95,7 +95,7 @@ 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.formParams = prototype.getFormParams() == null ? null : new FluentStringsMap(prototype.getFormParams()); this.queryParams = prototype.getQueryParams() == null ? null : new FluentStringsMap(prototype.getQueryParams()); this.parts = prototype.getParts() == null ? null : new ArrayList(prototype.getParts()); this.virtualHost = prototype.getVirtualHost(); @@ -253,8 +253,8 @@ public long getContentLength() { } /* @Override */ - public FluentStringsMap getParams() { - return params; + public FluentStringsMap getFormParams() { + return formParams; } /* @Override */ @@ -322,13 +322,13 @@ public String toString() { sb.append(headers.getJoinedValue(name, ", ")); } } - if (isNonEmpty(params)) { - sb.append("\tparams:"); - for (String name : params.keySet()) { + if (isNonEmpty(formParams)) { + sb.append("\tformParams:"); + for (String name : formParams.keySet()) { sb.append("\t"); sb.append(name); sb.append(":"); - sb.append(params.getJoinedValue(name, ", ")); + sb.append(formParams.getJoinedValue(name, ", ")); } } @@ -368,7 +368,7 @@ public T setURI(UriComponents uri) { if (uri.getPath() == null) throw new NullPointerException("uri.path"); request.originalUri = uri; - addQueryParameters(request.originalUri); + addQueryParams(request.originalUri); request.uri = null; request.rawUri = null; return derived.cast(this); @@ -384,20 +384,20 @@ public T setLocalInetAddress(InetAddress address) { return derived.cast(this); } - private void addQueryParameters(UriComponents uri) { + private void addQueryParams(UriComponents uri) { if (isNonEmpty(uri.getQuery())) { String[] queries = uri.getQuery().split("&"); int pos; for (String query : queries) { pos = query.indexOf("="); if (pos <= 0) { - addQueryParameter(query, null); + addQueryParam(query, null); } else { try { if (useRawUrl) { - addQueryParameter(query.substring(0, pos), query.substring(pos + 1)); + addQueryParam(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")); + addQueryParam(URLDecoder.decode(query.substring(0, pos), "UTF-8"), URLDecoder.decode(query.substring(pos + 1), "UTF-8")); } } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); @@ -483,12 +483,12 @@ public void resetCookies() { request.cookies.clear(); } - public void resetQueryParameters() { + public void resetQueryParams() { request.queryParams = null; } - public void resetParameters() { - request.params = null; + public void resetFormParams() { + request.formParams = null; } public void resetNonMultipartData() { @@ -509,7 +509,7 @@ public T setBody(File file) { } public T setBody(byte[] data) { - resetParameters(); + resetFormParams(); resetNonMultipartData(); resetMultipartData(); request.byteData = data; @@ -517,7 +517,7 @@ public T setBody(byte[] data) { } public T setBody(String data) { - resetParameters(); + resetFormParams(); resetNonMultipartData(); resetMultipartData(); request.stringData = data; @@ -525,7 +525,7 @@ public T setBody(String data) { } public T setBody(InputStream stream) { - resetParameters(); + resetFormParams(); resetNonMultipartData(); resetMultipartData(); request.streamData = stream; @@ -537,7 +537,7 @@ public T setBody(EntityWriter dataWriter) { } public T setBody(EntityWriter dataWriter, long length) { - resetParameters(); + resetFormParams(); resetNonMultipartData(); resetMultipartData(); request.entityWriter = dataWriter; @@ -550,7 +550,7 @@ public T setBody(BodyGenerator bodyGenerator) { return derived.cast(this); } - public T addQueryParameter(String name, String value) { + public T addQueryParam(String name, String value) { if (request.queryParams == null) { request.queryParams = new FluentStringsMap(); } @@ -558,7 +558,7 @@ public T addQueryParameter(String name, String value) { return derived.cast(this); } - public T setQueryParameters(FluentStringsMap parameters) { + public T setQueryParam(FluentStringsMap parameters) { if (parameters == null) { request.queryParams = null; } else { @@ -567,36 +567,34 @@ public T setQueryParameters(FluentStringsMap parameters) { return derived.cast(this); } - public T addParameter(String key, String value) { + public T addFormParam(String key, String value) { resetNonMultipartData(); resetMultipartData(); - if (request.params == null) { - request.params = new FluentStringsMap(); - } - request.params.add(key, value); + if (request.formParams == null) + request.formParams = new FluentStringsMap(); + request.formParams.add(key, value); return derived.cast(this); } - public T setParameters(FluentStringsMap parameters) { + public T setFormParams(FluentStringsMap parameters) { resetNonMultipartData(); resetMultipartData(); - request.params = new FluentStringsMap(parameters); + request.formParams = new FluentStringsMap(parameters); return derived.cast(this); } - public T setParameters(Map> parameters) { + public T setFormParams(Map> parameters) { resetNonMultipartData(); resetMultipartData(); - request.params = new FluentStringsMap(parameters); + request.formParams = new FluentStringsMap(parameters); return derived.cast(this); } public T addBodyPart(Part part) { - resetParameters(); + resetFormParams(); resetNonMultipartData(); - if (request.parts == null) { + if (request.parts == null) request.parts = new ArrayList(); - } request.parts.add(part); return derived.cast(this); } diff --git a/src/main/java/com/ning/http/client/SimpleAsyncHttpClient.java b/src/main/java/com/ning/http/client/SimpleAsyncHttpClient.java index 09b371edfe..d30ac084e5 100644 --- a/src/main/java/com/ning/http/client/SimpleAsyncHttpClient.java +++ b/src/main/java/com/ning/http/client/SimpleAsyncHttpClient.java @@ -367,9 +367,9 @@ public interface DerivedBuilder { DerivedBuilder setUrl(String url); - DerivedBuilder setParameters(FluentStringsMap parameters); + DerivedBuilder setFormParams(FluentStringsMap parameters); - DerivedBuilder setParameters(Map> parameters); + DerivedBuilder setFormParams(Map> parameters); DerivedBuilder setHeaders(Map> headers); @@ -377,9 +377,9 @@ public interface DerivedBuilder { DerivedBuilder setHeader(String name, String value); - DerivedBuilder addQueryParameter(String name, String value); + DerivedBuilder addQueryParam(String name, String value); - DerivedBuilder addParameter(String key, String value); + DerivedBuilder addFormParam(String key, String value); DerivedBuilder addHeader(String name, String value); @@ -437,13 +437,13 @@ public Builder addHeader(String name, String value) { return this; } - public Builder addParameter(String key, String value) { - requestBuilder.addParameter(key, value); + public Builder addFormParam(String key, String value) { + requestBuilder.addFormParam(key, value); return this; } - public Builder addQueryParameter(String name, String value) { - requestBuilder.addQueryParameter(name, value); + public Builder addQueryParam(String name, String value) { + requestBuilder.addQueryParam(name, value); return this; } @@ -462,13 +462,13 @@ public Builder setHeaders(Map> headers) { return this; } - public Builder setParameters(Map> parameters) { - requestBuilder.setParameters(parameters); + public Builder setFormParams(Map> parameters) { + requestBuilder.setFormParams(parameters); return this; } - public Builder setParameters(FluentStringsMap parameters) { - requestBuilder.setParameters(parameters); + public Builder setFormParams(FluentStringsMap parameters) { + requestBuilder.setFormParams(parameters); return this; } 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 bc36b19892..8b2fff3119 100644 --- a/src/main/java/com/ning/http/client/oauth/OAuthSignatureCalculator.java +++ b/src/main/java/com/ning/http/client/oauth/OAuthSignatureCalculator.java @@ -86,7 +86,7 @@ public void calculateAndAddSignature(String baseURL, Request request, RequestBui String method = request.getMethod(); // POST etc String nonce = generateNonce(); long timestamp = System.currentTimeMillis() / 1000L; - String signature = calculateSignature(method, baseURL, timestamp, nonce, request.getParams(), request.getQueryParams()); + String signature = calculateSignature(method, baseURL, timestamp, nonce, request.getFormParams(), 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/ApacheAsyncHttpProvider.java b/src/main/java/com/ning/http/client/providers/apache/ApacheAsyncHttpProvider.java index d15c2fb02f..2e121c57f5 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 @@ -266,9 +266,9 @@ private HttpMethodBase createMethod(HttpClient client, Request request) throws I post.setRequestEntity(r); post.setRequestHeader("Content-Length", String.valueOf(r.getContentLength())); - } else if (request.getParams() != null) { + } else if (request.getFormParams() != null) { StringBuilder sb = new StringBuilder(); - for (final Map.Entry> paramEntry : request.getParams()) { + for (final Map.Entry> paramEntry : request.getFormParams()) { final String key = paramEntry.getKey(); for (final String value : paramEntry.getValue()) { if (sb.length() > 0) { 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 65a3c4a4db..2bd089611d 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 @@ -1792,7 +1792,7 @@ private static Request newRequest(final UriComponents uri, builder.setUrl(uri.toString()); if (ctx.provider.clientConfig.isRemoveQueryParamOnRedirect()) { - builder.setQueryParameters(null); + builder.setQueryParam(null); } for (String cookieStr : response.getHeaders().values(Header.Cookie)) { builder.addOrReplaceCookie(CookieDecoder.decode(cookieStr)); @@ -2041,7 +2041,7 @@ private final class ParamsBodyHandler extends BodyHandler { public boolean handlesBodyType(final Request request) { - return isNonEmpty(request.getParams()); + return isNonEmpty(request.getFormParams()); } @SuppressWarnings({"unchecked"}) @@ -2058,7 +2058,7 @@ public boolean doHandle(final FilterChainContext ctx, if (charset == null) { charset = Charsets.ASCII_CHARSET.name(); } - final FluentStringsMap params = request.getParams(); + final FluentStringsMap params = request.getFormParams(); if (!params.isEmpty()) { for (Map.Entry> entry : params.entrySet()) { String name = entry.getKey(); 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 f430e4c3c5..fbcdd73e27 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 @@ -581,9 +581,9 @@ private void configure(UriComponents uri, HttpURLConnection urlConnection, Reque urlConnection.setFixedLengthStreamingMode(cachedBytesLenght); urlConnection.getOutputStream().write(cachedBytes, 0, cachedBytesLenght); - } else if (request.getParams() != null) { + } else if (request.getFormParams() != null) { StringBuilder sb = new StringBuilder(); - for (final Map.Entry> paramEntry : request.getParams()) { + for (final Map.Entry> paramEntry : request.getFormParams()) { final String key = paramEntry.getKey(); for (final String value : paramEntry.getValue()) { if (sb.length() > 0) { 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 64913f0486..2bae9e1010 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 @@ -831,9 +831,9 @@ else if (uri.getQuery() != null) byte[] bytes = request.getStringData().getBytes(bodyCharset); nettyRequest.setHeader(HttpHeaders.Names.CONTENT_LENGTH, String.valueOf(bytes.length)); nettyRequest.setContent(ChannelBuffers.wrappedBuffer(bytes)); - } else if (isNonEmpty(request.getParams())) { + } else if (isNonEmpty(request.getFormParams())) { StringBuilder sb = new StringBuilder(); - for (final Entry> paramEntry : request.getParams()) { + for (final Entry> paramEntry : request.getFormParams()) { final String key = paramEntry.getKey(); for (final String value : paramEntry.getValue()) { if (sb.length() > 0) { @@ -1951,7 +1951,7 @@ private boolean redirect(Request request, NettyResponseFuture future, HttpRes final RequestBuilder nBuilder = new RequestBuilder(future.getRequest()); if (config.isRemoveQueryParamOnRedirect()) - nBuilder.setQueryParameters(null); + nBuilder.setQueryParam(null); if (!(statusCode < 302 || statusCode > 303) && !(statusCode == 302 && config.isStrict302Handling())) { nBuilder.setMethod("GET"); 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 c0897b718a..d1c42c502e 100755 --- a/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java +++ b/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java @@ -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(getTargetUrl() + "").addQueryParameter("q", "a b").build(); + Request request = new RequestBuilder("GET").setUrl(getTargetUrl() + "").addQueryParam("q", "a b").build(); Future responseFuture = client.executeRequest(request, new AsyncCompletionHandler() { @Override @@ -297,7 +297,7 @@ public void asyncParamPOSTTest() throws Throwable { 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(); + Request request = new RequestBuilder("POST").setUrl(getTargetUrl()).setHeaders(h).setFormParams(m).build(); client.executeRequest(request, new AsyncCompletionHandlerAdapter() { @Override @@ -507,7 +507,7 @@ 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() { + client.preparePost(getTargetUrl()).addFormParam("foo", "bar").execute(new AsyncCompletionHandlerAdapter() { @Override public Response onCompleted(Response response) throws Exception { @@ -837,7 +837,7 @@ public void asyncRequestVirtualServerPOSTTest() throws Throwable { 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(); + Request request = new RequestBuilder("POST").setUrl(getTargetUrl()).setHeaders(h).setFormParams(m).setVirtualHost("localhost:" + port1).build(); Response response = client.executeRequest(request, new AsyncCompletionHandlerAdapter()).get(); 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 319ec94031..12973ca191 100644 --- a/src/test/java/com/ning/http/client/async/AsyncStreamHandlerTest.java +++ b/src/test/java/com/ning/http/client/async/AsyncStreamHandlerTest.java @@ -100,7 +100,7 @@ public void asyncStreamPOSTTest() throws Exception { try { Future f = c.preparePost(getTargetUrl())// .setHeader("Content-Type", "application/x-www-form-urlencoded")// - .addParameter("param_1", "value_1")// + .addFormParam("param_1", "value_1")// .execute(new AsyncHandlerAdapter() { private StringBuilder builder = new StringBuilder(); @@ -145,7 +145,7 @@ public void asyncStreamInterruptTest() throws Exception { try { c.preparePost(getTargetUrl())// .setHeader("Content-Type", "application/x-www-form-urlencoded")// - .addParameter("param_1", "value_1")// + .addFormParam("param_1", "value_1")// .execute(new AsyncHandlerAdapter() { @Override @@ -185,7 +185,7 @@ public void asyncStreamFutureTest() throws Exception { final AtomicReference responseHeaders = new AtomicReference(); final AtomicReference throwable = new AtomicReference(); try { - Future f = c.preparePost(getTargetUrl()).addParameter("param_1", "value_1").execute(new AsyncHandlerAdapter() { + Future f = c.preparePost(getTargetUrl()).addFormParam("param_1", "value_1").execute(new AsyncHandlerAdapter() { private StringBuilder builder = new StringBuilder(); @Override @@ -265,7 +265,7 @@ public void asyncStreamReusePOSTTest() throws Exception { try { BoundRequestBuilder rb = c.preparePost(getTargetUrl())// .setHeader("Content-Type", "application/x-www-form-urlencoded") - .addParameter("param_1", "value_1"); + .addFormParam("param_1", "value_1"); Future f = rb.execute(new AsyncHandlerAdapter() { private StringBuilder builder = new StringBuilder(); 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 fc84431aaf..d84668e0f8 100644 --- a/src/test/java/com/ning/http/client/async/ParamEncodingTest.java +++ b/src/test/java/com/ning/http/client/async/ParamEncodingTest.java @@ -61,7 +61,7 @@ public void testParameters() throws IOException, ExecutionException, TimeoutExce String value = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKQLMNOPQRSTUVWXYZ1234567809`~!@#$%^&*()_+-=,.<>/?;:'\"[]{}\\| "; AsyncHttpClient client = getAsyncHttpClient(null); try { - Future f = client.preparePost("http://127.0.0.1:" + port1).addParameter("test", value).execute(); + Future f = client.preparePost("http://127.0.0.1:" + port1).addFormParam("test", value).execute(); Response resp = f.get(10, TimeUnit.SECONDS); assertNotNull(resp); assertEquals(resp.getStatusCode(), HttpServletResponse.SC_OK); 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 19407a095d..d5c6889aa2 100644 --- a/src/test/java/com/ning/http/client/async/PostRedirectGetTest.java +++ b/src/test/java/com/ning/http/client/async/PostRedirectGetTest.java @@ -83,7 +83,7 @@ public FilterContext filter(FilterContext ctx) throws FilterException { } }).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(); + Request request = new RequestBuilder("POST").setUrl(getTargetUrl()).addFormParam("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 @@ -117,7 +117,7 @@ public FilterContext filter(FilterContext ctx) throws FilterException { } }).build()); try { - Request request = new RequestBuilder("POST").setUrl(getTargetUrl()).addParameter("q", "a b").addHeader("x-redirect", +status + "@" + "http://localhost:" + port1 + "/foo/bar/baz").build(); + Request request = new RequestBuilder("POST").setUrl(getTargetUrl()).addFormParam("q", "a b").addHeader("x-redirect", +status + "@" + "http://localhost:" + port1 + "/foo/bar/baz").build(); Future responseFuture = p.executeRequest(request, new AsyncCompletionHandler() { @Override 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 27d796a07a..c40677a583 100644 --- a/src/test/java/com/ning/http/client/async/QueryParametersTest.java +++ b/src/test/java/com/ning/http/client/async/QueryParametersTest.java @@ -73,7 +73,7 @@ public AbstractHandler configureHandler() throws Exception { public void testQueryParameters() throws IOException, ExecutionException, TimeoutException, InterruptedException { AsyncHttpClient client = getAsyncHttpClient(null); try { - Future f = client.prepareGet("http://127.0.0.1:" + port1).addQueryParameter("a", "1").addQueryParameter("b", "2").execute(); + Future f = client.prepareGet("http://127.0.0.1:" + port1).addQueryParam("a", "1").addQueryParam("b", "2").execute(); Response resp = f.get(3, TimeUnit.SECONDS); assertNotNull(resp); assertEquals(resp.getStatusCode(), HttpServletResponse.SC_OK); diff --git a/src/test/java/com/ning/http/client/async/RequestBuilderTest.java b/src/test/java/com/ning/http/client/async/RequestBuilderTest.java index 5371d9b98d..f1c40a162e 100644 --- a/src/test/java/com/ning/http/client/async/RequestBuilderTest.java +++ b/src/test/java/com/ning/http/client/async/RequestBuilderTest.java @@ -54,7 +54,7 @@ public void testEncodesQueryParameters() throws UnsupportedEncodingException { for (String value : values) { RequestBuilder builder = new RequestBuilder("GET"). setUrl("http://example.com/"). - addQueryParameter("name", value); + addQueryParam("name", value); StringBuilder sb = new StringBuilder(); for (int i = 0, len = value.length(); i < len; ++i) { @@ -77,7 +77,7 @@ public void testEncodesQueryParameters() throws UnsupportedEncodingException { public void testChaining() throws IOException, ExecutionException, InterruptedException { Request request = new RequestBuilder("GET") .setUrl("http://foo.com") - .addQueryParameter("x", "value") + .addQueryParam("x", "value") .build(); Request request2 = new RequestBuilder(request).build(); @@ -89,7 +89,7 @@ public void testChaining() throws IOException, ExecutionException, InterruptedEx public void testParsesQueryParams() throws IOException, ExecutionException, InterruptedException { Request request = new RequestBuilder("GET") .setUrl("http://foo.com/?param1=value1") - .addQueryParameter("param2", "value2") + .addQueryParam("param2", "value2") .build(); assertEquals(request.getUrl(), "http://foo.com/?param1=value1¶m2=value2"); @@ -124,8 +124,8 @@ public void testContentTypeCharsetToBodyEncoding() { @Test(groups = {"standalone", "default_provider"}) public void testAddQueryParameterReadRawUrl() throws UnsupportedEncodingException { RequestBuilder rb = new RequestBuilder("GET", true).setUrl("http://example.com/path") - .addQueryParameter("a", "1?&") - .addQueryParameter("b", "+ ="); + .addQueryParam("a", "1?&") + .addQueryParam("b", "+ ="); Request request = rb.build(); assertEquals(request.getUrl(), "http://example.com/path?a=1%3F%26&b=%2B%20%3D"); assertEquals(request.getRawUrl(), "http://example.com/path?a=1?&&b=+ ="); 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 86eabd4ba4..b74433783c 100644 --- a/src/test/java/com/ning/http/client/async/RetryNonBlockingIssue.java +++ b/src/test/java/com/ning/http/client/async/RetryNonBlockingIssue.java @@ -107,10 +107,10 @@ public void stop() { private ListenableFuture testMethodRequest(AsyncHttpClient fetcher, int requests, String action, String id) throws IOException { RequestBuilder builder = new RequestBuilder("GET"); - builder.addQueryParameter(action, "1"); + builder.addQueryParam(action, "1"); - builder.addQueryParameter("maxRequests", "" + requests); - builder.addQueryParameter("id", id); + builder.addQueryParam("maxRequests", "" + requests); + builder.addQueryParam("id", id); builder.setUrl(servletEndpointUri.toString()); com.ning.http.client.Request r = builder.build(); return fetcher.executeRequest(r); From 324d0d29addba70728f666d25d03c953aeef82f0 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 4 Jul 2014 15:36:13 +0200 Subject: [PATCH 340/701] Drop deprecated RealmBuilder.getDomain, close #593 --- src/main/java/com/ning/http/client/Realm.java | 39 +++++-------------- .../http/client/SimpleAsyncHttpClient.java | 4 +- .../providers/jdk/JDKAsyncHttpProvider.java | 2 +- 3 files changed, 12 insertions(+), 33 deletions(-) diff --git a/src/main/java/com/ning/http/client/Realm.java b/src/main/java/com/ning/http/client/Realm.java index 2dc5a17fb0..b6e0277adc 100644 --- a/src/main/java/com/ning/http/client/Realm.java +++ b/src/main/java/com/ning/http/client/Realm.java @@ -49,7 +49,7 @@ public class Realm { private final boolean useAbsoluteURI; private final boolean omitQuery; - private final String domain; + private final String ntlmDomain; public enum AuthScheme { DIGEST, @@ -73,7 +73,7 @@ private Realm(AuthScheme scheme, String uri, String method, boolean usePreemptiveAuth, - String domain, + String ntlmDomain, String enc, String host, boolean messageType2Received, @@ -95,7 +95,7 @@ private Realm(AuthScheme scheme, this.uri = uri; this.methodName = method; this.usePreemptiveAuth = usePreemptiveAuth; - this.domain = domain; + this.ntlmDomain = ntlmDomain; this.enc = enc; this.host = host; this.messageType2Received = messageType2Received; @@ -173,23 +173,13 @@ public boolean getUsePreemptiveAuth() { return usePreemptiveAuth; } - /** - * Return the NTLM domain to use. This value should map the JDK - * - * @return the NTLM domain - * @deprecated - use getNtlmDomain() - */ - public String getDomain() { - return domain; - } - /** * Return the NTLM domain to use. This value should map the JDK * * @return the NTLM domain */ public String getNtlmDomain() { - return domain; + return ntlmDomain; } /** @@ -297,30 +287,19 @@ public static class RealmBuilder { private String uri = ""; private String methodName = "GET"; private boolean usePreemptive = false; - private String domain = System.getProperty("http.auth.ntlm.domain", ""); + private String ntlmDomain = System.getProperty("http.auth.ntlm.domain", ""); private String enc = "UTF-8"; private String host = "localhost"; private boolean messageType2Received = false; private boolean useAbsoluteURI = true; private boolean omitQuery = false; - @Deprecated - public String getDomain() { - return domain; - } - - @Deprecated - public RealmBuilder setDomain(String domain) { - this.domain = domain; - return this; - } - public String getNtlmDomain() { - return domain; + return ntlmDomain; } - public RealmBuilder setNtlmDomain(String domain) { - this.domain = domain; + public RealmBuilder setNtlmDomain(String ntlmDomain) { + this.ntlmDomain = ntlmDomain; return this; } @@ -657,7 +636,7 @@ public Realm build() { uri, methodName, usePreemptive, - domain, + ntlmDomain, enc, host, messageType2Received, diff --git a/src/main/java/com/ning/http/client/SimpleAsyncHttpClient.java b/src/main/java/com/ning/http/client/SimpleAsyncHttpClient.java index d30ac084e5..06d8abc73a 100644 --- a/src/main/java/com/ning/http/client/SimpleAsyncHttpClient.java +++ b/src/main/java/com/ning/http/client/SimpleAsyncHttpClient.java @@ -552,8 +552,8 @@ public Builder setRequestCompressionLevel(int requestCompressionLevel) { return this; } - public Builder setRealmDomain(String domain) { - realm().setDomain(domain); + public Builder setRealmNtlmDomain(String ntlmDomain) { + realm().setNtlmDomain(ntlmDomain); 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 fbcdd73e27..6c50e80f71 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 @@ -522,7 +522,7 @@ private void configure(UriComponents uri, HttpURLConnection urlConnection, Reque break; case NTLM: jdkNtlmDomain = System.getProperty(NTLM_DOMAIN); - System.setProperty(NTLM_DOMAIN, realm.getDomain()); + System.setProperty(NTLM_DOMAIN, realm.getNtlmDomain()); break; case NONE: break; From 64f22ec288a46ad0cd73caabc659c93f0574a15d Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 4 Jul 2014 16:09:12 +0200 Subject: [PATCH 341/701] Merge Request.isRedirectEnabled and isRedirectOverrideSet, close #594 --- src/main/java/com/ning/http/client/Request.java | 14 ++++---------- .../com/ning/http/client/RequestBuilderBase.java | 10 +++------- .../providers/apache/ApacheAsyncHttpProvider.java | 2 +- .../grizzly/GrizzlyAsyncHttpProvider.java | 9 +-------- .../client/providers/jdk/JDKAsyncHttpProvider.java | 2 +- .../providers/netty/NettyAsyncHttpProvider.java | 3 +-- .../com/ning/http/util/AsyncHttpProviderUtils.java | 4 ++++ 7 files changed, 15 insertions(+), 29 deletions(-) diff --git a/src/main/java/com/ning/http/client/Request.java b/src/main/java/com/ning/http/client/Request.java index dc4035ca42..c7f82cdc7a 100644 --- a/src/main/java/com/ning/http/client/Request.java +++ b/src/main/java/com/ning/http/client/Request.java @@ -187,18 +187,12 @@ public static interface EntityWriter { File getFile(); /** - * Return the true> to follow redirect + * Return follow redirect * - * @return the true> to follow redirect + * @return the TRUE> to follow redirect, FALSE, if NOT to follow, whatever the client config. + * Return null if not set. */ - boolean isRedirectEnabled(); - - /** - * - * @return true> if request's redirectEnabled setting - * should be used in place of client's - */ - boolean isRedirectOverrideSet(); + Boolean getFollowRedirect(); /** * Overrides the config default value diff --git a/src/main/java/com/ning/http/client/RequestBuilderBase.java b/src/main/java/com/ning/http/client/RequestBuilderBase.java index 48b15809ea..36a8cebf73 100644 --- a/src/main/java/com/ning/http/client/RequestBuilderBase.java +++ b/src/main/java/com/ning/http/client/RequestBuilderBase.java @@ -103,7 +103,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.getFollowRedirect(); this.requestTimeoutInMs = prototype.getRequestTimeoutInMs(); this.rangeOffset = prototype.getRangeOffset(); this.charset = prototype.getBodyEncoding(); @@ -283,12 +283,8 @@ public File getFile() { return file; } - public boolean isRedirectEnabled() { - return followRedirects != null && followRedirects; - } - - public boolean isRedirectOverrideSet() { - return followRedirects != null; + public Boolean getFollowRedirect() { + return followRedirects; } public int getRequestTimeoutInMs() { 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 2e121c57f5..20f135b848 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 @@ -508,7 +508,7 @@ public T call() { logger.debug("\n\nRequest {}\n\nResponse {}\n", request, method); - boolean redirectEnabled = (request.isRedirectEnabled() || config.isRedirectEnabled()); + boolean redirectEnabled = AsyncHttpProviderUtils.redirectEnabled(config, request); if (redirectEnabled && (statusCode == 302 || statusCode == 301)) { isAuth.set(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 2bd089611d..161455e497 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 @@ -1518,14 +1518,7 @@ private static GrizzlyWebSocketAdapter createWebSocketAdapter(final HttpTransact } private static boolean isRedirectAllowed(final HttpTransactionContext ctx) { - boolean allowed = ctx.request.isRedirectEnabled(); - if (ctx.request.isRedirectOverrideSet()) { - return allowed; - } - if (!allowed) { - allowed = ctx.redirectsAllowed; - } - return allowed; + return ctx.request.getFollowRedirect() != null? ctx.request.getFollowRedirect().booleanValue() : ctx.redirectsAllowed; } private static HttpTransactionContext cleanup(final FilterChainContext ctx, 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 6c50e80f71..2eee0ad730 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 @@ -268,7 +268,7 @@ public T call() throws Exception { return call(); } - boolean redirectEnabled = (request.isRedirectEnabled() || config.isRedirectEnabled()); + boolean redirectEnabled = AsyncHttpProviderUtils.redirectEnabled(config, request); if (redirectEnabled && (statusCode == 302 || statusCode == 301)) { if (currentRedirectCount++ < config.getMaxRedirects()) { 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 2bae9e1010..091c113d71 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 @@ -1938,8 +1938,7 @@ private static final boolean validateWebSocketRequest(Request request, AsyncHand 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 (AsyncHttpProviderUtils.redirectEnabled(config, request) && (statusCode == 302 || statusCode == 301 || statusCode == 303 || statusCode == 307)) { if (future.incrementAndGetCurrentRedirectCount() < config.getMaxRedirects()) { // We must allow 401 handling again. diff --git a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java index a8ac9bde3e..609070684b 100644 --- a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java +++ b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java @@ -228,4 +228,8 @@ public static String keepAliveHeaderValue(AsyncHttpClientConfig config) { public static int requestTimeout(AsyncHttpClientConfig config, Request request) { return request.getRequestTimeoutInMs() != 0 ? request.getRequestTimeoutInMs() : config.getRequestTimeoutInMs(); } + + public static boolean redirectEnabled(AsyncHttpClientConfig config, Request request) { + return request.getFollowRedirect() != null? request.getFollowRedirect().booleanValue() : config.isRedirectEnabled(); + } } From db10a4f9d5afcc625c6e42469bcc7377db18c116 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 4 Jul 2014 18:54:04 +0200 Subject: [PATCH 342/701] Turn queryParams and formParams into List, close #595 --- .../com/ning/http/client/AsyncHttpClient.java | 9 +- .../ning/http/client/FluentStringsMap.java | 14 ++ src/main/java/com/ning/http/client/Param.java | 62 +++++++++ .../java/com/ning/http/client/Request.java | 4 +- .../com/ning/http/client/RequestBuilder.java | 18 ++- .../ning/http/client/RequestBuilderBase.java | 124 ++++++++---------- .../http/client/SimpleAsyncHttpClient.java | 15 ++- .../oauth/OAuthSignatureCalculator.java | 19 +-- .../apache/ApacheAsyncHttpProvider.java | 23 ++-- .../grizzly/GrizzlyAsyncHttpProvider.java | 72 ++-------- .../providers/jdk/JDKAsyncHttpProvider.java | 24 +--- .../netty/NettyAsyncHttpProvider.java | 27 ++-- .../http/util/AsyncHttpProviderUtils.java | 27 +++- .../client/async/AsyncProvidersBasicTest.java | 5 +- .../http/client/async/RequestBuilderTest.java | 16 ++- .../async/netty/NettyProxyTunnellingTest.java | 3 + .../client/oauth/TestSignatureCalculator.java | 11 +- 17 files changed, 244 insertions(+), 229 deletions(-) create mode 100644 src/main/java/com/ning/http/client/Param.java diff --git a/src/main/java/com/ning/http/client/AsyncHttpClient.java b/src/main/java/com/ning/http/client/AsyncHttpClient.java index ea5d24b025..a3970bbf2f 100755 --- a/src/main/java/com/ning/http/client/AsyncHttpClient.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClient.java @@ -21,6 +21,7 @@ import java.io.InputStream; import java.lang.reflect.InvocationTargetException; import java.util.Collection; +import java.util.List; import java.util.Map; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -304,13 +305,13 @@ public BoundRequestBuilder setHeaders(Map> headers) { } @Override - public BoundRequestBuilder setFormParams(Map> parameters) { - return super.setFormParams(parameters); + public BoundRequestBuilder setFormParams(Map> params) { + return super.setFormParams(params); } @Override - public BoundRequestBuilder setFormParams(FluentStringsMap parameters) { - return super.setFormParams(parameters); + public BoundRequestBuilder setFormParams(List params) { + return super.setFormParams(params); } @Override diff --git a/src/main/java/com/ning/http/client/FluentStringsMap.java b/src/main/java/com/ning/http/client/FluentStringsMap.java index 6df70f018d..3fdf5e2581 100644 --- a/src/main/java/com/ning/http/client/FluentStringsMap.java +++ b/src/main/java/com/ning/http/client/FluentStringsMap.java @@ -400,6 +400,20 @@ public Collection> values() { return values.values(); } + public List toParams() { + if (values.isEmpty()) + return Collections.emptyList(); + else { + List params = new ArrayList(values.size()); + for (Map.Entry> entry : values.entrySet()) { + String name = entry.getKey(); + for (String value: entry.getValue()) + params.add(new Param(name, value)); + } + return params; + } + } + @Override public boolean equals(Object obj) { if (this == obj) { diff --git a/src/main/java/com/ning/http/client/Param.java b/src/main/java/com/ning/http/client/Param.java new file mode 100644 index 0000000000..36174f2b48 --- /dev/null +++ b/src/main/java/com/ning/http/client/Param.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2014 AsyncHttpClient Project. 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; + +/** + * A pair of (name, value) String + * @author slandelle + */ +public class Param { + + private final String name; + private final String value; + public Param(String name, String value) { + this.name = name; + this.value = value; + } + public String getName() { + return name; + } + public String getValue() { + return value; + } + + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((name == null) ? 0 : name.hashCode()); + result = prime * result + ((value == null) ? 0 : value.hashCode()); + return result; + } + + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (!(obj instanceof Param)) + return false; + Param other = (Param) obj; + if (name == null) { + if (other.name != null) + return false; + } else if (!name.equals(other.name)) + return false; + if (value == null) { + if (other.value != null) + return false; + } else if (!value.equals(other.value)) + return false; + return true; + } +} diff --git a/src/main/java/com/ning/http/client/Request.java b/src/main/java/com/ning/http/client/Request.java index c7f82cdc7a..3e8ae483ff 100644 --- a/src/main/java/com/ning/http/client/Request.java +++ b/src/main/java/com/ning/http/client/Request.java @@ -142,7 +142,7 @@ public static interface EntityWriter { * * @return a {@link FluentStringsMap} of parameters. */ - FluentStringsMap getFormParams(); + List getFormParams(); /** * Return the current {@link Part} @@ -163,7 +163,7 @@ public static interface EntityWriter { * * @return {@link FluentStringsMap} of query string */ - FluentStringsMap getQueryParams(); + List getQueryParams(); /** * Return the {@link ProxyServer} diff --git a/src/main/java/com/ning/http/client/RequestBuilder.java b/src/main/java/com/ning/http/client/RequestBuilder.java index 724a4b3a61..209f0c2a86 100644 --- a/src/main/java/com/ning/http/client/RequestBuilder.java +++ b/src/main/java/com/ning/http/client/RequestBuilder.java @@ -17,6 +17,7 @@ import java.io.InputStream; import java.util.Collection; +import java.util.List; import java.util.Map; import com.ning.http.client.Request.EntityWriter; @@ -75,8 +76,13 @@ public RequestBuilder addQueryParam(String name, String value) { } @Override - public RequestBuilder setQueryParam(FluentStringsMap parameters) { - return super.setQueryParam(parameters); + public RequestBuilder setQueryParams(List params) { + return super.setQueryParams(params); + } + + @Override + public RequestBuilder setQueryParams(Map> params) { + return super.setQueryParams(params); } @Override @@ -136,13 +142,13 @@ public RequestBuilder setHeaders(Map> headers) { } @Override - public RequestBuilder setFormParams(Map> parameters) { - return super.setFormParams(parameters); + public RequestBuilder setFormParams(List params) { + return super.setFormParams(params); } @Override - public RequestBuilder setFormParams(FluentStringsMap parameters) { - return super.setFormParams(parameters); + public RequestBuilder setFormParams(Map> params) { + return super.setFormParams(params); } @Override diff --git a/src/main/java/com/ning/http/client/RequestBuilderBase.java b/src/main/java/com/ning/http/client/RequestBuilderBase.java index 36a8cebf73..433def45db 100644 --- a/src/main/java/com/ning/http/client/RequestBuilderBase.java +++ b/src/main/java/com/ning/http/client/RequestBuilderBase.java @@ -28,7 +28,6 @@ import java.util.Iterator; import java.util.List; import java.util.Map; -import java.util.Map.Entry; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -63,11 +62,11 @@ private static final class RequestImpl implements Request { private InputStream streamData; private EntityWriter entityWriter; private BodyGenerator bodyGenerator; - private FluentStringsMap formParams; + private List formParams; private List parts; private String virtualHost; private long length = -1; - public FluentStringsMap queryParams; + public List queryParams; public ProxyServer proxyServer; private Realm realm; private File file; @@ -95,8 +94,8 @@ public RequestImpl(Request prototype) { this.streamData = prototype.getStreamData(); this.entityWriter = prototype.getEntityWriter(); this.bodyGenerator = prototype.getBodyGenerator(); - this.formParams = prototype.getFormParams() == null ? null : new FluentStringsMap(prototype.getFormParams()); - this.queryParams = prototype.getQueryParams() == null ? null : new FluentStringsMap(prototype.getQueryParams()); + this.formParams = prototype.getFormParams() == null ? null : new ArrayList(prototype.getFormParams()); + this.queryParams = prototype.getQueryParams() == null ? null : new ArrayList(prototype.getQueryParams()); this.parts = prototype.getParts() == null ? null : new ArrayList(prototype.getParts()); this.virtualHost = prototype.getVirtualHost(); this.length = prototype.getContentLength(); @@ -112,7 +111,6 @@ public RequestImpl(Request prototype) { } } - /* @Override */ public String getMethod() { return method; } @@ -134,12 +132,10 @@ private String removeTrailingSlash(UriComponents uri) { } } - /* @Override */ public String getUrl() { return removeTrailingSlash(getURI()); } - /* @Override */ public String getRawUrl() { return removeTrailingSlash(getRawURI()); } @@ -173,31 +169,23 @@ private UriComponents toUriComponents(boolean encode) { String newQuery = null; if (isNonEmpty(queryParams)) { StringBuilder sb = new StringBuilder(); - for (Iterator>> i = queryParams.iterator(); i.hasNext();) { - Map.Entry> param = i.next(); - String name = param.getKey(); - for (Iterator j = param.getValue().iterator(); j.hasNext();) { - String value = j.next(); - if (encode) { - UTF8UrlEncoder.appendEncoded(sb, name); - } else { - sb.append(name); - } - if (value != null) { - sb.append('='); - if (encode) { - UTF8UrlEncoder.appendEncoded(sb, value); - } else { - sb.append(value); - } - } - if (j.hasNext()) { - sb.append('&'); - } + for (Iterator i = queryParams.iterator(); i.hasNext();) { + Param param = i.next(); + String name = param.getName(); + String value = param.getValue(); + if (encode) + UTF8UrlEncoder.appendEncoded(sb, name); + else + sb.append(name); + if (value != null) { + sb.append('='); + if (encode) + UTF8UrlEncoder.appendEncoded(sb, value); + else + sb.append(value); } - if (i.hasNext()) { + if (i.hasNext()) sb.append('&'); - } } newQuery = sb.toString(); @@ -212,63 +200,52 @@ private UriComponents toUriComponents(boolean encode) { newQuery); } - /* @Override */ public FluentCaseInsensitiveStringsMap getHeaders() { return headers; } - /* @Override */ public Collection getCookies() { return cookies != null ? Collections.unmodifiableCollection(cookies) : Collections. emptyList(); } - /* @Override */ public byte[] getByteData() { return byteData; } - /* @Override */ public String getStringData() { return stringData; } - /* @Override */ public InputStream getStreamData() { return streamData; } - /* @Override */ public EntityWriter getEntityWriter() { return entityWriter; } - /* @Override */ public BodyGenerator getBodyGenerator() { return bodyGenerator; } - /* @Override */ public long getContentLength() { return length; } - /* @Override */ - public FluentStringsMap getFormParams() { - return formParams; + public List getFormParams() { + return formParams != null ? formParams : Collections. emptyList(); } - /* @Override */ public List getParts() { - return parts; + return parts != null ? parts : Collections. emptyList(); } - /* @Override */ public String getVirtualHost() { return virtualHost; } - public FluentStringsMap getQueryParams() { - return queryParams; + public List getQueryParams() { + return queryParams != null ? queryParams : Collections. emptyList(); } public ProxyServer getProxyServer() { @@ -320,11 +297,11 @@ public String toString() { } if (isNonEmpty(formParams)) { sb.append("\tformParams:"); - for (String name : formParams.keySet()) { + for (Param param : formParams) { sb.append("\t"); - sb.append(name); + sb.append(param.getName()); sb.append(":"); - sb.append(formParams.getJoinedValue(name, ", ")); + sb.append(param.getValue()); } } @@ -548,41 +525,50 @@ public T setBody(BodyGenerator bodyGenerator) { public T addQueryParam(String name, String value) { if (request.queryParams == null) { - request.queryParams = new FluentStringsMap(); + request.queryParams = new ArrayList(1); } - request.queryParams.add(name, value); + request.queryParams.add(new Param(name, value)); return derived.cast(this); } - public T setQueryParam(FluentStringsMap parameters) { - if (parameters == null) { - request.queryParams = null; - } else { - request.queryParams = new FluentStringsMap(parameters); + private List map2ParamList(Map> map) { + if (map == null) + return null; + + List params = new ArrayList(map.size()); + for (Map.Entry> entries : map.entrySet()) { + String name = entries.getKey(); + for (String value : entries.getValue()) + params.add(new Param(name, value)); } - return derived.cast(this); + return params; + } + + public T setQueryParams(Map> map) { + return setQueryParams(map2ParamList(map)); } - public T addFormParam(String key, String value) { - resetNonMultipartData(); - resetMultipartData(); - if (request.formParams == null) - request.formParams = new FluentStringsMap(); - request.formParams.add(key, value); + public T setQueryParams(List params) { + request.queryParams = params; return derived.cast(this); } - - public T setFormParams(FluentStringsMap parameters) { + + public T addFormParam(String name, String value) { resetNonMultipartData(); resetMultipartData(); - request.formParams = new FluentStringsMap(parameters); + if (request.formParams == null) + request.formParams = new ArrayList(1); + request.formParams.add(new Param(name, value)); return derived.cast(this); } - public T setFormParams(Map> parameters) { + public T setFormParams(Map> map) { + return setFormParams(map2ParamList(map)); + } + public T setFormParams(List params) { resetNonMultipartData(); resetMultipartData(); - request.formParams = new FluentStringsMap(parameters); + request.formParams = params; return derived.cast(this); } diff --git a/src/main/java/com/ning/http/client/SimpleAsyncHttpClient.java b/src/main/java/com/ning/http/client/SimpleAsyncHttpClient.java index 06d8abc73a..f21c149433 100644 --- a/src/main/java/com/ning/http/client/SimpleAsyncHttpClient.java +++ b/src/main/java/com/ning/http/client/SimpleAsyncHttpClient.java @@ -14,6 +14,7 @@ import java.io.IOException; import java.util.Collection; +import java.util.List; import java.util.Map; import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; @@ -367,9 +368,9 @@ public interface DerivedBuilder { DerivedBuilder setUrl(String url); - DerivedBuilder setFormParams(FluentStringsMap parameters); + DerivedBuilder setFormParams(List params); - DerivedBuilder setFormParams(Map> parameters); + DerivedBuilder setFormParams(Map> params); DerivedBuilder setHeaders(Map> headers); @@ -461,14 +462,14 @@ public Builder setHeaders(Map> headers) { requestBuilder.setHeaders(headers); return this; } - - public Builder setFormParams(Map> parameters) { - requestBuilder.setFormParams(parameters); + + public Builder setFormParams(List params) { + requestBuilder.setFormParams(params); return this; } - public Builder setFormParams(FluentStringsMap parameters) { - requestBuilder.setFormParams(parameters); + public Builder setFormParams(Map> params) { + requestBuilder.setFormParams(params); return this; } 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 8b2fff3119..f674bcb3af 100644 --- a/src/main/java/com/ning/http/client/oauth/OAuthSignatureCalculator.java +++ b/src/main/java/com/ning/http/client/oauth/OAuthSignatureCalculator.java @@ -16,7 +16,7 @@ */ package com.ning.http.client.oauth; -import com.ning.http.client.FluentStringsMap; +import com.ning.http.client.Param; import com.ning.http.client.Request; import com.ning.http.client.RequestBuilderBase; import com.ning.http.client.SignatureCalculator; @@ -27,7 +27,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import java.util.Map; import java.util.Random; /** @@ -95,7 +94,7 @@ public void calculateAndAddSignature(String baseURL, Request request, RequestBui * Method for calculating OAuth signature using HMAC/SHA-1 method. */ public String calculateSignature(String method, String baseURL, long oauthTimestamp, String nonce, - FluentStringsMap formParams, FluentStringsMap queryParams) { + List formParams, List queryParams) { StringBuilder signedText = new StringBuilder(100); signedText.append(method); // POST / GET etc (nothing to URL encode) signedText.append('&'); @@ -133,19 +132,13 @@ public String calculateSignature(String method, String baseURL, long oauthTimest allParameters.add(KEY_OAUTH_VERSION, OAUTH_VERSION_1_0); if (formParams != null) { - for (Map.Entry> entry : formParams) { - String key = entry.getKey(); - for (String value : entry.getValue()) { - allParameters.add(key, value); - } + for (Param param : formParams) { + allParameters.add(param.getName(), param.getValue()); } } if (queryParams != null) { - for (Map.Entry> entry : queryParams) { - String key = entry.getKey(); - for (String value : entry.getValue()) { - allParameters.add(key, value); - } + for (Param param : queryParams) { + allParameters.add(param.getName(), param.getValue()); } } String encodedParams = allParameters.sortAndConcat(); 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 20f135b848..187411ada5 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 @@ -26,6 +26,7 @@ import com.ning.http.client.HttpResponseStatus; import com.ning.http.client.ListenableFuture; import com.ning.http.client.MaxRedirectException; +import com.ning.http.client.Param; import com.ning.http.client.Part; import com.ning.http.client.ProgressAsyncHandler; import com.ning.http.client.ProxyServer; @@ -105,7 +106,6 @@ import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.util.List; -import java.util.Map; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executors; @@ -266,18 +266,17 @@ private HttpMethodBase createMethod(HttpClient client, Request request) throws I post.setRequestEntity(r); post.setRequestHeader("Content-Length", String.valueOf(r.getContentLength())); - } else if (request.getFormParams() != null) { + } else if (isNonEmpty(request.getFormParams())) { StringBuilder sb = new StringBuilder(); - for (final Map.Entry> paramEntry : request.getFormParams()) { - final String key = paramEntry.getKey(); - for (final String value : paramEntry.getValue()) { - if (sb.length() > 0) { - sb.append("&"); - } - UTF8UrlEncoder.appendEncoded(sb, key); - sb.append("="); - UTF8UrlEncoder.appendEncoded(sb, value); + for (final Param param : request.getFormParams()) { + final String name = param.getName(); + final String value = param.getValue(); + if (sb.length() > 0) { + sb.append("&"); } + UTF8UrlEncoder.appendEncoded(sb, name); + sb.append("="); + UTF8UrlEncoder.appendEncoded(sb, value); } post.setRequestHeader("Content-Length", String.valueOf(sb.length())); @@ -286,7 +285,7 @@ private HttpMethodBase createMethod(HttpClient client, Request request) throws I if (!request.getHeaders().containsKey("Content-Type")) { post.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); } - } else if (request.getParts() != null) { + } else if (isNonEmpty(request.getParts())) { MultipartRequestEntity mre = createMultipartRequestEntity(bodyCharset, request.getParts(), post.getParams()); post.setRequestEntity(mre); post.setRequestHeader("Content-Type", mre.getContentType()); 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 161455e497..a150f12611 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 @@ -113,12 +113,12 @@ import com.ning.http.client.BodyGenerator; import com.ning.http.client.ConnectionsPool; import com.ning.http.client.FluentCaseInsensitiveStringsMap; -import com.ning.http.client.FluentStringsMap; 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.Param; import com.ning.http.client.Part; import com.ning.http.client.ProxyServer; import com.ning.http.client.Realm; @@ -1084,39 +1084,6 @@ private void convertCookies(final Collection cookies, } } - - - private void addQueryString(final Request request, - final HttpRequestPacket requestPacket) { - - final FluentStringsMap map = request.getQueryParams(); - 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 (isNonEmpty(values)) { - try { - for (int i = 0, len = values.size(); i < len; i++) { - final String value = values.get(i); - if (isNonEmpty(value)) { - sb.append(URLEncoder.encode(name, "UTF-8")).append('=') - .append(URLEncoder.encode(values.get(i), "UTF-8")).append('&'); - } else { - sb.append(URLEncoder.encode(name, "UTF-8")).append('&'); - } - } - } catch (UnsupportedEncodingException ignored) { - } - } - } - sb.setLength(sb.length() - 1); - String queryString = sb.toString(); - - requestPacket.setQueryString(queryString); - } - } - } // END AsyncHttpClientFiler @@ -1785,7 +1752,7 @@ private static Request newRequest(final UriComponents uri, builder.setUrl(uri.toString()); if (ctx.provider.clientConfig.isRemoveQueryParamOnRedirect()) { - builder.setQueryParam(null); + builder.resetQueryParams();; } for (String cookieStr : response.getHeaders().values(Header.Cookie)) { builder.addOrReplaceCookie(CookieDecoder.decode(cookieStr)); @@ -2046,43 +2013,30 @@ public boolean doHandle(final FilterChainContext ctx, if (requestPacket.getContentType() == null) { requestPacket.setContentType("application/x-www-form-urlencoded"); } - StringBuilder sb = null; String charset = request.getBodyEncoding(); if (charset == null) { charset = Charsets.ASCII_CHARSET.name(); } - final FluentStringsMap params = request.getFormParams(); - if (!params.isEmpty()) { - for (Map.Entry> entry : params.entrySet()) { - String name = entry.getKey(); - List values = entry.getValue(); - if (isNonEmpty(values)) { - if (sb == null) { - sb = new StringBuilder(128); - } - for (String value : values) { - if (sb.length() > 0) { - sb.append('&'); - } - sb.append(URLEncoder.encode(name, charset)) - .append('=').append(URLEncoder.encode(value, charset)); - } - } + + if (isNonEmpty(request.getFormParams())) { + StringBuilder sb = new StringBuilder(128); + for (Param param : request.getFormParams()) { + String name = URLEncoder.encode(param.getName(), charset); + String value = URLEncoder.encode(param.getValue(), charset); + sb.append(name).append('=').append(value).append('&'); } - } - if (sb != null) { + sb.setLength(sb.length() - 1); final byte[] data = sb.toString().getBytes(charset); final MemoryManager mm = ctx.getMemoryManager(); final Buffer gBuffer = Buffers.wrap(mm, data); final HttpContent content = requestPacket.httpContentBuilder().content(gBuffer).build(); - if (requestPacket.getContentLength() == -1) { - if (!clientConfig.isCompressionEnabled()) { - requestPacket.setContentLengthLong(data.length); - } + if (requestPacket.getContentLength() == -1 && !clientConfig.isCompressionEnabled()) { + requestPacket.setContentLengthLong(data.length); } content.setLast(true); ctx.write(content, ((!requestPacket.isCommitted()) ? ctx.getTransportContext().getCompletionHandler() : null)); } + return true; } 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 2eee0ad730..045a07ed45 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 @@ -81,7 +81,6 @@ import com.ning.http.util.AuthenticatorUtils; import com.ning.http.util.ProxyUtils; import com.ning.http.util.SslUtils; -import com.ning.http.util.UTF8UrlEncoder; public class JDKAsyncHttpProvider implements AsyncHttpProvider { private final static Logger logger = LoggerFactory.getLogger(JDKAsyncHttpProvider.class); @@ -581,27 +580,16 @@ private void configure(UriComponents uri, HttpURLConnection urlConnection, Reque urlConnection.setFixedLengthStreamingMode(cachedBytesLenght); urlConnection.getOutputStream().write(cachedBytes, 0, cachedBytesLenght); - } else if (request.getFormParams() != null) { - StringBuilder sb = new StringBuilder(); - for (final Map.Entry> paramEntry : request.getFormParams()) { - final String key = paramEntry.getKey(); - for (final String value : paramEntry.getValue()) { - if (sb.length() > 0) { - sb.append("&"); - } - UTF8UrlEncoder.appendEncoded(sb, key); - sb.append("="); - UTF8UrlEncoder.appendEncoded(sb, value); - } - } - urlConnection.setRequestProperty("Content-Length", String.valueOf(sb.length())); - urlConnection.setFixedLengthStreamingMode(sb.length()); + } else if (isNonEmpty(request.getFormParams())) { + String formBody = AsyncHttpProviderUtils.formParams2UTF8String(request.getFormParams()); + urlConnection.setRequestProperty("Content-Length", String.valueOf(formBody.length())); + urlConnection.setFixedLengthStreamingMode(formBody.length()); if (!request.getHeaders().containsKey("Content-Type")) { urlConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); } - urlConnection.getOutputStream().write(sb.toString().getBytes(bodyCharset)); - } else if (request.getParts() != null) { + urlConnection.getOutputStream().write(formBody.getBytes(bodyCharset)); + } else if (isNonEmpty(request.getParts() )) { int lenght = (int) request.getContentLength(); if (lenght != -1) { urlConnection.setRequestProperty("Content-Length", String.valueOf(lenght)); 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 091c113d71..b0a5cbec45 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 @@ -154,7 +154,6 @@ import com.ning.http.util.MiscUtil; import com.ning.http.util.ProxyUtils; import com.ning.http.util.SslUtils; -import com.ning.http.util.UTF8UrlEncoder; public class NettyAsyncHttpProvider extends SimpleChannelUpstreamHandler implements AsyncHttpProvider { @@ -508,7 +507,7 @@ protected final void writeRequest(final Channel channel, final AsyncHttpClie nettyRequest.setHeader(HttpHeaders.Names.TRANSFER_ENCODING, HttpHeaders.Values.CHUNKED); } - } else if (future.getRequest().getParts() != null) { + } else if (isNonEmpty(future.getRequest().getParts())) { String contentType = nettyRequest.getHeader(HttpHeaders.Names.CONTENT_TYPE); String contentLength = nettyRequest.getHeader(HttpHeaders.Names.CONTENT_LENGTH); @@ -824,34 +823,26 @@ else if (uri.getQuery() != null) if (buffer != null && buffer.writerIndex() != 0) { nettyRequest.setHeader(HttpHeaders.Names.CONTENT_LENGTH, buffer.writerIndex()); nettyRequest.setContent(buffer); + } else if (request.getByteData() != null) { nettyRequest.setHeader(HttpHeaders.Names.CONTENT_LENGTH, String.valueOf(request.getByteData().length)); nettyRequest.setContent(ChannelBuffers.wrappedBuffer(request.getByteData())); + } else if (request.getStringData() != null) { byte[] bytes = request.getStringData().getBytes(bodyCharset); nettyRequest.setHeader(HttpHeaders.Names.CONTENT_LENGTH, String.valueOf(bytes.length)); nettyRequest.setContent(ChannelBuffers.wrappedBuffer(bytes)); + } else if (isNonEmpty(request.getFormParams())) { - StringBuilder sb = new StringBuilder(); - for (final Entry> paramEntry : request.getFormParams()) { - final String key = paramEntry.getKey(); - for (final String value : paramEntry.getValue()) { - if (sb.length() > 0) { - sb.append("&"); - } - UTF8UrlEncoder.appendEncoded(sb, key); - sb.append("="); - UTF8UrlEncoder.appendEncoded(sb, value); - } - } - nettyRequest.setHeader(HttpHeaders.Names.CONTENT_LENGTH, String.valueOf(sb.length())); - nettyRequest.setContent(ChannelBuffers.wrappedBuffer(sb.toString().getBytes(bodyCharset))); + String formBody = AsyncHttpProviderUtils.formParams2UTF8String(request.getFormParams()); + nettyRequest.setHeader(HttpHeaders.Names.CONTENT_LENGTH, String.valueOf(formBody.length())); + nettyRequest.setContent(ChannelBuffers.wrappedBuffer(formBody.getBytes(bodyCharset))); if (!request.getHeaders().containsKey(HttpHeaders.Names.CONTENT_TYPE)) { nettyRequest.setHeader(HttpHeaders.Names.CONTENT_TYPE, HttpHeaders.Values.APPLICATION_X_WWW_FORM_URLENCODED); } - } else if (request.getParts() != null) { + } else if (isNonEmpty(request.getParts())) { MultipartRequestEntity mre = AsyncHttpProviderUtils.createMultipartRequestEntity(request.getParts(), request.getHeaders()); nettyRequest.setHeader(HttpHeaders.Names.CONTENT_TYPE, mre.getContentType()); @@ -1950,7 +1941,7 @@ private boolean redirect(Request request, NettyResponseFuture future, HttpRes final RequestBuilder nBuilder = new RequestBuilder(future.getRequest()); if (config.isRemoveQueryParamOnRedirect()) - nBuilder.setQueryParam(null); + nBuilder.resetQueryParams(); if (!(statusCode < 302 || statusCode > 303) && !(statusCode == 302 && config.isStrict302Handling())) { nBuilder.setMethod("GET"); diff --git a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java index 609070684b..b50a97655a 100644 --- a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java +++ b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java @@ -14,13 +14,6 @@ import static com.ning.http.util.MiscUtil.isNonEmpty; -import java.io.ByteArrayInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.io.UnsupportedEncodingException; -import java.util.List; - import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.AsyncHttpProvider; import com.ning.http.client.ByteArrayPart; @@ -28,6 +21,7 @@ import com.ning.http.client.FluentCaseInsensitiveStringsMap; import com.ning.http.client.HttpResponseBodyPart; import com.ning.http.client.HttpResponseBodyPartsInputStream; +import com.ning.http.client.Param; import com.ning.http.client.Part; import com.ning.http.client.Request; import com.ning.http.client.StringPart; @@ -36,6 +30,13 @@ 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.util.List; + /** * {@link com.ning.http.client.AsyncHttpProvider} common utilities. *

    @@ -232,4 +233,16 @@ public static int requestTimeout(AsyncHttpClientConfig config, Request request) public static boolean redirectEnabled(AsyncHttpClientConfig config, Request request) { return request.getFollowRedirect() != null? request.getFollowRedirect().booleanValue() : config.isRedirectEnabled(); } + + public static String formParams2UTF8String(List params) { + StringBuilder sb = new StringBuilder(params.size() * 15); + for (Param param : params) { + UTF8UrlEncoder.appendEncoded(sb, param.getName()); + sb.append("="); + UTF8UrlEncoder.appendEncoded(sb, param.getValue()); + sb.append("&"); + } + sb.setLength(sb.length() - 1); + return sb.toString(); + } } 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 d1c42c502e..af4f11179b 100755 --- a/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java +++ b/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java @@ -30,7 +30,6 @@ import java.net.URL; import java.nio.channels.UnresolvedAddressException; import java.util.Arrays; -import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -293,7 +292,7 @@ public void asyncParamPOSTTest() throws Throwable { FluentCaseInsensitiveStringsMap h = new FluentCaseInsensitiveStringsMap(); h.add("Content-Type", "application/x-www-form-urlencoded"); - Map> m = new HashMap>(); + Map> m = new HashMap>(); for (int i = 0; i < 5; i++) { m.put("param_" + i, Arrays.asList("value_" + i)); } @@ -833,7 +832,7 @@ public void asyncRequestVirtualServerPOSTTest() throws Throwable { FluentCaseInsensitiveStringsMap h = new FluentCaseInsensitiveStringsMap(); h.add("Content-Type", "application/x-www-form-urlencoded"); - Map> m = new HashMap>(); + Map> m = new HashMap>(); for (int i = 0; i < 5; i++) { m.put("param_" + i, Arrays.asList("value_" + i)); } diff --git a/src/test/java/com/ning/http/client/async/RequestBuilderTest.java b/src/test/java/com/ning/http/client/async/RequestBuilderTest.java index f1c40a162e..7a97b76ee9 100644 --- a/src/test/java/com/ning/http/client/async/RequestBuilderTest.java +++ b/src/test/java/com/ning/http/client/async/RequestBuilderTest.java @@ -15,17 +15,19 @@ */ package com.ning.http.client.async; -import com.ning.http.client.FluentStringsMap; +import static org.testng.Assert.assertEquals; + +import org.testng.annotations.Test; + +import com.ning.http.client.Param; import com.ning.http.client.Request; import com.ning.http.client.RequestBuilder; -import org.testng.annotations.Test; import java.io.IOException; import java.io.UnsupportedEncodingException; +import java.util.List; import java.util.concurrent.ExecutionException; -import static org.testng.Assert.assertEquals; - public class RequestBuilderTest { private final static String SAFE_CHARS = @@ -93,10 +95,10 @@ public void testParsesQueryParams() throws IOException, ExecutionException, Inte .build(); assertEquals(request.getUrl(), "http://foo.com/?param1=value1¶m2=value2"); - FluentStringsMap params = request.getQueryParams(); + List params = request.getQueryParams(); assertEquals(params.size(), 2); - assertEquals(params.get("param1").get(0), "value1"); - assertEquals(params.get("param2").get(0), "value2"); + assertEquals(params.get(0), new Param("param1", "value1")); + assertEquals(params.get(1), new Param("param2", "value2")); } @Test(groups = {"standalone", "default_provider"}) diff --git a/src/test/java/com/ning/http/client/async/netty/NettyProxyTunnellingTest.java b/src/test/java/com/ning/http/client/async/netty/NettyProxyTunnellingTest.java index a07028b865..13ae7feb86 100644 --- a/src/test/java/com/ning/http/client/async/netty/NettyProxyTunnellingTest.java +++ b/src/test/java/com/ning/http/client/async/netty/NettyProxyTunnellingTest.java @@ -12,11 +12,14 @@ */ package com.ning.http.client.async.netty; +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.async.ProxyTunnellingTest; +@Test public class NettyProxyTunnellingTest extends ProxyTunnellingTest { @Override public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { diff --git a/src/test/java/com/ning/http/client/oauth/TestSignatureCalculator.java b/src/test/java/com/ning/http/client/oauth/TestSignatureCalculator.java index e75a1e981a..b24b05a51f 100644 --- a/src/test/java/com/ning/http/client/oauth/TestSignatureCalculator.java +++ b/src/test/java/com/ning/http/client/oauth/TestSignatureCalculator.java @@ -18,7 +18,10 @@ import org.testng.Assert; import org.testng.annotations.Test; -import com.ning.http.client.FluentStringsMap; +import com.ning.http.client.Param; + +import java.util.ArrayList; +import java.util.List; public class TestSignatureCalculator { @@ -42,9 +45,9 @@ public void test() ConsumerKey consumer = new ConsumerKey(CONSUMER_KEY, CONSUMER_SECRET); RequestToken user = new RequestToken(TOKEN_KEY, TOKEN_SECRET); OAuthSignatureCalculator calc = new OAuthSignatureCalculator(consumer, user); - FluentStringsMap queryParams = new FluentStringsMap(); - queryParams.add("file", "vacation.jpg"); - queryParams.add("size", "original"); + List queryParams = new ArrayList(); + queryParams.add(new Param("file", "vacation.jpg")); + queryParams.add(new Param("size", "original")); String url = "http://photos.example.net/photos"; String sig = calc.calculateSignature("GET", url, TIMESTAMP, NONCE, null, queryParams); From ff973f5259d14eaa18a72ccabcefd4e46da1dc0b Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 7 Jul 2014 11:15:21 +0200 Subject: [PATCH 343/701] minor clean up + comments, non functional change --- .../ning/http/client/RequestBuilderBase.java | 1 + .../netty/NettyAsyncHttpProvider.java | 32 ++++++++++++------- 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/ning/http/client/RequestBuilderBase.java b/src/main/java/com/ning/http/client/RequestBuilderBase.java index 433def45db..3503ab4900 100644 --- a/src/main/java/com/ning/http/client/RequestBuilderBase.java +++ b/src/main/java/com/ning/http/client/RequestBuilderBase.java @@ -165,6 +165,7 @@ private UriComponents toUriComponents(boolean encode) { AsyncHttpProviderUtils.validateSupportedScheme(originalUri); + // FIXME is that right? String newPath = isNonEmpty(originalUri.getPath())? originalUri.getPath() : "/"; String newQuery = null; if (isNonEmpty(queryParams)) { 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 b0a5cbec45..a5f380d0ca 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 @@ -658,25 +658,27 @@ private static SpnegoEngine getSpnegoEngine() { return spnegoEngine; } + private static String computeNonConnectRequestPath(AsyncHttpClientConfig config, UriComponents uri, ProxyServer proxyServer) { + if (proxyServer != null && !(isSecure(uri) && config.isUseRelativeURIsWithSSLProxies())) + return uri.toString(); + else if (uri.getQuery() != null) + return uri.getPath() + "?" + uri.getQuery(); + else + return uri.getPath(); + } + private static HttpRequest construct(AsyncHttpClientConfig config, Request request, HttpMethod m, UriComponents uri, ChannelBuffer buffer, ProxyServer proxyServer) throws IOException { - String host = request.getVirtualHost() != null ? request.getVirtualHost() : uri.getHost(); HttpRequest nettyRequest; if (m.equals(HttpMethod.CONNECT)) { nettyRequest = new DefaultHttpRequest(HttpVersion.HTTP_1_0, m, AsyncHttpProviderUtils.getAuthority(uri)); } else { - String path = null; - if (proxyServer != null && !(isSecure(uri) && config.isUseRelativeURIsWithSSLProxies())) - path = uri.toString(); - else if (uri.getQuery() != null) - path = uri.getPath() + "?" + uri.getQuery(); - else - path = uri.getPath(); + String path = computeNonConnectRequestPath(config, uri, proxyServer); nettyRequest = new DefaultHttpRequest(HttpVersion.HTTP_1_1, m, path); } boolean webSocket = isWebSocket(uri.getScheme()); - if (!m.equals(HttpMethod.CONNECT) && webSocket) { + if (webSocket && !m.equals(HttpMethod.CONNECT)) { 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()); @@ -684,7 +686,9 @@ else if (uri.getQuery() != null) nettyRequest.addHeader(HttpHeaders.Names.SEC_WEBSOCKET_VERSION, "13"); } + String host = request.getVirtualHost() != null ? request.getVirtualHost() : uri.getHost(); if (host != null) { + // FIXME why write port when regular host? if (request.getVirtualHost() != null || uri.getPort() == -1) { nettyRequest.setHeader(HttpHeaders.Names.HOST, host); } else { @@ -2091,9 +2095,13 @@ public void handle(final ChannelHandlerContext ctx, final MessageEvent e) throws if (newRealm == null) return; } else { - Realm.RealmBuilder realmBuilder = new Realm.RealmBuilder().clone(realm).setScheme(realm.getAuthScheme()); - newRealm = realmBuilder.setUri(request.getURI().getPath()).setMethodName(request.getMethod()).setUsePreemptiveAuth(true) - .parseWWWAuthenticateHeader(wwwAuth.get(0)).build(); + newRealm = new Realm.RealmBuilder().clone(realm) // + .setScheme(realm.getAuthScheme()) // + .setUri(request.getURI().getPath()) // + .setMethodName(request.getMethod()) // + .setUsePreemptiveAuth(true) // + .parseWWWAuthenticateHeader(wwwAuth.get(0)) // + .build(); } String realmURI = computeRealmURI(newRealm, request.getURI()); From 6e63f7efdbe2297027ed7f697b83462be606afde Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 7 Jul 2014 11:19:06 +0200 Subject: [PATCH 344/701] method, not reqType --- src/main/java/com/ning/http/client/AsyncHttpClient.java | 8 ++++---- 1 file changed, 4 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 a3970bbf2f..704ef83a77 100755 --- a/src/main/java/com/ning/http/client/AsyncHttpClient.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClient.java @@ -214,8 +214,8 @@ public AsyncHttpClient(String providerClass, AsyncHttpClientConfig config) { public class BoundRequestBuilder extends RequestBuilderBase { - private BoundRequestBuilder(String reqType, boolean useRawUrl) { - super(BoundRequestBuilder.class, reqType, useRawUrl); + private BoundRequestBuilder(String method, boolean useRawUrl) { + super(BoundRequestBuilder.class, method, useRawUrl); } private BoundRequestBuilder(Request prototype) { @@ -583,8 +583,8 @@ private final static AsyncHttpProvider loadDefaultProvider(String className, Asy } } - protected BoundRequestBuilder requestBuilder(String reqType, String url) { - return new BoundRequestBuilder(reqType, config.isUseRawUrl()).setUrl(url).setSignatureCalculator(signatureCalculator); + protected BoundRequestBuilder requestBuilder(String method, String url) { + return new BoundRequestBuilder(method, config.isUseRawUrl()).setUrl(url).setSignatureCalculator(signatureCalculator); } protected BoundRequestBuilder requestBuilder(Request prototype) { From 13eab71d65220a423fe795346f134775fcc2b49e Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 7 Jul 2014 13:25:39 +0200 Subject: [PATCH 345/701] Rename AHCConfig.useRawUrl into useRawUrlForBoundedRequests, close #596, close #554 --- .../com/ning/http/client/AsyncHttpClient.java | 2 +- .../http/client/AsyncHttpClientConfig.java | 24 +-- .../client/AsyncHttpClientConfigBean.java | 6 +- .../client/AsyncHttpClientConfigDefaults.java | 4 +- .../java/com/ning/http/client/Request.java | 11 -- .../ning/http/client/RequestBuilderBase.java | 143 +++++++----------- .../apache/ApacheAsyncHttpProvider.java | 7 +- .../grizzly/GrizzlyAsyncHttpProvider.java | 2 +- .../providers/jdk/JDKAsyncHttpProvider.java | 8 +- .../netty/NettyAsyncHttpProvider.java | 4 +- .../java/com/ning/http/util/ProxyUtils.java | 4 +- .../http/client/async/RequestBuilderTest.java | 13 +- .../client/websocket/ByteMessageTest.java | 1 - 13 files changed, 88 insertions(+), 141 deletions(-) diff --git a/src/main/java/com/ning/http/client/AsyncHttpClient.java b/src/main/java/com/ning/http/client/AsyncHttpClient.java index 704ef83a77..9939409fc0 100755 --- a/src/main/java/com/ning/http/client/AsyncHttpClient.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClient.java @@ -584,7 +584,7 @@ private final static AsyncHttpProvider loadDefaultProvider(String className, Asy } protected BoundRequestBuilder requestBuilder(String method, String url) { - return new BoundRequestBuilder(method, config.isUseRawUrl()).setUrl(url).setSignatureCalculator(signatureCalculator); + return new BoundRequestBuilder(method, config.isUseRawUrlForBoundedRequests()).setUrl(url).setSignatureCalculator(signatureCalculator); } protected BoundRequestBuilder requestBuilder(Request prototype) { diff --git a/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java b/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java index 4624bbf0c2..eabd0e41f8 100644 --- a/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java @@ -78,7 +78,7 @@ public class AsyncHttpClientConfig { protected int requestCompressionLevel; protected int maxRequestRetry; protected boolean allowSslConnectionPool; - protected boolean useRawUrl; + protected boolean useRawUrlForBoundedRequests; protected boolean removeQueryParamOnRedirect; protected HostnameVerifier hostnameVerifier; protected int ioThreadMultiplier; @@ -115,7 +115,7 @@ private AsyncHttpClientConfig(int maxTotalConnections, int requestCompressionLevel, int maxRequestRetry, boolean allowSslConnectionCaching, - boolean useRawUrl, + boolean useRawUrlForBoundedRequests, boolean removeQueryParamOnRedirect, HostnameVerifier hostnameVerifier, int ioThreadMultiplier, @@ -159,7 +159,7 @@ private AsyncHttpClientConfig(int maxTotalConnections, this.applicationThreadPool = applicationThreadPool; } this.proxyServerSelector = proxyServerSelector; - this.useRawUrl = useRawUrl; + this.useRawUrlForBoundedRequests = useRawUrlForBoundedRequests; this.timeConverter = timeConverter; } @@ -416,10 +416,10 @@ public boolean isSslConnectionPoolEnabled() { /** - * @return the useRawUrl + * @return the useRawUrlForBoundedRequests */ - public boolean isUseRawUrl() { - return useRawUrl; + public boolean isUseRawUrlForBoundedRequests() { + return useRawUrlForBoundedRequests; } /** @@ -543,7 +543,7 @@ public static class Builder { private int maxRequestRetry = defaultMaxRequestRetry(); private int ioThreadMultiplier = defaultIoThreadMultiplier(); private boolean allowSslConnectionPool = defaultAllowSslConnectionPool(); - private boolean useRawUrl = defaultUseRawUrl(); + private boolean useRawUrlForBoundedRequests = defaultUseRawUrlForBoundedRequests(); private boolean removeQueryParamOnRedirect = defaultRemoveQueryParamOnRedirect(); private boolean strict302Handling = defaultStrict302Handling(); private HostnameVerifier hostnameVerifier = defaultHostnameVerifier(); @@ -925,11 +925,11 @@ public Builder setAllowSslConnectionPool(boolean allowSslConnectionPool) { * Allows use unescaped URLs in requests * useful for retrieving data from broken sites * - * @param useRawUrl + * @param useRawUrlForBoundedRequests * @return this */ - public Builder setUseRawUrl(boolean useRawUrl) { - this.useRawUrl = useRawUrl; + public Builder setUseRawUrl(boolean useRawUrlForBoundedRequests) { + this.useRawUrlForBoundedRequests = useRawUrlForBoundedRequests; return this; } @@ -1068,7 +1068,7 @@ public Builder(AsyncHttpClientConfig prototype) { ioExceptionFilters.addAll(prototype.getIOExceptionFilters()); requestCompressionLevel = prototype.getRequestCompressionLevel(); - useRawUrl = prototype.isUseRawUrl(); + useRawUrlForBoundedRequests = prototype.isUseRawUrlForBoundedRequests(); ioThreadMultiplier = prototype.getIoThreadMultiplier(); maxRequestRetry = prototype.getMaxRequestRetry(); allowSslConnectionPool = prototype.getAllowPoolingConnection(); @@ -1134,7 +1134,7 @@ public Thread newThread(Runnable r) { requestCompressionLevel, maxRequestRetry, allowSslConnectionPool, - useRawUrl, + useRawUrlForBoundedRequests, removeQueryParamOnRedirect, hostnameVerifier, ioThreadMultiplier, diff --git a/src/main/java/com/ning/http/client/AsyncHttpClientConfigBean.java b/src/main/java/com/ning/http/client/AsyncHttpClientConfigBean.java index db2639a7f7..07e251e05e 100644 --- a/src/main/java/com/ning/http/client/AsyncHttpClientConfigBean.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClientConfigBean.java @@ -63,7 +63,7 @@ void configureDefaults() { maxRequestRetry = defaultMaxRequestRetry(); ioThreadMultiplier = defaultIoThreadMultiplier(); allowSslConnectionPool = defaultAllowSslConnectionPool(); - useRawUrl = defaultUseRawUrl(); + useRawUrlForBoundedRequests = defaultUseRawUrlForBoundedRequests(); removeQueryParamOnRedirect = defaultRemoveQueryParamOnRedirect(); strict302Handling = defaultStrict302Handling(); hostnameVerifier = defaultHostnameVerifier(); @@ -223,8 +223,8 @@ public AsyncHttpClientConfigBean setAllowSslConnectionPool(boolean allowSslConne return this; } - public AsyncHttpClientConfigBean setUseRawUrl(boolean useRawUrl) { - this.useRawUrl = useRawUrl; + public AsyncHttpClientConfigBean setUseRawUrlForBoundedRequests(boolean useRawUrlForBoundedRequests) { + this.useRawUrlForBoundedRequests = useRawUrlForBoundedRequests; return this; } diff --git a/src/main/java/com/ning/http/client/AsyncHttpClientConfigDefaults.java b/src/main/java/com/ning/http/client/AsyncHttpClientConfigDefaults.java index 58ccb8ce14..1badfe77f2 100644 --- a/src/main/java/com/ning/http/client/AsyncHttpClientConfigDefaults.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClientConfigDefaults.java @@ -109,8 +109,8 @@ public static boolean defaultAllowSslConnectionPool() { return getBoolean(ASYNC_CLIENT + "allowSslConnectionPool", true); } - public static boolean defaultUseRawUrl() { - return Boolean.getBoolean(ASYNC_CLIENT + "useRawUrl"); + public static boolean defaultUseRawUrlForBoundedRequests() { + return Boolean.getBoolean(ASYNC_CLIENT + "useRawUrlForBoundedRequests"); } public static boolean defaultRemoveQueryParamOnRedirect() { diff --git a/src/main/java/com/ning/http/client/Request.java b/src/main/java/com/ning/http/client/Request.java index 3e8ae483ff..7368063632 100644 --- a/src/main/java/com/ning/http/client/Request.java +++ b/src/main/java/com/ning/http/client/Request.java @@ -61,9 +61,7 @@ public static interface EntityWriter { */ String getUrl(); - UriComponents getOriginalURI(); UriComponents getURI(); - UriComponents getRawURI(); /** * Return the InetAddress to override @@ -74,13 +72,6 @@ public static interface EntityWriter { InetAddress getLocalAddress(); - /** - * Return the undecoded url - * - * @return the undecoded url - */ - String getRawUrl(); - /** * Return the current set of Headers. * @@ -214,7 +205,5 @@ public static interface EntityWriter { */ String getBodyEncoding(); - 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 3503ab4900..ca8f5ad94b 100644 --- a/src/main/java/com/ning/http/client/RequestBuilderBase.java +++ b/src/main/java/com/ning/http/client/RequestBuilderBase.java @@ -25,7 +25,6 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; -import java.util.Iterator; import java.util.List; import java.util.Map; @@ -50,9 +49,7 @@ public abstract class RequestBuilderBase> { private static final class RequestImpl implements Request { private String method; - private UriComponents originalUri; private UriComponents uri; - private UriComponents rawUri; private InetAddress address; private InetAddress localAddress; private FluentCaseInsensitiveStringsMap headers = new FluentCaseInsensitiveStringsMap(); @@ -74,17 +71,15 @@ private static final class RequestImpl implements Request { private int requestTimeoutInMs; private long rangeOffset; public String charset; - private boolean useRawUrl; private ConnectionPoolKeyStrategy connectionPoolKeyStrategy = DefaultConnectionPoolStrategy.INSTANCE; - public RequestImpl(boolean useRawUrl) { - this.useRawUrl = useRawUrl; + public RequestImpl() { } public RequestImpl(Request prototype) { if (prototype != null) { this.method = prototype.getMethod(); - this.originalUri = prototype.getOriginalURI(); + this.uri = prototype.getURI(); this.address = prototype.getInetAddress(); this.localAddress = prototype.getLocalAddress(); this.headers = new FluentCaseInsensitiveStringsMap(prototype.getHeaders()); @@ -106,7 +101,6 @@ public RequestImpl(Request prototype) { this.requestTimeoutInMs = prototype.getRequestTimeoutInMs(); this.rangeOffset = prototype.getRangeOffset(); this.charset = prototype.getBodyEncoding(); - this.useRawUrl = prototype.isUseRawUrl(); this.connectionPoolKeyStrategy = prototype.getConnectionPoolKeyStrategy(); } } @@ -136,71 +130,10 @@ public String getUrl() { return removeTrailingSlash(getURI()); } - public String getRawUrl() { - return removeTrailingSlash(getRawURI()); - } - - public UriComponents getOriginalURI() { - return originalUri; - } - public UriComponents getURI() { - if (uri == null) - uri = toUriComponents(true); return uri; } - public UriComponents getRawURI() { - if (rawUri == null) - rawUri = toUriComponents(false); - return rawUri; - } - - private UriComponents toUriComponents(boolean encode) { - - if (originalUri == null) { - logger.debug("setUrl hasn't been invoked. Using http://localhost"); - originalUri = DEFAULT_REQUEST_URL; - } - - AsyncHttpProviderUtils.validateSupportedScheme(originalUri); - - // FIXME is that right? - String newPath = isNonEmpty(originalUri.getPath())? originalUri.getPath() : "/"; - String newQuery = null; - if (isNonEmpty(queryParams)) { - StringBuilder sb = new StringBuilder(); - for (Iterator i = queryParams.iterator(); i.hasNext();) { - Param param = i.next(); - String name = param.getName(); - String value = param.getValue(); - if (encode) - UTF8UrlEncoder.appendEncoded(sb, name); - else - sb.append(name); - if (value != null) { - sb.append('='); - if (encode) - UTF8UrlEncoder.appendEncoded(sb, value); - else - sb.append(value); - } - if (i.hasNext()) - sb.append('&'); - } - - newQuery = sb.toString(); - } - - return new UriComponents(// - originalUri.getScheme(),// - originalUri.getUserInfo(),// - originalUri.getHost(),// - originalUri.getPort(),// - newPath,// - newQuery); - } - public FluentCaseInsensitiveStringsMap getHeaders() { return headers; } @@ -308,43 +241,34 @@ public String toString() { return sb.toString(); } - - public boolean isUseRawUrl() { - return useRawUrl; - } } private final Class derived; protected final RequestImpl request; - protected boolean useRawUrl = false; - protected String baseURL; + protected boolean useRawUrl; protected SignatureCalculator signatureCalculator; - protected RequestBuilderBase(Class derived, String method, boolean rawUrls) { + protected RequestBuilderBase(Class derived, String method, boolean useRawUrl) { this.derived = derived; - request = new RequestImpl(rawUrls); + request = new RequestImpl(); request.method = method; - this.useRawUrl = rawUrls; + this.useRawUrl = useRawUrl; } protected RequestBuilderBase(Class derived, Request prototype) { this.derived = derived; request = new RequestImpl(prototype); - this.useRawUrl = prototype.isUseRawUrl(); } public T setUrl(String url) { - this.baseURL = url; return setURI(UriComponents.create(url)); } public T setURI(UriComponents uri) { if (uri.getPath() == null) throw new NullPointerException("uri.path"); - request.originalUri = uri; - addQueryParams(request.originalUri); - request.uri = null; - request.rawUri = null; + request.uri = uri; + addQueryParams(uri); return derived.cast(this); } @@ -632,12 +556,8 @@ private void executeSignatureCalculator() { * (order does not matter with current implementation but may in future) */ if (signatureCalculator != null) { - String url = baseURL != null ? baseURL : request.originalUri.toString(); // Should not include query parameters, ensure: - int i = url.indexOf('?'); - if (i != -1) { - url = url.substring(0, i); - } + String url = new UriComponents(request.uri.getScheme(), null, request.uri.getHost(), request.uri.getPort(), request.uri.getPath(), null).toString(); signatureCalculator.calculateAndAddSignature(url, request, this); } } @@ -675,7 +595,52 @@ private void computeRequestLength() { } } + private void computeFinalUri() { + + if (request.uri == null) { + logger.debug("setUrl hasn't been invoked. Using http://localhost"); + request.uri = DEFAULT_REQUEST_URL; + } + + AsyncHttpProviderUtils.validateSupportedScheme(request.uri); + + // FIXME is that right? + String newPath = isNonEmpty(request.uri.getPath())? request.uri.getPath() : "/"; + String newQuery = null; + if (isNonEmpty(request.queryParams)) { + StringBuilder sb = new StringBuilder(); + for (Param param : request.queryParams) { + String name = param.getName(); + String value = param.getValue(); + if (!useRawUrl) + UTF8UrlEncoder.appendEncoded(sb, name); + else + sb.append(name); + if (value != null) { + sb.append('='); + if (!useRawUrl) + UTF8UrlEncoder.appendEncoded(sb, value); + else + sb.append(value); + } + sb.append('&'); + } + + sb.setLength(sb.length() - 1); + newQuery = sb.toString(); + } + + request.uri = new UriComponents(// + request.uri.getScheme(),// + request.uri.getUserInfo(),// + request.uri.getHost(),// + request.uri.getPort(),// + newPath,// + newQuery); + } + public Request build() { + computeFinalUri(); executeSignatureCalculator(); computeRequestCharset(); computeRequestLength(); 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 187411ada5..e3cb605ff2 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 @@ -460,12 +460,7 @@ public T call() { terminate = true; AsyncHandler.STATE state = AsyncHandler.STATE.ABORT; try { - UriComponents uri = null; - try { - uri = AsyncHttpProviderUtils.createNonEmptyPathURI(request.getRawUrl()); - } catch (IllegalArgumentException u) { - uri = AsyncHttpProviderUtils.createNonEmptyPathURI(request.getUrl()); - } + UriComponents uri = request.getURI(); int delay = AsyncHttpProviderUtils.requestTimeout(config, future.getRequest()); if (delay != -1) { 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 a150f12611..f3decfbf21 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 @@ -843,7 +843,7 @@ private boolean sendAsGrizzlyRequest(final Request request, convertToUpgradeRequest(httpCtx); } final Request req = httpCtx.request; - final UriComponents uri = req.isUseRawUrl() ? req.getRawURI() : req.getURI(); + final UriComponents uri = req.getURI(); final Method method = Method.valueOf(request.getMethod()); final HttpRequestPacket.Builder builder = HttpRequestPacket.builder(); boolean secure = "https".equals(uri.getScheme()); 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 045a07ed45..de454cb71e 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 @@ -231,13 +231,7 @@ public AsyncHttpUrlConnection(HttpURLConnection urlConnection, Request request, public T call() throws Exception { AsyncHandler.STATE state = AsyncHandler.STATE.ABORT; try { - UriComponents uri = null; - // Encoding with URLConnection is a bit bogus so we need to try both way before setting it - try { - uri = AsyncHttpProviderUtils.createNonEmptyPathURI(request.getRawUrl()); - } catch (IllegalArgumentException u) { - uri = AsyncHttpProviderUtils.createNonEmptyPathURI(request.getUrl()); - } + UriComponents uri = request.getURI(); configure(uri, urlConnection, request); urlConnection.connect(); 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 a5f380d0ca..2a84fcd659 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 @@ -208,7 +208,6 @@ public boolean remove(Object o) { private boolean executeConnectAsync = true; public static final ThreadLocal IN_IO_THREAD = new ThreadLocalBoolean(); private final boolean trackConnections; - private final boolean useRawUrl; private final boolean disableZeroCopy; private final static NTLMEngine ntlmEngine = new NTLMEngine(); private static SpnegoEngine spnegoEngine = null; @@ -289,7 +288,6 @@ public NettyAsyncHttpProvider(AsyncHttpClientConfig config) { trackConnections = false; } - useRawUrl = config.isUseRawUrl(); disableZeroCopy = providerConfig.isDisableZeroCopy(); } @@ -973,7 +971,7 @@ private ListenableFuture doConnect(final Request request, final AsyncHand throw new IOException("Closed"); } - UriComponents uri = useRawUrl ? request.getRawURI() : request.getURI(); + UriComponents uri = request.getURI(); if (uri.getScheme().startsWith(WEBSOCKET) && !validateWebSocketRequest(request, asyncHandler)) { throw new IOException("WebSocket method must be a GET"); diff --git a/src/main/java/com/ning/http/util/ProxyUtils.java b/src/main/java/com/ning/http/util/ProxyUtils.java index 36e8c242b1..67427af23e 100644 --- a/src/main/java/com/ning/http/util/ProxyUtils.java +++ b/src/main/java/com/ning/http/util/ProxyUtils.java @@ -85,7 +85,7 @@ public static ProxyServer getProxyServer(AsyncHttpClientConfig config, Request r if (proxyServer == null) { ProxyServerSelector selector = config.getProxyServerSelector(); if (selector != null) { - proxyServer = selector.select(request.getOriginalURI()); + proxyServer = selector.select(request.getURI()); } } return ProxyUtils.avoidProxy(proxyServer, request) ? null : proxyServer; @@ -95,7 +95,7 @@ public static ProxyServer getProxyServer(AsyncHttpClientConfig config, Request r * @see #avoidProxy(ProxyServer, String) */ public static boolean avoidProxy(final ProxyServer proxyServer, final Request request) { - return avoidProxy(proxyServer, request.getOriginalURI().getHost()); + return avoidProxy(proxyServer, request.getURI().getHost()); } private static boolean matchNonProxyHost(String targetHost, String nonProxyHost) { diff --git a/src/test/java/com/ning/http/client/async/RequestBuilderTest.java b/src/test/java/com/ning/http/client/async/RequestBuilderTest.java index 7a97b76ee9..1b0a369d48 100644 --- a/src/test/java/com/ning/http/client/async/RequestBuilderTest.java +++ b/src/test/java/com/ning/http/client/async/RequestBuilderTest.java @@ -124,12 +124,19 @@ public void testContentTypeCharsetToBodyEncoding() { } @Test(groups = {"standalone", "default_provider"}) - public void testAddQueryParameterReadRawUrl() throws UnsupportedEncodingException { - RequestBuilder rb = new RequestBuilder("GET", true).setUrl("http://example.com/path") + public void testAddQueryParameter() throws UnsupportedEncodingException { + RequestBuilder rb = new RequestBuilder("GET", false).setUrl("http://example.com/path") .addQueryParam("a", "1?&") .addQueryParam("b", "+ ="); Request request = rb.build(); assertEquals(request.getUrl(), "http://example.com/path?a=1%3F%26&b=%2B%20%3D"); - assertEquals(request.getRawUrl(), "http://example.com/path?a=1?&&b=+ ="); + } + + @Test(groups = {"standalone", "default_provider"}) + public void testRawUrlQuery() throws UnsupportedEncodingException { + String preEncodedUrl = "http://example.com/space%20mirror.php?%3Bteile"; + RequestBuilder rb = new RequestBuilder("GET", true).setUrl(preEncodedUrl); + Request request = rb.build(); + assertEquals(request.getUrl(), preEncodedUrl); } } 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 1811a3895b..4ed5706707 100644 --- a/src/test/java/com/ning/http/client/websocket/ByteMessageTest.java +++ b/src/test/java/com/ning/http/client/websocket/ByteMessageTest.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; From 7dcf7cb83aa9b9e2a5ffa2cf7badf25df20fbf2b Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 7 Jul 2014 13:38:15 +0200 Subject: [PATCH 346/701] Rename useRawUrl into disableUrlEncoding, close #597 --- .../com/ning/http/client/AsyncHttpClient.java | 6 ++--- .../http/client/AsyncHttpClientConfig.java | 27 +++++++++---------- .../client/AsyncHttpClientConfigBean.java | 6 ++--- .../client/AsyncHttpClientConfigDefaults.java | 4 +-- .../ning/http/client/RequestBuilderBase.java | 12 ++++----- .../GrizzlyNoTransferEncodingTest.java | 2 +- 6 files changed, 28 insertions(+), 29 deletions(-) diff --git a/src/main/java/com/ning/http/client/AsyncHttpClient.java b/src/main/java/com/ning/http/client/AsyncHttpClient.java index 9939409fc0..3e761639b2 100755 --- a/src/main/java/com/ning/http/client/AsyncHttpClient.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClient.java @@ -214,8 +214,8 @@ public AsyncHttpClient(String providerClass, AsyncHttpClientConfig config) { public class BoundRequestBuilder extends RequestBuilderBase { - private BoundRequestBuilder(String method, boolean useRawUrl) { - super(BoundRequestBuilder.class, method, useRawUrl); + private BoundRequestBuilder(String method, boolean isDisableUrlEncoding) { + super(BoundRequestBuilder.class, method, isDisableUrlEncoding); } private BoundRequestBuilder(Request prototype) { @@ -584,7 +584,7 @@ private final static AsyncHttpProvider loadDefaultProvider(String className, Asy } protected BoundRequestBuilder requestBuilder(String method, String url) { - return new BoundRequestBuilder(method, config.isUseRawUrlForBoundedRequests()).setUrl(url).setSignatureCalculator(signatureCalculator); + return new BoundRequestBuilder(method, config.isDisableUrlEncodingForBoundedRequests()).setUrl(url).setSignatureCalculator(signatureCalculator); } protected BoundRequestBuilder requestBuilder(Request prototype) { diff --git a/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java b/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java index eabd0e41f8..cd439de7b9 100644 --- a/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java @@ -78,7 +78,7 @@ public class AsyncHttpClientConfig { protected int requestCompressionLevel; protected int maxRequestRetry; protected boolean allowSslConnectionPool; - protected boolean useRawUrlForBoundedRequests; + protected boolean disableUrlEncodingForBoundedRequests; protected boolean removeQueryParamOnRedirect; protected HostnameVerifier hostnameVerifier; protected int ioThreadMultiplier; @@ -115,7 +115,7 @@ private AsyncHttpClientConfig(int maxTotalConnections, int requestCompressionLevel, int maxRequestRetry, boolean allowSslConnectionCaching, - boolean useRawUrlForBoundedRequests, + boolean disableUrlEncodingForBoundedRequests, boolean removeQueryParamOnRedirect, HostnameVerifier hostnameVerifier, int ioThreadMultiplier, @@ -159,7 +159,7 @@ private AsyncHttpClientConfig(int maxTotalConnections, this.applicationThreadPool = applicationThreadPool; } this.proxyServerSelector = proxyServerSelector; - this.useRawUrlForBoundedRequests = useRawUrlForBoundedRequests; + this.disableUrlEncodingForBoundedRequests = disableUrlEncodingForBoundedRequests; this.timeConverter = timeConverter; } @@ -416,10 +416,10 @@ public boolean isSslConnectionPoolEnabled() { /** - * @return the useRawUrlForBoundedRequests + * @return the disableUrlEncodingForBoundedRequests */ - public boolean isUseRawUrlForBoundedRequests() { - return useRawUrlForBoundedRequests; + public boolean isDisableUrlEncodingForBoundedRequests() { + return disableUrlEncodingForBoundedRequests; } /** @@ -543,7 +543,7 @@ public static class Builder { private int maxRequestRetry = defaultMaxRequestRetry(); private int ioThreadMultiplier = defaultIoThreadMultiplier(); private boolean allowSslConnectionPool = defaultAllowSslConnectionPool(); - private boolean useRawUrlForBoundedRequests = defaultUseRawUrlForBoundedRequests(); + private boolean disableUrlEncodingForBoundedRequests = defaultDisableUrlEncodingForBoundedRequests(); private boolean removeQueryParamOnRedirect = defaultRemoveQueryParamOnRedirect(); private boolean strict302Handling = defaultStrict302Handling(); private HostnameVerifier hostnameVerifier = defaultHostnameVerifier(); @@ -922,14 +922,13 @@ public Builder setAllowSslConnectionPool(boolean allowSslConnectionPool) { } /** - * Allows use unescaped URLs in requests - * useful for retrieving data from broken sites + * Disable automatic url escaping * - * @param useRawUrlForBoundedRequests + * @param disableUrlEncodingForBoundedRequests * @return this */ - public Builder setUseRawUrl(boolean useRawUrlForBoundedRequests) { - this.useRawUrlForBoundedRequests = useRawUrlForBoundedRequests; + public Builder setDisableUrlEncodingForBoundedRequests(boolean disableUrlEncodingForBoundedRequests) { + this.disableUrlEncodingForBoundedRequests = disableUrlEncodingForBoundedRequests; return this; } @@ -1068,7 +1067,7 @@ public Builder(AsyncHttpClientConfig prototype) { ioExceptionFilters.addAll(prototype.getIOExceptionFilters()); requestCompressionLevel = prototype.getRequestCompressionLevel(); - useRawUrlForBoundedRequests = prototype.isUseRawUrlForBoundedRequests(); + disableUrlEncodingForBoundedRequests = prototype.isDisableUrlEncodingForBoundedRequests(); ioThreadMultiplier = prototype.getIoThreadMultiplier(); maxRequestRetry = prototype.getMaxRequestRetry(); allowSslConnectionPool = prototype.getAllowPoolingConnection(); @@ -1134,7 +1133,7 @@ public Thread newThread(Runnable r) { requestCompressionLevel, maxRequestRetry, allowSslConnectionPool, - useRawUrlForBoundedRequests, + disableUrlEncodingForBoundedRequests, removeQueryParamOnRedirect, hostnameVerifier, ioThreadMultiplier, diff --git a/src/main/java/com/ning/http/client/AsyncHttpClientConfigBean.java b/src/main/java/com/ning/http/client/AsyncHttpClientConfigBean.java index 07e251e05e..7a5b7e1688 100644 --- a/src/main/java/com/ning/http/client/AsyncHttpClientConfigBean.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClientConfigBean.java @@ -63,7 +63,7 @@ void configureDefaults() { maxRequestRetry = defaultMaxRequestRetry(); ioThreadMultiplier = defaultIoThreadMultiplier(); allowSslConnectionPool = defaultAllowSslConnectionPool(); - useRawUrlForBoundedRequests = defaultUseRawUrlForBoundedRequests(); + disableUrlEncodingForBoundedRequests = defaultDisableUrlEncodingForBoundedRequests(); removeQueryParamOnRedirect = defaultRemoveQueryParamOnRedirect(); strict302Handling = defaultStrict302Handling(); hostnameVerifier = defaultHostnameVerifier(); @@ -223,8 +223,8 @@ public AsyncHttpClientConfigBean setAllowSslConnectionPool(boolean allowSslConne return this; } - public AsyncHttpClientConfigBean setUseRawUrlForBoundedRequests(boolean useRawUrlForBoundedRequests) { - this.useRawUrlForBoundedRequests = useRawUrlForBoundedRequests; + public AsyncHttpClientConfigBean setDisableUrlEncodingForBoundedRequests(boolean disableUrlEncodingForBoundedRequests) { + this.disableUrlEncodingForBoundedRequests = disableUrlEncodingForBoundedRequests; return this; } diff --git a/src/main/java/com/ning/http/client/AsyncHttpClientConfigDefaults.java b/src/main/java/com/ning/http/client/AsyncHttpClientConfigDefaults.java index 1badfe77f2..f565a3e7de 100644 --- a/src/main/java/com/ning/http/client/AsyncHttpClientConfigDefaults.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClientConfigDefaults.java @@ -109,8 +109,8 @@ public static boolean defaultAllowSslConnectionPool() { return getBoolean(ASYNC_CLIENT + "allowSslConnectionPool", true); } - public static boolean defaultUseRawUrlForBoundedRequests() { - return Boolean.getBoolean(ASYNC_CLIENT + "useRawUrlForBoundedRequests"); + public static boolean defaultDisableUrlEncodingForBoundedRequests() { + return Boolean.getBoolean(ASYNC_CLIENT + "disableUrlEncodingForBoundedRequests"); } public static boolean defaultRemoveQueryParamOnRedirect() { diff --git a/src/main/java/com/ning/http/client/RequestBuilderBase.java b/src/main/java/com/ning/http/client/RequestBuilderBase.java index ca8f5ad94b..da1ab46356 100644 --- a/src/main/java/com/ning/http/client/RequestBuilderBase.java +++ b/src/main/java/com/ning/http/client/RequestBuilderBase.java @@ -245,14 +245,14 @@ public String toString() { private final Class derived; protected final RequestImpl request; - protected boolean useRawUrl; + protected boolean disableUrlEncoding; protected SignatureCalculator signatureCalculator; - protected RequestBuilderBase(Class derived, String method, boolean useRawUrl) { + protected RequestBuilderBase(Class derived, String method, boolean disableUrlEncoding) { this.derived = derived; request = new RequestImpl(); request.method = method; - this.useRawUrl = useRawUrl; + this.disableUrlEncoding = disableUrlEncoding; } protected RequestBuilderBase(Class derived, Request prototype) { @@ -292,7 +292,7 @@ private void addQueryParams(UriComponents uri) { addQueryParam(query, null); } else { try { - if (useRawUrl) { + if (disableUrlEncoding) { addQueryParam(query.substring(0, pos), query.substring(pos + 1)); } else { addQueryParam(URLDecoder.decode(query.substring(0, pos), "UTF-8"), URLDecoder.decode(query.substring(pos + 1), "UTF-8")); @@ -612,13 +612,13 @@ private void computeFinalUri() { for (Param param : request.queryParams) { String name = param.getName(); String value = param.getValue(); - if (!useRawUrl) + if (!disableUrlEncoding) UTF8UrlEncoder.appendEncoded(sb, name); else sb.append(name); if (value != null) { sb.append('='); - if (!useRawUrl) + if (!disableUrlEncoding) UTF8UrlEncoder.appendEncoded(sb, value); else sb.append(value); diff --git a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyNoTransferEncodingTest.java b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyNoTransferEncodingTest.java index 8ce945dc25..58ad23a799 100644 --- a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyNoTransferEncodingTest.java +++ b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyNoTransferEncodingTest.java @@ -90,7 +90,7 @@ public void testNoTransferEncoding() throws Exception { .setConnectionTimeoutInMs(15000) .setRequestTimeoutInMs(15000) .setAllowPoolingConnection(false) - .setUseRawUrl(true) + .setDisableUrlEncodingForBoundedRequests(true) .setIOThreadMultiplier(2) // 2 is default .build(); From 7f0ffb4cbb0b2f89e79125a88604b22db0c2829b Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 7 Jul 2014 17:52:48 +0200 Subject: [PATCH 347/701] Only extract uri query params when building the request, close #598 --- .../ning/http/client/RequestBuilderBase.java | 192 ++++++++++++------ .../grizzly/GrizzlyAsyncHttpProvider.java | 2 +- .../netty/NettyAsyncHttpProvider.java | 2 +- 3 files changed, 135 insertions(+), 61 deletions(-) diff --git a/src/main/java/com/ning/http/client/RequestBuilderBase.java b/src/main/java/com/ning/http/client/RequestBuilderBase.java index da1ab46356..00173eff97 100644 --- a/src/main/java/com/ning/http/client/RequestBuilderBase.java +++ b/src/main/java/com/ning/http/client/RequestBuilderBase.java @@ -63,7 +63,6 @@ private static final class RequestImpl implements Request { private List parts; private String virtualHost; private long length = -1; - public List queryParams; public ProxyServer proxyServer; private Realm realm; private File file; @@ -72,6 +71,7 @@ private static final class RequestImpl implements Request { private long rangeOffset; public String charset; private ConnectionPoolKeyStrategy connectionPoolKeyStrategy = DefaultConnectionPoolStrategy.INSTANCE; + private List queryParams; public RequestImpl() { } @@ -90,7 +90,6 @@ public RequestImpl(Request prototype) { this.entityWriter = prototype.getEntityWriter(); this.bodyGenerator = prototype.getBodyGenerator(); this.formParams = prototype.getFormParams() == null ? null : new ArrayList(prototype.getFormParams()); - this.queryParams = prototype.getQueryParams() == null ? null : new ArrayList(prototype.getQueryParams()); this.parts = prototype.getParts() == null ? null : new ArrayList(prototype.getParts()); this.virtualHost = prototype.getVirtualHost(); this.length = prototype.getContentLength(); @@ -178,10 +177,6 @@ public String getVirtualHost() { return virtualHost; } - public List getQueryParams() { - return queryParams != null ? queryParams : Collections. emptyList(); - } - public ProxyServer getProxyServer() { return proxyServer; } @@ -214,6 +209,24 @@ public ConnectionPoolKeyStrategy getConnectionPoolKeyStrategy() { return connectionPoolKeyStrategy; } + @Override + public List getQueryParams() { + if (queryParams == null) + // lazy load + if (isNonEmpty(uri.getQuery())) { + queryParams = new ArrayList(1); + for (String queryStringParam : uri.getQuery().split("&")) { + int pos = queryStringParam.indexOf('='); + if (pos <= 0) + queryParams.add(new Param(queryStringParam, null)); + else + queryParams.add(new Param(queryStringParam.substring(0, pos), queryStringParam.substring(pos + 1))); + } + } else + queryParams = Collections.emptyList(); + return queryParams; + } + @Override public String toString() { StringBuilder sb = new StringBuilder(getURI().toString()); @@ -246,6 +259,7 @@ public String toString() { private final Class derived; protected final RequestImpl request; protected boolean disableUrlEncoding; + protected List queryParams; protected SignatureCalculator signatureCalculator; protected RequestBuilderBase(Class derived, String method, boolean disableUrlEncoding) { @@ -268,7 +282,6 @@ public T setURI(UriComponents uri) { if (uri.getPath() == null) throw new NullPointerException("uri.path"); request.uri = uri; - addQueryParams(uri); return derived.cast(this); } @@ -282,29 +295,6 @@ public T setLocalInetAddress(InetAddress address) { return derived.cast(this); } - private void addQueryParams(UriComponents uri) { - if (isNonEmpty(uri.getQuery())) { - String[] queries = uri.getQuery().split("&"); - int pos; - for (String query : queries) { - pos = query.indexOf("="); - if (pos <= 0) { - addQueryParam(query, null); - } else { - try { - if (disableUrlEncoding) { - addQueryParam(query.substring(0, pos), query.substring(pos + 1)); - } else { - addQueryParam(URLDecoder.decode(query.substring(0, pos), "UTF-8"), URLDecoder.decode(query.substring(pos + 1), "UTF-8")); - } - } catch (UnsupportedEncodingException e) { - throw new RuntimeException(e); - } - } - } - } - } - public T setVirtualHost(String virtualHost) { request.virtualHost = virtualHost; return derived.cast(this); @@ -381,8 +371,9 @@ public void resetCookies() { request.cookies.clear(); } - public void resetQueryParams() { - request.queryParams = null; + public void resetQuery() { + queryParams = null; + request.uri = request.uri.withNewQuery(null); } public void resetFormParams() { @@ -449,10 +440,10 @@ public T setBody(BodyGenerator bodyGenerator) { } public T addQueryParam(String name, String value) { - if (request.queryParams == null) { - request.queryParams = new ArrayList(1); + if (queryParams == null) { + queryParams = new ArrayList(1); } - request.queryParams.add(new Param(name, value)); + queryParams.add(new Param(name, value)); return derived.cast(this); } @@ -474,7 +465,7 @@ public T setQueryParams(Map> map) { } public T setQueryParams(List params) { - request.queryParams = params; + queryParams = params; return derived.cast(this); } @@ -595,6 +586,111 @@ private void computeRequestLength() { } } + private void appendRawQueryParams(StringBuilder sb, List queryParams) { + for (Param param : queryParams) + appendRawQueryParam(sb, param.getName(), param.getValue()); + } + + private void appendRawQueryParam(StringBuilder sb, String name, String value) { + sb.append(name); + if (value != null) + sb.append('=').append(value); + sb.append('&'); + } + + private String decodeUTF8(String s) { + try { + return URLDecoder.decode(s, "UTF-8"); + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + } + + // FIXME super inefficient!!! + private void appendEscapedQueryParam(StringBuilder sb, String name, String value) { + UTF8UrlEncoder.appendEncoded(sb, name); + if (value != null) { + sb.append('='); + UTF8UrlEncoder.appendEncoded(sb, value); + } + sb.append('&'); + } + + private void appendEscapeQuery(StringBuilder sb, String query) { + int pos; + for (String queryParamString : query.split("&")) { + pos = queryParamString.indexOf('='); + if (pos <= 0) { + String decodedName = decodeUTF8(queryParamString); + appendEscapedQueryParam(sb, decodedName, null); + } else { + String decodedName = decodeUTF8(queryParamString.substring(0, pos)); + String decodedValue = decodeUTF8(queryParamString.substring(pos + 1)); + appendEscapedQueryParam(sb, decodedName, decodedValue); + } + } + } + + private void appendEscapeQueryParams(StringBuilder sb, List queryParams) { + for (Param param: queryParams) + appendEscapedQueryParam(sb, param.getName(), param.getValue()); + } + + private String computeFinalQueryString(String query, List queryParams) { + + boolean hasQuery = isNonEmpty(query); + boolean hasQueryParams = isNonEmpty(queryParams); + + if (hasQuery) { + if (hasQueryParams) { + if (disableUrlEncoding) { + // concatenate raw query + raw query params + StringBuilder sb = new StringBuilder(query); + appendRawQueryParams(sb, queryParams); + sb.setLength(sb.length() - 1); + return sb.toString(); + } else { + // concatenate encoded query + encoded query params + StringBuilder sb = new StringBuilder(query.length() + 16); + appendEscapeQuery(sb, query); + appendEscapeQueryParams(sb, queryParams); + sb.setLength(sb.length() - 1); + return sb.toString(); + } + } else { + if (disableUrlEncoding) { + // return raw query as is + return query; + } else { + // encode query + StringBuilder sb = new StringBuilder(query.length() + 16); + appendEscapeQuery(sb, query); + sb.setLength(sb.length() - 1); + return sb.toString(); + } + } + } else { + if (hasQueryParams) { + if (disableUrlEncoding) { + // concatenate raw queryParams + StringBuilder sb = new StringBuilder(queryParams.size() * 16); + appendRawQueryParams(sb, queryParams); + sb.setLength(sb.length() - 1); + return sb.toString(); + } else { + // concatenate encoded query params + StringBuilder sb = new StringBuilder(queryParams.size() * 16); + appendEscapeQueryParams(sb, queryParams); + sb.setLength(sb.length() - 1); + return sb.toString(); + } + } else { + // neither query nor query param + return null; + } + } + } + private void computeFinalUri() { if (request.uri == null) { @@ -606,29 +702,7 @@ private void computeFinalUri() { // FIXME is that right? String newPath = isNonEmpty(request.uri.getPath())? request.uri.getPath() : "/"; - String newQuery = null; - if (isNonEmpty(request.queryParams)) { - StringBuilder sb = new StringBuilder(); - for (Param param : request.queryParams) { - String name = param.getName(); - String value = param.getValue(); - if (!disableUrlEncoding) - UTF8UrlEncoder.appendEncoded(sb, name); - else - sb.append(name); - if (value != null) { - sb.append('='); - if (!disableUrlEncoding) - UTF8UrlEncoder.appendEncoded(sb, value); - else - sb.append(value); - } - sb.append('&'); - } - - sb.setLength(sb.length() - 1); - newQuery = sb.toString(); - } + String newQuery = computeFinalQueryString(request.uri.getQuery(), queryParams); request.uri = new UriComponents(// request.uri.getScheme(),// 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 f3decfbf21..bfdd5ced81 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 @@ -1752,7 +1752,7 @@ private static Request newRequest(final UriComponents uri, builder.setUrl(uri.toString()); if (ctx.provider.clientConfig.isRemoveQueryParamOnRedirect()) { - builder.resetQueryParams();; + builder.resetQuery(); } for (String cookieStr : response.getHeaders().values(Header.Cookie)) { builder.addOrReplaceCookie(CookieDecoder.decode(cookieStr)); 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 2a84fcd659..e396859ded 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 @@ -1943,7 +1943,7 @@ private boolean redirect(Request request, NettyResponseFuture future, HttpRes final RequestBuilder nBuilder = new RequestBuilder(future.getRequest()); if (config.isRemoveQueryParamOnRedirect()) - nBuilder.resetQueryParams(); + nBuilder.resetQuery(); if (!(statusCode < 302 || statusCode > 303) && !(statusCode == 302 && config.isStrict302Handling())) { nBuilder.setMethod("GET"); From 744a2351af4adc4a1c5f6e87f055c00a3afce6c9 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 7 Jul 2014 18:14:28 +0200 Subject: [PATCH 348/701] Handle disabled removeQueryParamOnRedirect after #598, fix build --- src/main/java/com/ning/http/client/RequestBuilder.java | 5 +++++ src/main/java/com/ning/http/client/RequestBuilderBase.java | 6 ++++++ .../client/providers/grizzly/GrizzlyAsyncHttpProvider.java | 2 ++ .../http/client/providers/netty/NettyAsyncHttpProvider.java | 2 ++ 4 files changed, 15 insertions(+) diff --git a/src/main/java/com/ning/http/client/RequestBuilder.java b/src/main/java/com/ning/http/client/RequestBuilder.java index 209f0c2a86..3f49519fec 100644 --- a/src/main/java/com/ning/http/client/RequestBuilder.java +++ b/src/main/java/com/ning/http/client/RequestBuilder.java @@ -75,6 +75,11 @@ public RequestBuilder addQueryParam(String name, String value) { return super.addQueryParam(name, value); } + @Override + public RequestBuilder addQueryParams(List queryParams) { + return super.addQueryParams(queryParams); + } + @Override public RequestBuilder setQueryParams(List params) { return super.setQueryParams(params); diff --git a/src/main/java/com/ning/http/client/RequestBuilderBase.java b/src/main/java/com/ning/http/client/RequestBuilderBase.java index 00173eff97..c9d6605bc8 100644 --- a/src/main/java/com/ning/http/client/RequestBuilderBase.java +++ b/src/main/java/com/ning/http/client/RequestBuilderBase.java @@ -447,6 +447,12 @@ public T addQueryParam(String name, String value) { return derived.cast(this); } + public T addQueryParams(List queryParams) { + for (Param queryParam: queryParams) + addQueryParam(queryParam.getName(), queryParam.getValue()); + return derived.cast(this); + } + private List map2ParamList(Map> map) { if (map == null) return 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 bfdd5ced81..799cf509ab 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 @@ -1753,6 +1753,8 @@ private static Request newRequest(final UriComponents uri, if (ctx.provider.clientConfig.isRemoveQueryParamOnRedirect()) { builder.resetQuery(); + } else { + builder.addQueryParams(ctx.request.getQueryParams()); } for (String cookieStr : response.getHeaders().values(Header.Cookie)) { builder.addOrReplaceCookie(CookieDecoder.decode(cookieStr)); 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 e396859ded..b78956a2b6 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 @@ -1944,6 +1944,8 @@ private boolean redirect(Request request, NettyResponseFuture future, HttpRes if (config.isRemoveQueryParamOnRedirect()) nBuilder.resetQuery(); + else + nBuilder.addQueryParams(future.getRequest().getQueryParams()); if (!(statusCode < 302 || statusCode > 303) && !(statusCode == 302 && config.isStrict302Handling())) { nBuilder.setMethod("GET"); From de7fd2a9bff13c30bf8d501188ad0548de9708d2 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 7 Jul 2014 18:31:40 +0200 Subject: [PATCH 349/701] Use UTF8UrlEncoder.appendEncoded instead of encode, close #599 --- .../ning/http/client/oauth/OAuthSignatureCalculator.java | 2 +- .../java/com/ning/http/client/oauth/ThreadSafeHMAC.java | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) 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 f674bcb3af..a400f588da 100644 --- a/src/main/java/com/ning/http/client/oauth/OAuthSignatureCalculator.java +++ b/src/main/java/com/ning/http/client/oauth/OAuthSignatureCalculator.java @@ -113,7 +113,7 @@ public String calculateSignature(String method, String baseURL, long oauthTimest baseURL = baseURL.substring(0, i) + baseURL.substring(i + 4); } } - signedText.append(UTF8UrlEncoder.encode(baseURL)); + UTF8UrlEncoder.appendEncoded(signedText, baseURL); /** * List of all query and form parameters added to this request; needed 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 7ba72dd1a6..d5529a31cc 100644 --- a/src/main/java/com/ning/http/client/oauth/ThreadSafeHMAC.java +++ b/src/main/java/com/ning/http/client/oauth/ThreadSafeHMAC.java @@ -37,7 +37,11 @@ public class ThreadSafeHMAC { private final Mac mac; public ThreadSafeHMAC(ConsumerKey consumerAuth, RequestToken userAuth) { - byte[] keyBytes = UTF8Codec.toUTF8(UTF8UrlEncoder.encode(consumerAuth.getSecret()) + "&" + UTF8UrlEncoder.encode(userAuth.getSecret())); + StringBuilder sb = new StringBuilder(consumerAuth.getSecret().length() + userAuth.getSecret().length() + 16); + UTF8UrlEncoder.appendEncoded(sb, consumerAuth.getSecret()); + sb.append('&'); + UTF8UrlEncoder.appendEncoded(sb, userAuth.getSecret()); + byte[] keyBytes = UTF8Codec.toUTF8(sb.toString()); SecretKeySpec signingKey = new SecretKeySpec(keyBytes, HMAC_SHA1_ALGORITHM); // Get an hmac_sha1 instance and initialize with the signing key From 3da2797d4f688743c2af92b36cb7176818c4fd0d Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 7 Jul 2014 18:58:40 +0200 Subject: [PATCH 350/701] Don't try to decode if it's really necessary, first tentative for #600 --- .../ning/http/client/RequestBuilderBase.java | 63 +++++++++++-------- 1 file changed, 36 insertions(+), 27 deletions(-) diff --git a/src/main/java/com/ning/http/client/RequestBuilderBase.java b/src/main/java/com/ning/http/client/RequestBuilderBase.java index c9d6605bc8..4905e47e7b 100644 --- a/src/main/java/com/ning/http/client/RequestBuilderBase.java +++ b/src/main/java/com/ning/http/client/RequestBuilderBase.java @@ -591,19 +591,19 @@ private void computeRequestLength() { } } } - + private void appendRawQueryParams(StringBuilder sb, List queryParams) { for (Param param : queryParams) appendRawQueryParam(sb, param.getName(), param.getValue()); } - + private void appendRawQueryParam(StringBuilder sb, String name, String value) { sb.append(name); if (value != null) sb.append('=').append(value); sb.append('&'); } - + private String decodeUTF8(String s) { try { return URLDecoder.decode(s, "UTF-8"); @@ -611,9 +611,8 @@ private String decodeUTF8(String s) { throw new RuntimeException(e); } } - - // FIXME super inefficient!!! - private void appendEscapedQueryParam(StringBuilder sb, String name, String value) { + + private void encodeAndAppendQueryParam(StringBuilder sb, String name, String value) { UTF8UrlEncoder.appendEncoded(sb, name); if (value != null) { sb.append('='); @@ -622,31 +621,41 @@ private void appendEscapedQueryParam(StringBuilder sb, String name, String value sb.append('&'); } - private void appendEscapeQuery(StringBuilder sb, String query) { + private void encodeAndAppendQuery(StringBuilder sb, String query, boolean decode) { int pos; for (String queryParamString : query.split("&")) { pos = queryParamString.indexOf('='); if (pos <= 0) { - String decodedName = decodeUTF8(queryParamString); - appendEscapedQueryParam(sb, decodedName, null); + String decodedName = decode ? decodeUTF8(queryParamString) : queryParamString; + encodeAndAppendQueryParam(sb, decodedName, null); } else { - String decodedName = decodeUTF8(queryParamString.substring(0, pos)); - String decodedValue = decodeUTF8(queryParamString.substring(pos + 1)); - appendEscapedQueryParam(sb, decodedName, decodedValue); + String name = queryParamString.substring(0, pos); + String decodedName = decode ? decodeUTF8(name) : name; + String value = queryParamString.substring(pos + 1); + String decodedValue = decode ? decodeUTF8(value) : value; + encodeAndAppendQueryParam(sb, decodedName, decodedValue); } } } - - private void appendEscapeQueryParams(StringBuilder sb, List queryParams) { - for (Param param: queryParams) - appendEscapedQueryParam(sb, param.getName(), param.getValue()); + + private boolean decodeRequired(String query) { + return query.indexOf('%') != -1 || query.indexOf('+') != -1; } - + + private void encodeAndAppendQuery(StringBuilder sb, String query) { + encodeAndAppendQuery(sb, query, decodeRequired(query)); + } + + private void encodeAndAppendQueryParams(StringBuilder sb, List queryParams) { + for (Param param : queryParams) + encodeAndAppendQueryParam(sb, param.getName(), param.getValue()); + } + private String computeFinalQueryString(String query, List queryParams) { - + boolean hasQuery = isNonEmpty(query); boolean hasQueryParams = isNonEmpty(queryParams); - + if (hasQuery) { if (hasQueryParams) { if (disableUrlEncoding) { @@ -658,10 +667,10 @@ private String computeFinalQueryString(String query, List queryParams) { } else { // concatenate encoded query + encoded query params StringBuilder sb = new StringBuilder(query.length() + 16); - appendEscapeQuery(sb, query); - appendEscapeQueryParams(sb, queryParams); + encodeAndAppendQuery(sb, query); + encodeAndAppendQueryParams(sb, queryParams); sb.setLength(sb.length() - 1); - return sb.toString(); + return sb.toString(); } } else { if (disableUrlEncoding) { @@ -670,7 +679,7 @@ private String computeFinalQueryString(String query, List queryParams) { } else { // encode query StringBuilder sb = new StringBuilder(query.length() + 16); - appendEscapeQuery(sb, query); + encodeAndAppendQuery(sb, query); sb.setLength(sb.length() - 1); return sb.toString(); } @@ -686,7 +695,7 @@ private String computeFinalQueryString(String query, List queryParams) { } else { // concatenate encoded query params StringBuilder sb = new StringBuilder(queryParams.size() * 16); - appendEscapeQueryParams(sb, queryParams); + encodeAndAppendQueryParams(sb, queryParams); sb.setLength(sb.length() - 1); return sb.toString(); } @@ -696,7 +705,7 @@ private String computeFinalQueryString(String query, List queryParams) { } } } - + private void computeFinalUri() { if (request.uri == null) { @@ -707,7 +716,7 @@ private void computeFinalUri() { AsyncHttpProviderUtils.validateSupportedScheme(request.uri); // FIXME is that right? - String newPath = isNonEmpty(request.uri.getPath())? request.uri.getPath() : "/"; + String newPath = isNonEmpty(request.uri.getPath()) ? request.uri.getPath() : "/"; String newQuery = computeFinalQueryString(request.uri.getQuery(), queryParams); request.uri = new UriComponents(// @@ -718,7 +727,7 @@ private void computeFinalUri() { newPath,// newQuery); } - + public Request build() { computeFinalUri(); executeSignatureCalculator(); From cbf57abdfa8c804149e8d5c2ccd797e4ae0f43b4 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 7 Jul 2014 20:21:36 +0200 Subject: [PATCH 351/701] Minor UTF8UrlEncoder clean up, see #600 --- .../com/ning/http/util/UTF8UrlEncoder.java | 23 +++++++++---------- 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/ning/http/util/UTF8UrlEncoder.java b/src/main/java/com/ning/http/util/UTF8UrlEncoder.java index 3e24f1c2d7..f18c52f28e 100644 --- a/src/main/java/com/ning/http/util/UTF8UrlEncoder.java +++ b/src/main/java/com/ning/http/util/UTF8UrlEncoder.java @@ -20,28 +20,29 @@ * (as per RFC-3986, see [http://www.ietf.org/rfc/rfc3986.txt]). */ public class UTF8UrlEncoder { - private static final boolean encodeSpaceUsingPlus = System.getProperty("com.com.ning.http.util.UTF8UrlEncoder.encodeSpaceUsingPlus") == null ? false : true; + + private static final boolean encodeSpaceUsingPlus = MiscUtil.getBoolean("com.ning.http.util.UTF8UrlEncoder.encodeSpaceUsingPlus", false); /** * Encoding table used for figuring out ascii characters that must be escaped * (all non-Ascii characters need to be encoded anyway) */ - private final static int[] SAFE_ASCII = new int[128]; + private final static boolean[] SAFE_ASCII = new boolean[128]; static { for (int i = 'a'; i <= 'z'; ++i) { - SAFE_ASCII[i] = 1; + SAFE_ASCII[i] = true; } for (int i = 'A'; i <= 'Z'; ++i) { - SAFE_ASCII[i] = 1; + SAFE_ASCII[i] = true; } for (int i = '0'; i <= '9'; ++i) { - SAFE_ASCII[i] = 1; + SAFE_ASCII[i] = true; } - SAFE_ASCII['-'] = 1; - SAFE_ASCII['.'] = 1; - SAFE_ASCII['_'] = 1; - SAFE_ASCII['~'] = 1; + SAFE_ASCII['-'] = true; + SAFE_ASCII['.'] = true; + SAFE_ASCII['_'] = true; + SAFE_ASCII['~'] = true; } private final static char[] HEX = "0123456789ABCDEF".toCharArray(); @@ -56,12 +57,11 @@ public static String encode(String input) { } public static StringBuilder appendEncoded(StringBuilder sb, String input) { - final int[] safe = SAFE_ASCII; 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) { + if (SAFE_ASCII[c]) { sb.append((char) c); } else { appendSingleByteEncoded(sb, c); @@ -100,5 +100,4 @@ private final static void appendMultiByteEncoded(StringBuilder sb, int value) { appendSingleByteEncoded(sb, (0x80 | (value & 0x3f))); } } - } From e97030b628ebcf4be490f7daf3ccf7c7e706713c Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 7 Jul 2014 20:58:02 +0200 Subject: [PATCH 352/701] Remove dead code --- .../java/com/ning/http/util/UTF8Codec.java | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/src/main/java/com/ning/http/util/UTF8Codec.java b/src/main/java/com/ning/http/util/UTF8Codec.java index 29ee4cc20c..cb3a7ad2a3 100644 --- a/src/main/java/com/ning/http/util/UTF8Codec.java +++ b/src/main/java/com/ning/http/util/UTF8Codec.java @@ -36,14 +36,6 @@ public class UTF8Codec { public static byte[] toUTF8(String input) { return input.getBytes(utf8); } - - public static String fromUTF8(byte[] input) { - return fromUTF8(input, 0, input.length); - } - - public static String fromUTF8(byte[] input, int offset, int len) { - return new String(input, offset, len, utf8); - } */ // But until then (with 1.5) @@ -54,16 +46,4 @@ public static byte[] toUTF8(String input) { throw new IllegalStateException(); } } - - public static String fromUTF8(byte[] input) { - return fromUTF8(input, 0, input.length); - } - - public static String fromUTF8(byte[] input, int offset, int len) { - try { - return new String(input, offset, len, ENCODING_UTF8); - } catch (UnsupportedEncodingException e) { // never happens - throw new IllegalStateException(); - } - } } From cadc9d6e6d3f1d9c8caa29bde5f6e2e68ccacbf1 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 7 Jul 2014 22:54:26 +0200 Subject: [PATCH 353/701] Introduce UTF8UrlDecoder, see #600 --- .../ning/http/client/RequestBuilderBase.java | 17 ++---- .../com/ning/http/util/UTF8UrlDecoder.java | 61 +++++++++++++++++++ .../com/ning/http/util/UTF8UrlEncoder.java | 4 +- 3 files changed, 67 insertions(+), 15 deletions(-) create mode 100644 src/main/java/com/ning/http/util/UTF8UrlDecoder.java diff --git a/src/main/java/com/ning/http/client/RequestBuilderBase.java b/src/main/java/com/ning/http/client/RequestBuilderBase.java index 4905e47e7b..5fcf4ab1f0 100644 --- a/src/main/java/com/ning/http/client/RequestBuilderBase.java +++ b/src/main/java/com/ning/http/client/RequestBuilderBase.java @@ -19,9 +19,7 @@ import java.io.File; import java.io.InputStream; -import java.io.UnsupportedEncodingException; import java.net.InetAddress; -import java.net.URLDecoder; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -35,6 +33,7 @@ import com.ning.http.client.cookie.Cookie; import com.ning.http.client.uri.UriComponents; import com.ning.http.util.AsyncHttpProviderUtils; +import com.ning.http.util.UTF8UrlDecoder; import com.ning.http.util.UTF8UrlEncoder; /** @@ -604,14 +603,6 @@ private void appendRawQueryParam(StringBuilder sb, String name, String value) { sb.append('&'); } - private String decodeUTF8(String s) { - try { - return URLDecoder.decode(s, "UTF-8"); - } catch (UnsupportedEncodingException e) { - throw new RuntimeException(e); - } - } - private void encodeAndAppendQueryParam(StringBuilder sb, String name, String value) { UTF8UrlEncoder.appendEncoded(sb, name); if (value != null) { @@ -626,13 +617,13 @@ private void encodeAndAppendQuery(StringBuilder sb, String query, boolean decode for (String queryParamString : query.split("&")) { pos = queryParamString.indexOf('='); if (pos <= 0) { - String decodedName = decode ? decodeUTF8(queryParamString) : queryParamString; + String decodedName = decode ? UTF8UrlDecoder.decode(queryParamString) : queryParamString; encodeAndAppendQueryParam(sb, decodedName, null); } else { String name = queryParamString.substring(0, pos); - String decodedName = decode ? decodeUTF8(name) : name; + String decodedName = decode ? UTF8UrlDecoder.decode(name) : name; String value = queryParamString.substring(pos + 1); - String decodedValue = decode ? decodeUTF8(value) : value; + String decodedValue = decode ? UTF8UrlDecoder.decode(value) : value; encodeAndAppendQueryParam(sb, decodedName, decodedValue); } } diff --git a/src/main/java/com/ning/http/util/UTF8UrlDecoder.java b/src/main/java/com/ning/http/util/UTF8UrlDecoder.java new file mode 100644 index 0000000000..ac4d398fbe --- /dev/null +++ b/src/main/java/com/ning/http/util/UTF8UrlDecoder.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2014 AsyncHttpClient Project. 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; + +public final class UTF8UrlDecoder { + + private UTF8UrlDecoder() { + } + + private static StringBuilder initSb(StringBuilder sb, int initialSbLength, String s, int i) { + return sb != null ? sb : new StringBuilder(initialSbLength).append(s, 0, i); + } + + private static int hexaDigit(char c) { + return Character.digit(c, 0x10); + } + + public static String decode(String s) { + + final int numChars = s.length(); + final int initialSbLength = numChars > 500 ? numChars / 2 : numChars; + StringBuilder sb = null; + int i = 0; + + while (i < numChars) { + char c = s.charAt(i); + if (c == '+') { + sb = initSb(sb, initialSbLength, s, i); + sb.append(' '); + i++; + + } else if (c == '%') { + if (numChars - i < 2) + throw new IllegalArgumentException("UTF8UrlDecoder: Incomplete trailing escape (%) pattern"); + + int x, y; + if ((x = hexaDigit(s.charAt(++i))) == -1 || (y = hexaDigit(s.charAt(++i))) == -1) + throw new IllegalArgumentException("UTF8UrlDecoder: Malformed"); + + sb = initSb(sb, initialSbLength, s, i); + sb.append((byte) ((x << 4) + y)); + } else { + if (sb != null) + sb.append(c); + i++; + } + } + + return sb != null ? sb.toString() : s; + } +} diff --git a/src/main/java/com/ning/http/util/UTF8UrlEncoder.java b/src/main/java/com/ning/http/util/UTF8UrlEncoder.java index f18c52f28e..758849b6f6 100644 --- a/src/main/java/com/ning/http/util/UTF8UrlEncoder.java +++ b/src/main/java/com/ning/http/util/UTF8UrlEncoder.java @@ -19,7 +19,7 @@ * Convenience class that encapsulates details of "percent encoding" * (as per RFC-3986, see [http://www.ietf.org/rfc/rfc3986.txt]). */ -public class UTF8UrlEncoder { +public final class UTF8UrlEncoder { private static final boolean encodeSpaceUsingPlus = MiscUtil.getBoolean("com.ning.http.util.UTF8UrlEncoder.encodeSpaceUsingPlus", false); @@ -45,7 +45,7 @@ public class UTF8UrlEncoder { SAFE_ASCII['~'] = true; } - private final static char[] HEX = "0123456789ABCDEF".toCharArray(); + private static final char[] HEX = "0123456789ABCDEF".toCharArray(); private UTF8UrlEncoder() { } From b8db590309bd8ce826e6662d9ac70189d71a7079 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 7 Jul 2014 23:43:12 +0200 Subject: [PATCH 354/701] Fix UriComponents.toURI, see @gerdriesselmann comments in #596 --- .../ning/http/client/RequestBuilderBase.java | 4 +-- .../apache/ApacheAsyncHttpProvider.java | 7 ++-- .../grizzly/GrizzlyAsyncHttpProvider.java | 4 +-- .../providers/jdk/JDKAsyncHttpProvider.java | 7 ++-- .../ning/http/client/uri/UriComponents.java | 32 +++++++++---------- .../http/client/async/RequestBuilderTest.java | 5 ++- 6 files changed, 30 insertions(+), 29 deletions(-) diff --git a/src/main/java/com/ning/http/client/RequestBuilderBase.java b/src/main/java/com/ning/http/client/RequestBuilderBase.java index 5fcf4ab1f0..4c2a1a7008 100644 --- a/src/main/java/com/ning/http/client/RequestBuilderBase.java +++ b/src/main/java/com/ning/http/client/RequestBuilderBase.java @@ -116,7 +116,7 @@ public InetAddress getLocalAddress() { } private String removeTrailingSlash(UriComponents uri) { - String uriString = uri.toString(); + String uriString = uri.toUrl(); if (uriString.endsWith("/")) { return uriString.substring(0, uriString.length() - 1); } else { @@ -228,7 +228,7 @@ public List getQueryParams() { @Override public String toString() { - StringBuilder sb = new StringBuilder(getURI().toString()); + StringBuilder sb = new StringBuilder(getURI().toUrl()); sb.append("\t"); sb.append(method); 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 e3cb605ff2..92a521c777 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 @@ -510,14 +510,13 @@ public T call() { if (currentRedirectCount++ < config.getMaxRedirects()) { String location = method.getResponseHeader("Location").getValue(); UriComponents rediUri = UriComponents.create(uri, location); - String newUrl = rediUri.toString(); - if (!newUrl.equals(uri.toString())) { + if (!rediUri.equals(uri)) { RequestBuilder builder = new RequestBuilder(request); - logger.debug("Redirecting to {}", newUrl); + logger.debug("Redirecting to {}", rediUri); - request = builder.setUrl(newUrl).build(); + request = builder.setURI(rediUri).build(); method = createMethod(httpClient, request); terminate = false; return call(); 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 799cf509ab..39d855a30c 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 @@ -870,7 +870,7 @@ private boolean sendAsGrizzlyRequest(final Request request, } else if (secure && config.isUseRelativeURIsWithSSLProxies()){ builder.uri(uri.getPath()); } else { - builder.uri(uri.toString()); + builder.uri(uri.toUrl()); } } else { builder.uri(uri.getPath()); @@ -1658,7 +1658,7 @@ public boolean handleStatus(final HttpResponsePacket responsePacket, httpTransactionContext.lastRedirectURI = redirectURL; Request requestToSend; UriComponents uri = UriComponents.create(orig, redirectURL); - if (!uri.toString().equalsIgnoreCase(orig.toString())) { + if (!uri.toUrl().equalsIgnoreCase(orig.toUrl())) { requestToSend = newRequest(uri, responsePacket, httpTransactionContext, 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 de454cb71e..c5fd3d9dc9 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 @@ -267,14 +267,13 @@ public T call() throws Exception { if (currentRedirectCount++ < config.getMaxRedirects()) { String location = urlConnection.getHeaderField("Location"); UriComponents redirUri = UriComponents.create(uri, location); - String newUrl = redirUri.toString(); - if (!newUrl.equals(uri.toString())) { + if (!redirUri.equals(uri)) { RequestBuilder builder = new RequestBuilder(request); - logger.debug("Redirecting to {}", newUrl); + logger.debug("Redirecting to {}", redirUri); - request = builder.setUrl(newUrl).build(); + request = builder.setURI(redirUri).build(); urlConnection = createUrlConnection(request); terminate = false; return call(); diff --git a/src/main/java/com/ning/http/client/uri/UriComponents.java b/src/main/java/com/ning/http/client/uri/UriComponents.java index 5ba4f30cc9..fff21ac7ab 100644 --- a/src/main/java/com/ning/http/client/uri/UriComponents.java +++ b/src/main/java/com/ning/http/client/uri/UriComponents.java @@ -25,8 +25,7 @@ public static UriComponents create(UriComponents context, final String originalU UriComponentsParser parser = new UriComponentsParser(); parser.parse(context, originalUrl); - return new UriComponents( - parser.scheme,// + return new UriComponents(parser.scheme,// parser.userInfo,// parser.host,// parser.port,// @@ -41,8 +40,7 @@ public static UriComponents create(UriComponents context, final String originalU private final String query; private final String path; - public UriComponents( - String scheme,// + public UriComponents(String scheme,// String userInfo,// String host,// int port,// @@ -87,12 +85,10 @@ public String getHost() { } public URI toURI() throws URISyntaxException { - return new URI(scheme, userInfo, host, port, path, query, null); + return new URI(toUrl()); } - - @Override - public String toString() { - + + public String toUrl() { StringBuilder sb = new StringBuilder(); sb.append(scheme).append("://"); if (userInfo != null) @@ -104,13 +100,18 @@ public String toString() { sb.append(path); if (query != null) sb.append('?').append(query); - + return sb.toString(); } - + + @Override + public String toString() { + // for now, but might change + return toUrl(); + } + public UriComponents withNewScheme(String newScheme) { - return new UriComponents( - newScheme,// + return new UriComponents(newScheme,// userInfo,// host,// port,// @@ -119,15 +120,14 @@ public UriComponents withNewScheme(String newScheme) { } public UriComponents withNewQuery(String newQuery) { - return new UriComponents( - scheme,// + return new UriComponents(scheme,// userInfo,// host,// port,// path,// newQuery); } - + @Override public int hashCode() { final int prime = 31; diff --git a/src/test/java/com/ning/http/client/async/RequestBuilderTest.java b/src/test/java/com/ning/http/client/async/RequestBuilderTest.java index 1b0a369d48..b73f08a5c1 100644 --- a/src/test/java/com/ning/http/client/async/RequestBuilderTest.java +++ b/src/test/java/com/ning/http/client/async/RequestBuilderTest.java @@ -25,6 +25,7 @@ import java.io.IOException; import java.io.UnsupportedEncodingException; +import java.net.URISyntaxException; import java.util.List; import java.util.concurrent.ExecutionException; @@ -133,10 +134,12 @@ public void testAddQueryParameter() throws UnsupportedEncodingException { } @Test(groups = {"standalone", "default_provider"}) - public void testRawUrlQuery() throws UnsupportedEncodingException { + public void testRawUrlQuery() throws UnsupportedEncodingException, URISyntaxException { String preEncodedUrl = "http://example.com/space%20mirror.php?%3Bteile"; RequestBuilder rb = new RequestBuilder("GET", true).setUrl(preEncodedUrl); Request request = rb.build(); assertEquals(request.getUrl(), preEncodedUrl); + assertEquals(request.getURI().toUrl(), preEncodedUrl); + assertEquals(request.getURI().toURI().toString(), preEncodedUrl); } } From b4cf6ed383a421419e3cb7d61814334a311b5bae Mon Sep 17 00:00:00 2001 From: Gerd Riesselmann Date: Tue, 8 Jul 2014 00:54:59 +0200 Subject: [PATCH 355/701] Add tests for UTF8UrlDecoder and fix bugs in decoding % values --- .../com/ning/http/util/UTF8UrlDecoder.java | 9 ++++--- .../com/ning/http/util/TestUTF8UrlCodec.java | 27 +++++++++++++++++++ 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/ning/http/util/UTF8UrlDecoder.java b/src/main/java/com/ning/http/util/UTF8UrlDecoder.java index ac4d398fbe..41d071dd16 100644 --- a/src/main/java/com/ning/http/util/UTF8UrlDecoder.java +++ b/src/main/java/com/ning/http/util/UTF8UrlDecoder.java @@ -40,15 +40,18 @@ public static String decode(String s) { i++; } else if (c == '%') { - if (numChars - i < 2) + if (numChars - i < 3) // We expect 3 chars. 0 based i vs. 1 based length! throw new IllegalArgumentException("UTF8UrlDecoder: Incomplete trailing escape (%) pattern"); int x, y; - if ((x = hexaDigit(s.charAt(++i))) == -1 || (y = hexaDigit(s.charAt(++i))) == -1) + if ((x = hexaDigit(s.charAt(i+1))) == -1 || (y = hexaDigit(s.charAt(i+2))) == -1) throw new IllegalArgumentException("UTF8UrlDecoder: Malformed"); sb = initSb(sb, initialSbLength, s, i); - sb.append((byte) ((x << 4) + y)); + byte b = (byte)((x << 4) + y); + char cc = (char)(b); + sb.append(cc); + i+=3; } else { if (sb != null) sb.append(c); diff --git a/src/test/java/com/ning/http/util/TestUTF8UrlCodec.java b/src/test/java/com/ning/http/util/TestUTF8UrlCodec.java index a0cd0f3c34..53284944cd 100644 --- a/src/test/java/com/ning/http/util/TestUTF8UrlCodec.java +++ b/src/test/java/com/ning/http/util/TestUTF8UrlCodec.java @@ -38,4 +38,31 @@ public void testNonBmp() // Plane 15 Assert.assertEquals(UTF8UrlEncoder.encode("\udb80\udc01"), "%F3%B0%80%81"); } + + @Test(groups="fast") + public void testDecodeBasics() + { + Assert.assertEquals(UTF8UrlDecoder.decode("foobar"), "foobar"); + Assert.assertEquals(UTF8UrlDecoder.decode("a&b"), "a&b"); + Assert.assertEquals(UTF8UrlDecoder.decode("a+b"), "a b"); + + Assert.assertEquals(UTF8UrlDecoder.decode("+"), " "); + Assert.assertEquals(UTF8UrlDecoder.decode("%20"), " "); + Assert.assertEquals(UTF8UrlDecoder.decode("%25"), "%"); + + Assert.assertEquals(UTF8UrlDecoder.decode("+%20x"), " x"); + } + + @Test(groups="fast") + public void testDecodeTooShort() + { + try { + UTF8UrlDecoder.decode("%2"); + Assert.assertTrue(false, "No exception thrown on illegal encoding length"); + } catch (IllegalArgumentException ex) { + Assert.assertEquals("UTF8UrlDecoder: Incomplete trailing escape (%) pattern", ex.getMessage()); + } catch (StringIndexOutOfBoundsException ex) { + Assert.assertTrue(false, "String Index Out of Bound thrown, but should be IllegalArgument"); + } + } } From 9ae789fe33e96d46fb5e6950d5ef37eafbd39d6d Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 8 Jul 2014 01:09:40 +0200 Subject: [PATCH 356/701] Rename --- .../util/{TestUTF8UrlCodec.java => UTF8UrlCodecTest.java} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename src/test/java/com/ning/http/util/{TestUTF8UrlCodec.java => UTF8UrlCodecTest.java} (94%) diff --git a/src/test/java/com/ning/http/util/TestUTF8UrlCodec.java b/src/test/java/com/ning/http/util/UTF8UrlCodecTest.java similarity index 94% rename from src/test/java/com/ning/http/util/TestUTF8UrlCodec.java rename to src/test/java/com/ning/http/util/UTF8UrlCodecTest.java index 53284944cd..8ca9ec7bea 100644 --- a/src/test/java/com/ning/http/util/TestUTF8UrlCodec.java +++ b/src/test/java/com/ning/http/util/UTF8UrlCodecTest.java @@ -18,7 +18,7 @@ import org.testng.Assert; import org.testng.annotations.Test; -public class TestUTF8UrlCodec +public class UTF8UrlCodecTest { @Test(groups="fast") public void testBasics() @@ -60,7 +60,7 @@ public void testDecodeTooShort() UTF8UrlDecoder.decode("%2"); Assert.assertTrue(false, "No exception thrown on illegal encoding length"); } catch (IllegalArgumentException ex) { - Assert.assertEquals("UTF8UrlDecoder: Incomplete trailing escape (%) pattern", ex.getMessage()); + Assert.assertEquals(ex.getMessage(), "UTF8UrlDecoder: Incomplete trailing escape (%) pattern"); } catch (StringIndexOutOfBoundsException ex) { Assert.assertTrue(false, "String Index Out of Bound thrown, but should be IllegalArgument"); } From 1720c0896585c9b61c78e5357004304d13a588e9 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 8 Jul 2014 01:10:07 +0200 Subject: [PATCH 357/701] format --- .../com/ning/http/util/UTF8UrlCodecTest.java | 24 ++++++++----------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/src/test/java/com/ning/http/util/UTF8UrlCodecTest.java b/src/test/java/com/ning/http/util/UTF8UrlCodecTest.java index 8ca9ec7bea..2811eeadb9 100644 --- a/src/test/java/com/ning/http/util/UTF8UrlCodecTest.java +++ b/src/test/java/com/ning/http/util/UTF8UrlCodecTest.java @@ -18,19 +18,17 @@ import org.testng.Assert; import org.testng.annotations.Test; -public class UTF8UrlCodecTest -{ - @Test(groups="fast") - public void testBasics() - { +public class UTF8UrlCodecTest { + + @Test(groups = "fast") + public void testBasics() { Assert.assertEquals(UTF8UrlEncoder.encode("foobar"), "foobar"); Assert.assertEquals(UTF8UrlEncoder.encode("a&b"), "a%26b"); Assert.assertEquals(UTF8UrlEncoder.encode("a+b"), "a%2Bb"); } - @Test(groups="fast") - public void testNonBmp() - { + @Test(groups = "fast") + public void testNonBmp() { // Plane 1 Assert.assertEquals(UTF8UrlEncoder.encode("\uD83D\uDCA9"), "%F0%9F%92%A9"); // Plane 2 @@ -39,9 +37,8 @@ public void testNonBmp() Assert.assertEquals(UTF8UrlEncoder.encode("\udb80\udc01"), "%F3%B0%80%81"); } - @Test(groups="fast") - public void testDecodeBasics() - { + @Test(groups = "fast") + public void testDecodeBasics() { Assert.assertEquals(UTF8UrlDecoder.decode("foobar"), "foobar"); Assert.assertEquals(UTF8UrlDecoder.decode("a&b"), "a&b"); Assert.assertEquals(UTF8UrlDecoder.decode("a+b"), "a b"); @@ -53,9 +50,8 @@ public void testDecodeBasics() Assert.assertEquals(UTF8UrlDecoder.decode("+%20x"), " x"); } - @Test(groups="fast") - public void testDecodeTooShort() - { + @Test(groups = "fast") + public void testDecodeTooShort() { try { UTF8UrlDecoder.decode("%2"); Assert.assertTrue(false, "No exception thrown on illegal encoding length"); From 270a9c2a9f34dd761ee5a4c2d36da0736c22be70 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 8 Jul 2014 01:12:34 +0200 Subject: [PATCH 358/701] minor clean up --- src/main/java/com/ning/http/util/UTF8UrlDecoder.java | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/ning/http/util/UTF8UrlDecoder.java b/src/main/java/com/ning/http/util/UTF8UrlDecoder.java index 41d071dd16..265e4c551d 100644 --- a/src/main/java/com/ning/http/util/UTF8UrlDecoder.java +++ b/src/main/java/com/ning/http/util/UTF8UrlDecoder.java @@ -22,7 +22,7 @@ private static StringBuilder initSb(StringBuilder sb, int initialSbLength, Strin } private static int hexaDigit(char c) { - return Character.digit(c, 0x10); + return Character.digit(c, 16); } public static String decode(String s) { @@ -44,14 +44,12 @@ public static String decode(String s) { throw new IllegalArgumentException("UTF8UrlDecoder: Incomplete trailing escape (%) pattern"); int x, y; - if ((x = hexaDigit(s.charAt(i+1))) == -1 || (y = hexaDigit(s.charAt(i+2))) == -1) + if ((x = hexaDigit(s.charAt(i + 1))) == -1 || (y = hexaDigit(s.charAt(i + 2))) == -1) throw new IllegalArgumentException("UTF8UrlDecoder: Malformed"); sb = initSb(sb, initialSbLength, s, i); - byte b = (byte)((x << 4) + y); - char cc = (char)(b); - sb.append(cc); - i+=3; + sb.append((char) (x * 16 + y)); + i += 3; } else { if (sb != null) sb.append(c); From 761b6f3c2940e1773b0ce6c28b9d6c6df2e1c2e1 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 8 Jul 2014 10:23:21 +0200 Subject: [PATCH 359/701] Extract Query computing logic, close #602 --- .../com/ning/http/client/RequestBuilder.java | 9 ++ .../ning/http/client/RequestBuilderBase.java | 126 ++------------- .../com/ning/http/util/QueryComputer.java | 148 ++++++++++++++++++ 3 files changed, 171 insertions(+), 112 deletions(-) create mode 100644 src/main/java/com/ning/http/util/QueryComputer.java diff --git a/src/main/java/com/ning/http/client/RequestBuilder.java b/src/main/java/com/ning/http/client/RequestBuilder.java index 3f49519fec..4771d4906a 100644 --- a/src/main/java/com/ning/http/client/RequestBuilder.java +++ b/src/main/java/com/ning/http/client/RequestBuilder.java @@ -22,6 +22,7 @@ import com.ning.http.client.Request.EntityWriter; import com.ning.http.client.cookie.Cookie; +import com.ning.http.util.QueryComputer; /** * Builder for a {@link Request}. @@ -42,10 +43,18 @@ public RequestBuilder(String method, boolean useRawUrl) { super(RequestBuilder.class, method, useRawUrl); } + public RequestBuilder(String method, QueryComputer queryComputer) { + super(RequestBuilder.class, method, queryComputer); + } + public RequestBuilder(Request prototype) { super(RequestBuilder.class, prototype); } + public RequestBuilder(Request prototype, QueryComputer queryComputer) { + super(RequestBuilder.class, prototype, queryComputer); + } + // Note: For now we keep the delegates in place even though they are not needed // since otherwise Clojure (and maybe other languages) won't be able to // access these methods - see Clojure tickets 126 and 259 diff --git a/src/main/java/com/ning/http/client/RequestBuilderBase.java b/src/main/java/com/ning/http/client/RequestBuilderBase.java index 4c2a1a7008..f577b6ee6e 100644 --- a/src/main/java/com/ning/http/client/RequestBuilderBase.java +++ b/src/main/java/com/ning/http/client/RequestBuilderBase.java @@ -33,8 +33,7 @@ import com.ning.http.client.cookie.Cookie; import com.ning.http.client.uri.UriComponents; import com.ning.http.util.AsyncHttpProviderUtils; -import com.ning.http.util.UTF8UrlDecoder; -import com.ning.http.util.UTF8UrlEncoder; +import com.ning.http.util.QueryComputer; /** * Builder for {@link Request} @@ -257,22 +256,31 @@ public String toString() { private final Class derived; protected final RequestImpl request; - protected boolean disableUrlEncoding; + protected QueryComputer queryComputer; protected List queryParams; protected SignatureCalculator signatureCalculator; protected RequestBuilderBase(Class derived, String method, boolean disableUrlEncoding) { + this(derived, method, QueryComputer.queryComputer(disableUrlEncoding)); + } + + protected RequestBuilderBase(Class derived, String method, QueryComputer queryComputer) { this.derived = derived; request = new RequestImpl(); request.method = method; - this.disableUrlEncoding = disableUrlEncoding; + this.queryComputer = queryComputer; } protected RequestBuilderBase(Class derived, Request prototype) { + this(derived, prototype, QueryComputer.URL_ENCODING_ENABLED_QUERY_COMPUTER); + } + + protected RequestBuilderBase(Class derived, Request prototype, QueryComputer queryComputer) { this.derived = derived; request = new RequestImpl(prototype); + this.queryComputer = queryComputer; } - + public T setUrl(String url) { return setURI(UriComponents.create(url)); } @@ -591,112 +599,6 @@ private void computeRequestLength() { } } - private void appendRawQueryParams(StringBuilder sb, List queryParams) { - for (Param param : queryParams) - appendRawQueryParam(sb, param.getName(), param.getValue()); - } - - private void appendRawQueryParam(StringBuilder sb, String name, String value) { - sb.append(name); - if (value != null) - sb.append('=').append(value); - sb.append('&'); - } - - private void encodeAndAppendQueryParam(StringBuilder sb, String name, String value) { - UTF8UrlEncoder.appendEncoded(sb, name); - if (value != null) { - sb.append('='); - UTF8UrlEncoder.appendEncoded(sb, value); - } - sb.append('&'); - } - - private void encodeAndAppendQuery(StringBuilder sb, String query, boolean decode) { - int pos; - for (String queryParamString : query.split("&")) { - pos = queryParamString.indexOf('='); - if (pos <= 0) { - String decodedName = decode ? UTF8UrlDecoder.decode(queryParamString) : queryParamString; - encodeAndAppendQueryParam(sb, decodedName, null); - } else { - String name = queryParamString.substring(0, pos); - String decodedName = decode ? UTF8UrlDecoder.decode(name) : name; - String value = queryParamString.substring(pos + 1); - String decodedValue = decode ? UTF8UrlDecoder.decode(value) : value; - encodeAndAppendQueryParam(sb, decodedName, decodedValue); - } - } - } - - private boolean decodeRequired(String query) { - return query.indexOf('%') != -1 || query.indexOf('+') != -1; - } - - private void encodeAndAppendQuery(StringBuilder sb, String query) { - encodeAndAppendQuery(sb, query, decodeRequired(query)); - } - - private void encodeAndAppendQueryParams(StringBuilder sb, List queryParams) { - for (Param param : queryParams) - encodeAndAppendQueryParam(sb, param.getName(), param.getValue()); - } - - private String computeFinalQueryString(String query, List queryParams) { - - boolean hasQuery = isNonEmpty(query); - boolean hasQueryParams = isNonEmpty(queryParams); - - if (hasQuery) { - if (hasQueryParams) { - if (disableUrlEncoding) { - // concatenate raw query + raw query params - StringBuilder sb = new StringBuilder(query); - appendRawQueryParams(sb, queryParams); - sb.setLength(sb.length() - 1); - return sb.toString(); - } else { - // concatenate encoded query + encoded query params - StringBuilder sb = new StringBuilder(query.length() + 16); - encodeAndAppendQuery(sb, query); - encodeAndAppendQueryParams(sb, queryParams); - sb.setLength(sb.length() - 1); - return sb.toString(); - } - } else { - if (disableUrlEncoding) { - // return raw query as is - return query; - } else { - // encode query - StringBuilder sb = new StringBuilder(query.length() + 16); - encodeAndAppendQuery(sb, query); - sb.setLength(sb.length() - 1); - return sb.toString(); - } - } - } else { - if (hasQueryParams) { - if (disableUrlEncoding) { - // concatenate raw queryParams - StringBuilder sb = new StringBuilder(queryParams.size() * 16); - appendRawQueryParams(sb, queryParams); - sb.setLength(sb.length() - 1); - return sb.toString(); - } else { - // concatenate encoded query params - StringBuilder sb = new StringBuilder(queryParams.size() * 16); - encodeAndAppendQueryParams(sb, queryParams); - sb.setLength(sb.length() - 1); - return sb.toString(); - } - } else { - // neither query nor query param - return null; - } - } - } - private void computeFinalUri() { if (request.uri == null) { @@ -708,7 +610,7 @@ private void computeFinalUri() { // FIXME is that right? String newPath = isNonEmpty(request.uri.getPath()) ? request.uri.getPath() : "/"; - String newQuery = computeFinalQueryString(request.uri.getQuery(), queryParams); + String newQuery = queryComputer.computeFullQueryString(request.uri.getQuery(), queryParams); request.uri = new UriComponents(// request.uri.getScheme(),// diff --git a/src/main/java/com/ning/http/util/QueryComputer.java b/src/main/java/com/ning/http/util/QueryComputer.java new file mode 100644 index 0000000000..930e8515fb --- /dev/null +++ b/src/main/java/com/ning/http/util/QueryComputer.java @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2014 AsyncHttpClient Project. 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 static com.ning.http.util.MiscUtil.isNonEmpty; + +import com.ning.http.client.Param; + +import java.util.List; + +public enum QueryComputer { + + URL_ENCODING_ENABLED_QUERY_COMPUTER { + + protected String withQueryWithParams(final String query, final List queryParams) { + // concatenate encoded query + encoded query params + StringBuilder sb = new StringBuilder(query.length() + 16); + encodeAndAppendQuery(sb, query); + encodeAndAppendQueryParams(sb, queryParams); + sb.setLength(sb.length() - 1); + return sb.toString(); + } + + protected String withQueryWithoutParams(final String query) { + // encode query + StringBuilder sb = new StringBuilder(query.length() + 16); + encodeAndAppendQuery(sb, query); + sb.setLength(sb.length() - 1); + return sb.toString(); + } + + protected String withoutQueryWithParams(final List queryParams) { + // concatenate encoded query params + StringBuilder sb = new StringBuilder(queryParams.size() * 16); + encodeAndAppendQueryParams(sb, queryParams); + sb.setLength(sb.length() - 1); + return sb.toString(); + } + }, // + + URL_ENCODING_DISABLED_QUERY_COMPUTER { + + protected String withQueryWithParams(final String query, final List queryParams) { + // concatenate raw query + raw query params + StringBuilder sb = new StringBuilder(query); + appendRawQueryParams(sb, queryParams); + sb.setLength(sb.length() - 1); + return sb.toString(); + } + + protected String withQueryWithoutParams(final String query) { + // return raw query as is + return query; + } + + protected String withoutQueryWithParams(final List queryParams) { + // concatenate raw queryParams + StringBuilder sb = new StringBuilder(queryParams.size() * 16); + appendRawQueryParams(sb, queryParams); + sb.setLength(sb.length() - 1); + return sb.toString(); + } + }; + + public static QueryComputer queryComputer(boolean disableUrlEncoding) { + return disableUrlEncoding ? URL_ENCODING_DISABLED_QUERY_COMPUTER : URL_ENCODING_ENABLED_QUERY_COMPUTER; + } + + protected final void appendRawQueryParams(final StringBuilder sb, final List queryParams) { + for (Param param : queryParams) + appendRawQueryParam(sb, param.getName(), param.getValue()); + } + + private final void appendRawQueryParam(StringBuilder sb, String name, String value) { + sb.append(name); + if (value != null) + sb.append('=').append(value); + sb.append('&'); + } + + private void encodeAndAppendQueryParam(final StringBuilder sb, final String name, final String value) { + UTF8UrlEncoder.appendEncoded(sb, name); + if (value != null) { + sb.append('='); + UTF8UrlEncoder.appendEncoded(sb, value); + } + sb.append('&'); + } + + // FIXME it's probably possible to have only one pass instead of decoding then re-encoding + private final void encodeAndAppendQuery(final StringBuilder sb, final String query, final boolean decode) { + int pos; + for (String queryParamString : query.split("&")) { + pos = queryParamString.indexOf('='); + if (pos <= 0) { + String decodedName = decode ? UTF8UrlDecoder.decode(queryParamString) : queryParamString; + encodeAndAppendQueryParam(sb, decodedName, null); + } else { + String name = queryParamString.substring(0, pos); + String decodedName = decode ? UTF8UrlDecoder.decode(name) : name; + String value = queryParamString.substring(pos + 1); + String decodedValue = decode ? UTF8UrlDecoder.decode(value) : value; + encodeAndAppendQueryParam(sb, decodedName, decodedValue); + } + } + } + + private final boolean decodeRequired(final String query) { + return query.indexOf('%') != -1 || query.indexOf('+') != -1; + } + + protected final void encodeAndAppendQuery(final StringBuilder sb, final String query) { + encodeAndAppendQuery(sb, query, decodeRequired(query)); + } + + protected final void encodeAndAppendQueryParams(final StringBuilder sb, final List queryParams) { + for (Param param : queryParams) + encodeAndAppendQueryParam(sb, param.getName(), param.getValue()); + } + + protected abstract String withQueryWithParams(final String query, final List queryParams); + + protected abstract String withQueryWithoutParams(final String query); + + protected abstract String withoutQueryWithParams(final List queryParams); + + private final String withQuery(final String query, final List queryParams) { + return isNonEmpty(queryParams) ? withQueryWithParams(query, queryParams) : withQueryWithoutParams(query); + } + + private final String withoutQuery(final List queryParams) { + return isNonEmpty(queryParams) ? withoutQueryWithParams(queryParams) : null; + } + + public final String computeFullQueryString(final String query, final List queryParams) { + return isNonEmpty(query) ? withQuery(query, queryParams) : withoutQuery(queryParams); + } +} From 0d5861d5b8c7d370d8ee615d051f46762457e186 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 8 Jul 2014 15:17:30 +0200 Subject: [PATCH 360/701] Remove url from SignatureCalculator.calculateAndAddSignature, close #603 --- .../ning/http/client/RequestBuilderBase.java | 4 +- .../ning/http/client/SignatureCalculator.java | 7 ++-- .../oauth/OAuthSignatureCalculator.java | 38 ++++++++++--------- .../client/oauth/TestSignatureCalculator.java | 13 +++---- 4 files changed, 31 insertions(+), 31 deletions(-) diff --git a/src/main/java/com/ning/http/client/RequestBuilderBase.java b/src/main/java/com/ning/http/client/RequestBuilderBase.java index f577b6ee6e..e92f0acef5 100644 --- a/src/main/java/com/ning/http/client/RequestBuilderBase.java +++ b/src/main/java/com/ning/http/client/RequestBuilderBase.java @@ -560,9 +560,7 @@ private void executeSignatureCalculator() { * (order does not matter with current implementation but may in future) */ if (signatureCalculator != null) { - // Should not include query parameters, ensure: - String url = new UriComponents(request.uri.getScheme(), null, request.uri.getHost(), request.uri.getPort(), request.uri.getPath(), null).toString(); - signatureCalculator.calculateAndAddSignature(url, request, this); + signatureCalculator.calculateAndAddSignature(request, this); } } diff --git a/src/main/java/com/ning/http/client/SignatureCalculator.java b/src/main/java/com/ning/http/client/SignatureCalculator.java index 8826684658..49f1e43a4a 100644 --- a/src/main/java/com/ning/http/client/SignatureCalculator.java +++ b/src/main/java/com/ning/http/client/SignatureCalculator.java @@ -29,13 +29,12 @@ public interface SignatureCalculator { * (using passed {@link RequestBuilder}) to add signature (usually as * an HTTP header). * + * @param request Request that is being built; needed to access content to + * be signed * @param requestBuilder builder that can be used to modify request, usually * by adding header that includes calculated signature. Be sure NOT to * call {@link RequestBuilder#build} since this will cause infinite recursion - * @param request Request that is being built; needed to access content to - * be signed */ - void calculateAndAddSignature(String url, - Request request, + void calculateAndAddSignature(Request request, RequestBuilderBase requestBuilder); } 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 a400f588da..2468900296 100644 --- a/src/main/java/com/ning/http/client/oauth/OAuthSignatureCalculator.java +++ b/src/main/java/com/ning/http/client/oauth/OAuthSignatureCalculator.java @@ -16,10 +16,13 @@ */ package com.ning.http.client.oauth; +import static com.ning.http.util.MiscUtil.isNonEmpty; + import com.ning.http.client.Param; import com.ning.http.client.Request; import com.ning.http.client.RequestBuilderBase; import com.ning.http.client.SignatureCalculator; +import com.ning.http.client.uri.UriComponents; import com.ning.http.util.Base64; import com.ning.http.util.UTF8Codec; import com.ning.http.util.UTF8UrlEncoder; @@ -39,8 +42,7 @@ * * @author tatu (tatu.saloranta@iki.fi) */ -public class OAuthSignatureCalculator - implements SignatureCalculator { +public class OAuthSignatureCalculator implements SignatureCalculator { public final static String HEADER_AUTHORIZATION = "Authorization"; private static final String KEY_OAUTH_CONSUMER_KEY = "oauth_consumer_key"; @@ -81,11 +83,10 @@ public OAuthSignatureCalculator(ConsumerKey consumerAuth, RequestToken userAuth) //@Override // silly 1.5; doesn't allow this for interfaces - public void calculateAndAddSignature(String baseURL, Request request, RequestBuilderBase requestBuilder) { - String method = request.getMethod(); // POST etc + public void calculateAndAddSignature(Request request, RequestBuilderBase requestBuilder) { String nonce = generateNonce(); long timestamp = System.currentTimeMillis() / 1000L; - String signature = calculateSignature(method, baseURL, timestamp, nonce, request.getFormParams(), request.getQueryParams()); + String signature = calculateSignature(request.getMethod(), request.getURI(), timestamp, nonce, request.getFormParams(), request.getQueryParams()); String headerValue = constructAuthHeader(signature, nonce, timestamp); requestBuilder.setHeader(HEADER_AUTHORIZATION, headerValue); } @@ -93,7 +94,7 @@ public void calculateAndAddSignature(String baseURL, Request request, RequestBui /** * Method for calculating OAuth signature using HMAC/SHA-1 method. */ - public String calculateSignature(String method, String baseURL, long oauthTimestamp, String nonce, + public String calculateSignature(String method, UriComponents uri, long oauthTimestamp, String nonce, List formParams, List queryParams) { StringBuilder signedText = new StringBuilder(100); signedText.append(method); // POST / GET etc (nothing to URL encode) @@ -102,17 +103,20 @@ public String calculateSignature(String method, String baseURL, long oauthTimest /* 07-Oct-2010, tatu: URL may contain default port number; if so, need to extract * from base URL. */ - if (baseURL.startsWith("http:")) { - int i = baseURL.indexOf(":80/", 4); - if (i > 0) { - baseURL = baseURL.substring(0, i) + baseURL.substring(i + 3); - } - } else if (baseURL.startsWith("https:")) { - int i = baseURL.indexOf(":443/", 5); - if (i > 0) { - baseURL = baseURL.substring(0, i) + baseURL.substring(i + 4); - } - } + String scheme = uri.getScheme(); + int port = uri.getPort(); + if (scheme.equals("http") && port == 80) + port = -1; + else if (scheme.equals("https") && port == 443) + port = -1; + + StringBuilder sb = new StringBuilder().append(scheme).append("://").append(uri.getHost()); + if (port != -1) + sb.append(':').append(port); + if (isNonEmpty(uri.getPath())) + sb.append(uri.getPath()); + + String baseURL = sb.toString(); UTF8UrlEncoder.appendEncoded(signedText, baseURL); /** diff --git a/src/test/java/com/ning/http/client/oauth/TestSignatureCalculator.java b/src/test/java/com/ning/http/client/oauth/TestSignatureCalculator.java index b24b05a51f..08df681c96 100644 --- a/src/test/java/com/ning/http/client/oauth/TestSignatureCalculator.java +++ b/src/test/java/com/ning/http/client/oauth/TestSignatureCalculator.java @@ -19,12 +19,12 @@ import org.testng.annotations.Test; import com.ning.http.client.Param; +import com.ning.http.client.uri.UriComponents; import java.util.ArrayList; import java.util.List; -public class TestSignatureCalculator -{ +public class TestSignatureCalculator { private static final String CONSUMER_KEY = "dpf43f3p2l4k3l03"; private static final String CONSUMER_SECRET = "kd94hf93k423kf44"; @@ -36,12 +36,11 @@ public class TestSignatureCalculator public static final String NONCE = "kllo9940pd9333jh"; final static long TIMESTAMP = 1191242096; - + // based on the reference test case from // http://oauth.pbwiki.com/TestCases - @Test(groups="fast") - public void test() - { + @Test(groups = "fast") + public void test() { ConsumerKey consumer = new ConsumerKey(CONSUMER_KEY, CONSUMER_SECRET); RequestToken user = new RequestToken(TOKEN_KEY, TOKEN_SECRET); OAuthSignatureCalculator calc = new OAuthSignatureCalculator(consumer, user); @@ -49,7 +48,7 @@ public void test() queryParams.add(new Param("file", "vacation.jpg")); queryParams.add(new Param("size", "original")); String url = "http://photos.example.net/photos"; - String sig = calc.calculateSignature("GET", url, TIMESTAMP, NONCE, null, queryParams); + String sig = calc.calculateSignature("GET", UriComponents.create(url), TIMESTAMP, NONCE, null, queryParams); Assert.assertEquals("tR3+Ty81lMeYAr/Fid0kMTYa/WM=", sig); } From 2ec31faa5b6fae9e04be678236454d3faaa13a35 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 8 Jul 2014 15:36:25 +0200 Subject: [PATCH 361/701] minor clean up, see #603 --- .../http/client/oauth/OAuthSignatureCalculator.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) 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 2468900296..235aa544df 100644 --- a/src/main/java/com/ning/http/client/oauth/OAuthSignatureCalculator.java +++ b/src/main/java/com/ning/http/client/oauth/OAuthSignatureCalculator.java @@ -105,10 +105,12 @@ public String calculateSignature(String method, UriComponents uri, long oauthTim */ String scheme = uri.getScheme(); int port = uri.getPort(); - if (scheme.equals("http") && port == 80) - port = -1; - else if (scheme.equals("https") && port == 443) - port = -1; + if (scheme.equals("http")) + if (port == 80) + port = -1; + else if (scheme.equals("https")) + if (port == 443) + port = -1; StringBuilder sb = new StringBuilder().append(scheme).append("://").append(uri.getHost()); if (port != -1) From f05659a8b5939dadfa06d24e50f1ef2220a0c0da Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 8 Jul 2014 16:22:12 +0200 Subject: [PATCH 362/701] Support offset and length so that one doesn't have to substring, see #602 --- .../com/ning/http/util/UTF8UrlDecoder.java | 25 ++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/ning/http/util/UTF8UrlDecoder.java b/src/main/java/com/ning/http/util/UTF8UrlDecoder.java index 265e4c551d..1c7d91e493 100644 --- a/src/main/java/com/ning/http/util/UTF8UrlDecoder.java +++ b/src/main/java/com/ning/http/util/UTF8UrlDecoder.java @@ -17,8 +17,13 @@ public final class UTF8UrlDecoder { private UTF8UrlDecoder() { } - private static StringBuilder initSb(StringBuilder sb, int initialSbLength, String s, int i) { - return sb != null ? sb : new StringBuilder(initialSbLength).append(s, 0, i); + private static StringBuilder initSb(StringBuilder sb, String s, int i, int length) { + if (sb != null) { + return sb; + } else { + int initialSbLength = length > 500 ? length / 2 : length; + return new StringBuilder(initialSbLength).append(s, 0, i); + } } private static int hexaDigit(char c) { @@ -26,28 +31,30 @@ private static int hexaDigit(char c) { } public static String decode(String s) { + return decode(s, 0, s.length()); + } + + public static String decode(String s, int offset, int length) { - final int numChars = s.length(); - final int initialSbLength = numChars > 500 ? numChars / 2 : numChars; StringBuilder sb = null; - int i = 0; + int i = offset; - while (i < numChars) { + while (i < length) { char c = s.charAt(i); if (c == '+') { - sb = initSb(sb, initialSbLength, s, i); + sb = initSb(sb, s, i, length); sb.append(' '); i++; } else if (c == '%') { - if (numChars - i < 3) // We expect 3 chars. 0 based i vs. 1 based length! + if (length - i < 3) // We expect 3 chars. 0 based i vs. 1 based length! throw new IllegalArgumentException("UTF8UrlDecoder: Incomplete trailing escape (%) pattern"); int x, y; if ((x = hexaDigit(s.charAt(i + 1))) == -1 || (y = hexaDigit(s.charAt(i + 2))) == -1) throw new IllegalArgumentException("UTF8UrlDecoder: Malformed"); - sb = initSb(sb, initialSbLength, s, i); + sb = initSb(sb, s, i, length); sb.append((char) (x * 16 + y)); i += 3; } else { From 60a6d60c6e0b867001bc8640090a6d2b6072a290 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 8 Jul 2014 16:22:36 +0200 Subject: [PATCH 363/701] move actually private methods to proper place, see #602 --- .../com/ning/http/util/QueryComputer.java | 119 +++++++++--------- 1 file changed, 58 insertions(+), 61 deletions(-) diff --git a/src/main/java/com/ning/http/util/QueryComputer.java b/src/main/java/com/ning/http/util/QueryComputer.java index 930e8515fb..7f14f099df 100644 --- a/src/main/java/com/ning/http/util/QueryComputer.java +++ b/src/main/java/com/ning/http/util/QueryComputer.java @@ -22,24 +22,60 @@ public enum QueryComputer { URL_ENCODING_ENABLED_QUERY_COMPUTER { - protected String withQueryWithParams(final String query, final List queryParams) { + private final void encodeAndAppendQueryParam(final StringBuilder sb, final String name, final String value) { + UTF8UrlEncoder.appendEncoded(sb, name); + if (value != null) { + sb.append('='); + UTF8UrlEncoder.appendEncoded(sb, value); + } + sb.append('&'); + } + + private final void encodeAndAppendQueryParams(final StringBuilder sb, final List queryParams) { + for (Param param : queryParams) + encodeAndAppendQueryParam(sb, param.getName(), param.getValue()); + } + + private final boolean decodeRequired(final String query) { + return query.indexOf('%') != -1 || query.indexOf('+') != -1; + } + + // FIXME it's probably possible to have only one pass instead of decoding then re-encoding + private final void encodeAndAppendQuery(final StringBuilder sb, final String query) { + boolean decode = decodeRequired(query); + int pos; + for (String queryParamString : query.split("&")) { + pos = queryParamString.indexOf('='); + if (pos <= 0) { + String decodedName = decode ? UTF8UrlDecoder.decode(queryParamString) : queryParamString; + encodeAndAppendQueryParam(sb, decodedName, null); + } else { + String decodedName = decode ? UTF8UrlDecoder.decode(queryParamString, 0, pos) : queryParamString.substring(0, pos); + int valueStart = pos + 1; + String decodedValue = decode ? UTF8UrlDecoder.decode(queryParamString, valueStart, queryParamString.length() - valueStart) : queryParamString.substring(valueStart); + encodeAndAppendQueryParam(sb, decodedName, decodedValue); + } + } + } + + protected final String withQueryWithParams(final String query, final List queryParams) { // concatenate encoded query + encoded query params - StringBuilder sb = new StringBuilder(query.length() + 16); + StringBuilder sb = new StringBuilder(query.length() + queryParams.size() * 16); encodeAndAppendQuery(sb, query); encodeAndAppendQueryParams(sb, queryParams); sb.setLength(sb.length() - 1); return sb.toString(); } - protected String withQueryWithoutParams(final String query) { + protected final String withQueryWithoutParams(final String query) { // encode query - StringBuilder sb = new StringBuilder(query.length() + 16); + StringBuilder sb = new StringBuilder(query.length() + 6); encodeAndAppendQuery(sb, query); sb.setLength(sb.length() - 1); return sb.toString(); } - protected String withoutQueryWithParams(final List queryParams) { + protected final String withoutQueryWithParams(final List queryParams) { // concatenate encoded query params StringBuilder sb = new StringBuilder(queryParams.size() * 16); encodeAndAppendQueryParams(sb, queryParams); @@ -50,20 +86,33 @@ protected String withoutQueryWithParams(final List queryParams) { URL_ENCODING_DISABLED_QUERY_COMPUTER { - protected String withQueryWithParams(final String query, final List queryParams) { + private final void appendRawQueryParam(StringBuilder sb, String name, String value) { + sb.append(name); + if (value != null) + sb.append('=').append(value); + sb.append('&'); + } + + private final void appendRawQueryParams(final StringBuilder sb, final List queryParams) { + for (Param param : queryParams) + appendRawQueryParam(sb, param.getName(), param.getValue()); + } + + protected final String withQueryWithParams(final String query, final List queryParams) { // concatenate raw query + raw query params - StringBuilder sb = new StringBuilder(query); + StringBuilder sb = new StringBuilder(query.length() + queryParams.size() * 16); + sb.append(query); appendRawQueryParams(sb, queryParams); sb.setLength(sb.length() - 1); return sb.toString(); } - protected String withQueryWithoutParams(final String query) { + protected final String withQueryWithoutParams(final String query) { // return raw query as is return query; } - protected String withoutQueryWithParams(final List queryParams) { + protected final String withoutQueryWithParams(final List queryParams) { // concatenate raw queryParams StringBuilder sb = new StringBuilder(queryParams.size() * 16); appendRawQueryParams(sb, queryParams); @@ -76,58 +125,6 @@ public static QueryComputer queryComputer(boolean disableUrlEncoding) { return disableUrlEncoding ? URL_ENCODING_DISABLED_QUERY_COMPUTER : URL_ENCODING_ENABLED_QUERY_COMPUTER; } - protected final void appendRawQueryParams(final StringBuilder sb, final List queryParams) { - for (Param param : queryParams) - appendRawQueryParam(sb, param.getName(), param.getValue()); - } - - private final void appendRawQueryParam(StringBuilder sb, String name, String value) { - sb.append(name); - if (value != null) - sb.append('=').append(value); - sb.append('&'); - } - - private void encodeAndAppendQueryParam(final StringBuilder sb, final String name, final String value) { - UTF8UrlEncoder.appendEncoded(sb, name); - if (value != null) { - sb.append('='); - UTF8UrlEncoder.appendEncoded(sb, value); - } - sb.append('&'); - } - - // FIXME it's probably possible to have only one pass instead of decoding then re-encoding - private final void encodeAndAppendQuery(final StringBuilder sb, final String query, final boolean decode) { - int pos; - for (String queryParamString : query.split("&")) { - pos = queryParamString.indexOf('='); - if (pos <= 0) { - String decodedName = decode ? UTF8UrlDecoder.decode(queryParamString) : queryParamString; - encodeAndAppendQueryParam(sb, decodedName, null); - } else { - String name = queryParamString.substring(0, pos); - String decodedName = decode ? UTF8UrlDecoder.decode(name) : name; - String value = queryParamString.substring(pos + 1); - String decodedValue = decode ? UTF8UrlDecoder.decode(value) : value; - encodeAndAppendQueryParam(sb, decodedName, decodedValue); - } - } - } - - private final boolean decodeRequired(final String query) { - return query.indexOf('%') != -1 || query.indexOf('+') != -1; - } - - protected final void encodeAndAppendQuery(final StringBuilder sb, final String query) { - encodeAndAppendQuery(sb, query, decodeRequired(query)); - } - - protected final void encodeAndAppendQueryParams(final StringBuilder sb, final List queryParams) { - for (Param param : queryParams) - encodeAndAppendQueryParam(sb, param.getName(), param.getValue()); - } - protected abstract String withQueryWithParams(final String query, final List queryParams); protected abstract String withQueryWithoutParams(final String query); From c317fcda408977ff0277fd31ad19192bc0cb4e2a Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 8 Jul 2014 17:20:22 +0200 Subject: [PATCH 364/701] Less substrings, see #602 --- .../com/ning/http/util/QueryComputer.java | 15 ++---- .../ning/http/util/StringCharSequence.java | 54 +++++++++++++++++++ .../com/ning/http/util/UTF8UrlDecoder.java | 14 ++--- .../com/ning/http/util/UTF8UrlEncoder.java | 18 +++---- .../com/ning/http/util/UTF8UrlCodecTest.java | 14 ++--- 5 files changed, 81 insertions(+), 34 deletions(-) create mode 100644 src/main/java/com/ning/http/util/StringCharSequence.java diff --git a/src/main/java/com/ning/http/util/QueryComputer.java b/src/main/java/com/ning/http/util/QueryComputer.java index 7f14f099df..09b1d41c57 100644 --- a/src/main/java/com/ning/http/util/QueryComputer.java +++ b/src/main/java/com/ning/http/util/QueryComputer.java @@ -22,7 +22,7 @@ public enum QueryComputer { URL_ENCODING_ENABLED_QUERY_COMPUTER { - private final void encodeAndAppendQueryParam(final StringBuilder sb, final String name, final String value) { + private final void encodeAndAppendQueryParam(final StringBuilder sb, final CharSequence name, final CharSequence value) { UTF8UrlEncoder.appendEncoded(sb, name); if (value != null) { sb.append('='); @@ -36,23 +36,18 @@ private final void encodeAndAppendQueryParams(final StringBuilder sb, final List encodeAndAppendQueryParam(sb, param.getName(), param.getValue()); } - private final boolean decodeRequired(final String query) { - return query.indexOf('%') != -1 || query.indexOf('+') != -1; - } - - // FIXME it's probably possible to have only one pass instead of decoding then re-encoding + // FIXME this could be improved: remove split private final void encodeAndAppendQuery(final StringBuilder sb, final String query) { - boolean decode = decodeRequired(query); int pos; for (String queryParamString : query.split("&")) { pos = queryParamString.indexOf('='); if (pos <= 0) { - String decodedName = decode ? UTF8UrlDecoder.decode(queryParamString) : queryParamString; + CharSequence decodedName = UTF8UrlDecoder.decode(queryParamString); encodeAndAppendQueryParam(sb, decodedName, null); } else { - String decodedName = decode ? UTF8UrlDecoder.decode(queryParamString, 0, pos) : queryParamString.substring(0, pos); + CharSequence decodedName = UTF8UrlDecoder.decode(queryParamString, 0, pos); int valueStart = pos + 1; - String decodedValue = decode ? UTF8UrlDecoder.decode(queryParamString, valueStart, queryParamString.length() - valueStart) : queryParamString.substring(valueStart); + CharSequence decodedValue = UTF8UrlDecoder.decode(queryParamString, valueStart, queryParamString.length() - valueStart); encodeAndAppendQueryParam(sb, decodedName, decodedValue); } } diff --git a/src/main/java/com/ning/http/util/StringCharSequence.java b/src/main/java/com/ning/http/util/StringCharSequence.java new file mode 100644 index 0000000000..3ba4b29261 --- /dev/null +++ b/src/main/java/com/ning/http/util/StringCharSequence.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2014 AsyncHttpClient Project. 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; + +/** + * A CharSequence String wrapper that doesn't copy the char[] (damn new String implementation!!!) + * + * @author slandelle + */ +public class StringCharSequence implements CharSequence { + + private final String value; + private final int offset; + public final int length; + + public StringCharSequence(String value, int offset, int length) { + this.value = value; + this.offset = offset; + this.length = length; + } + + @Override + public int length() { + return length; + } + + @Override + public char charAt(int index) { + return value.charAt(offset + index); + } + + @Override + public CharSequence subSequence(int start, int end) { + int offsetedEnd = offset + end; + if (offsetedEnd < length) + throw new ArrayIndexOutOfBoundsException(); + return new StringCharSequence(value, offset + start, end - start); + } + + @Override + public String toString() { + return value.substring(offset, length); + } +} diff --git a/src/main/java/com/ning/http/util/UTF8UrlDecoder.java b/src/main/java/com/ning/http/util/UTF8UrlDecoder.java index 1c7d91e493..345c216b00 100644 --- a/src/main/java/com/ning/http/util/UTF8UrlDecoder.java +++ b/src/main/java/com/ning/http/util/UTF8UrlDecoder.java @@ -17,12 +17,12 @@ public final class UTF8UrlDecoder { private UTF8UrlDecoder() { } - private static StringBuilder initSb(StringBuilder sb, String s, int i, int length) { + private static StringBuilder initSb(StringBuilder sb, String s, int i, int offset, int length) { if (sb != null) { return sb; } else { int initialSbLength = length > 500 ? length / 2 : length; - return new StringBuilder(initialSbLength).append(s, 0, i); + return new StringBuilder(initialSbLength).append(s, offset, i); } } @@ -30,11 +30,11 @@ private static int hexaDigit(char c) { return Character.digit(c, 16); } - public static String decode(String s) { + public static CharSequence decode(String s) { return decode(s, 0, s.length()); } - public static String decode(String s, int offset, int length) { + public static CharSequence decode(final String s, final int offset, final int length) { StringBuilder sb = null; int i = offset; @@ -42,7 +42,7 @@ public static String decode(String s, int offset, int length) { while (i < length) { char c = s.charAt(i); if (c == '+') { - sb = initSb(sb, s, i, length); + sb = initSb(sb, s, i, offset, length); sb.append(' '); i++; @@ -54,7 +54,7 @@ public static String decode(String s, int offset, int length) { if ((x = hexaDigit(s.charAt(i + 1))) == -1 || (y = hexaDigit(s.charAt(i + 2))) == -1) throw new IllegalArgumentException("UTF8UrlDecoder: Malformed"); - sb = initSb(sb, s, i, length); + sb = initSb(sb, s, i, offset, length); sb.append((char) (x * 16 + y)); i += 3; } else { @@ -64,6 +64,6 @@ public static String decode(String s, int offset, int length) { } } - return sb != null ? sb.toString() : s; + return sb != null ? sb.toString() : new StringCharSequence(s, offset, length); } } diff --git a/src/main/java/com/ning/http/util/UTF8UrlEncoder.java b/src/main/java/com/ning/http/util/UTF8UrlEncoder.java index 758849b6f6..f76cf15495 100644 --- a/src/main/java/com/ning/http/util/UTF8UrlEncoder.java +++ b/src/main/java/com/ning/http/util/UTF8UrlEncoder.java @@ -56,19 +56,17 @@ public static String encode(String input) { return sb.toString(); } - public static StringBuilder appendEncoded(StringBuilder sb, String input) { - - for (int c, i = 0, len = input.length(); i < len; i+= Character.charCount(c)) { - c = input.codePointAt(i); - if (c <= 127) { - if (SAFE_ASCII[c]) { + public static StringBuilder appendEncoded(StringBuilder sb, CharSequence input) { + int c; + for (int i = 0; i < input.length(); i+= Character.charCount(c)) { + c = Character.codePointAt(input, i); + if (c <= 127) + if (SAFE_ASCII[c]) sb.append((char) c); - } else { + else appendSingleByteEncoded(sb, c); - } - } else { + else appendMultiByteEncoded(sb, c); - } } return sb; } diff --git a/src/test/java/com/ning/http/util/UTF8UrlCodecTest.java b/src/test/java/com/ning/http/util/UTF8UrlCodecTest.java index 2811eeadb9..d4b5765368 100644 --- a/src/test/java/com/ning/http/util/UTF8UrlCodecTest.java +++ b/src/test/java/com/ning/http/util/UTF8UrlCodecTest.java @@ -39,15 +39,15 @@ public void testNonBmp() { @Test(groups = "fast") public void testDecodeBasics() { - Assert.assertEquals(UTF8UrlDecoder.decode("foobar"), "foobar"); - Assert.assertEquals(UTF8UrlDecoder.decode("a&b"), "a&b"); - Assert.assertEquals(UTF8UrlDecoder.decode("a+b"), "a b"); + Assert.assertEquals(UTF8UrlDecoder.decode("foobar").toString(), "foobar"); + Assert.assertEquals(UTF8UrlDecoder.decode("a&b").toString(), "a&b"); + Assert.assertEquals(UTF8UrlDecoder.decode("a+b").toString(), "a b"); - Assert.assertEquals(UTF8UrlDecoder.decode("+"), " "); - Assert.assertEquals(UTF8UrlDecoder.decode("%20"), " "); - Assert.assertEquals(UTF8UrlDecoder.decode("%25"), "%"); + Assert.assertEquals(UTF8UrlDecoder.decode("+").toString(), " "); + Assert.assertEquals(UTF8UrlDecoder.decode("%20").toString(), " "); + Assert.assertEquals(UTF8UrlDecoder.decode("%25").toString(), "%"); - Assert.assertEquals(UTF8UrlDecoder.decode("+%20x"), " x"); + Assert.assertEquals(UTF8UrlDecoder.decode("+%20x").toString(), " x"); } @Test(groups = "fast") From 187fc970760fe2e41e6070591b8c1ce65464f91e Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 8 Jul 2014 23:07:28 +0200 Subject: [PATCH 365/701] woups --- src/main/java/com/ning/http/util/UTF8UrlDecoder.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/ning/http/util/UTF8UrlDecoder.java b/src/main/java/com/ning/http/util/UTF8UrlDecoder.java index 345c216b00..50b2474742 100644 --- a/src/main/java/com/ning/http/util/UTF8UrlDecoder.java +++ b/src/main/java/com/ning/http/util/UTF8UrlDecoder.java @@ -38,8 +38,9 @@ public static CharSequence decode(final String s, final int offset, final int le StringBuilder sb = null; int i = offset; + int end = length + offset; - while (i < length) { + while (i < end) { char c = s.charAt(i); if (c == '+') { sb = initSb(sb, s, i, offset, length); @@ -47,7 +48,7 @@ public static CharSequence decode(final String s, final int offset, final int le i++; } else if (c == '%') { - if (length - i < 3) // We expect 3 chars. 0 based i vs. 1 based length! + if (end - i < 3) // We expect 3 chars. 0 based i vs. 1 based length! throw new IllegalArgumentException("UTF8UrlDecoder: Incomplete trailing escape (%) pattern"); int x, y; From b2abd835dae33ac95b0a3e4a615489cf890304b2 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 9 Jul 2014 00:43:07 +0200 Subject: [PATCH 366/701] Use followRedirect everywhere, close #604 --- .../http/client/AsyncHttpClientConfig.java | 18 +++++++++--------- .../http/client/AsyncHttpClientConfigBean.java | 6 +++--- .../client/AsyncHttpClientConfigDefaults.java | 4 ++-- .../apache/ApacheAsyncHttpProvider.java | 3 +-- .../grizzly/GrizzlyAsyncHttpProvider.java | 2 +- .../providers/jdk/JDKAsyncHttpProvider.java | 3 +-- .../netty/NettyAsyncHttpProvider.java | 2 +- .../ning/http/util/AsyncHttpProviderUtils.java | 4 ++-- .../client/async/AsyncProvidersBasicTest.java | 2 +- .../client/async/AsyncStreamHandlerTest.java | 2 +- .../ning/http/client/async/BasicAuthTest.java | 2 +- .../ning/http/client/async/ChunkingTest.java | 2 +- .../http/client/async/FollowingThreadTest.java | 2 +- .../client/async/HttpToHttpsRedirectTest.java | 6 +++--- .../http/client/async/MultipartUploadTest.java | 2 +- .../http/client/async/NoNullResponseTest.java | 2 +- .../async/PerRequestRelative302Test.java | 2 +- .../http/client/async/PostRedirectGetTest.java | 4 ++-- .../http/client/async/ProxyTunnellingTest.java | 4 ++-- .../async/RedirectConnectionUsageTest.java | 2 +- .../http/client/async/Relative302Test.java | 8 ++++---- .../ning/http/client/async/RemoteSiteTest.java | 10 +++++----- .../grizzly/GrizzlyNoTransferEncodingTest.java | 2 +- .../http/client/websocket/RedirectTest.java | 2 +- 24 files changed, 47 insertions(+), 49 deletions(-) diff --git a/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java b/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java index cd439de7b9..610ef65c0e 100644 --- a/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java @@ -60,7 +60,7 @@ public class AsyncHttpClientConfig { protected int idleConnectionInPoolTimeoutInMs; protected int idleConnectionTimeoutInMs; protected int requestTimeoutInMs; - protected boolean redirectEnabled; + protected boolean followRedirect; protected int maxRedirects; protected boolean compressionEnabled; protected String userAgent; @@ -131,7 +131,7 @@ private AsyncHttpClientConfig(int maxTotalConnections, this.idleConnectionTimeoutInMs = idleConnectionTimeoutInMs; this.requestTimeoutInMs = requestTimeoutInMs; this.maxConnectionLifeTimeInMs = connectionMaxLifeTimeInMs; - this.redirectEnabled = redirectEnabled; + this.followRedirect = followRedirect; this.maxRedirects = maxRedirects; this.compressionEnabled = compressionEnabled; this.userAgent = userAgent; @@ -232,8 +232,8 @@ public int getRequestTimeoutInMs() { * * @return true if enabled. */ - public boolean isRedirectEnabled() { - return redirectEnabled; + public boolean isFollowRedirect() { + return followRedirect; } /** @@ -531,7 +531,7 @@ public static class Builder { private int idleConnectionTimeoutInMs = defaultIdleConnectionTimeoutInMs(); private int requestTimeoutInMs = defaultRequestTimeoutInMs(); private int maxConnectionLifeTimeInMs = defaultMaxConnectionLifeTimeInMs(); - private boolean redirectEnabled = defaultRedirectEnabled(); + private boolean followRedirect = defaultFollowRedirect(); private int maxDefaultRedirects = defaultMaxRedirects(); private boolean compressionEnabled = defaultCompressionEnabled(); private String userAgent = defaultUserAgent(); @@ -651,8 +651,8 @@ public Builder setRequestTimeoutInMs(int requestTimeoutInMs) { * @param redirectEnabled true if enabled. * @return a {@link Builder} */ - public Builder setFollowRedirects(boolean redirectEnabled) { - this.redirectEnabled = redirectEnabled; + public Builder setFollowRedirect(boolean followRedirect) { + this.followRedirect = followRedirect; return this; } @@ -1054,7 +1054,7 @@ public Builder(AsyncHttpClientConfig prototype) { sslContext = prototype.getSSLContext(); sslEngineFactory = prototype.getSSLEngineFactory(); userAgent = prototype.getUserAgent(); - redirectEnabled = prototype.isRedirectEnabled(); + followRedirect = prototype.isFollowRedirect(); compressionEnabled = prototype.isCompressionEnabled(); applicationThreadPool = prototype.executorService(); @@ -1115,7 +1115,7 @@ public Thread newThread(Runnable r) { idleConnectionTimeoutInMs, requestTimeoutInMs, maxConnectionLifeTimeInMs, - redirectEnabled, + followRedirect, maxDefaultRedirects, compressionEnabled, userAgent, diff --git a/src/main/java/com/ning/http/client/AsyncHttpClientConfigBean.java b/src/main/java/com/ning/http/client/AsyncHttpClientConfigBean.java index 7a5b7e1688..1a2618decb 100644 --- a/src/main/java/com/ning/http/client/AsyncHttpClientConfigBean.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClientConfigBean.java @@ -53,7 +53,7 @@ void configureDefaults() { idleConnectionTimeoutInMs = defaultIdleConnectionTimeoutInMs(); requestTimeoutInMs = defaultRequestTimeoutInMs(); maxConnectionLifeTimeInMs = defaultMaxConnectionLifeTimeInMs(); - redirectEnabled = defaultRedirectEnabled(); + followRedirect = defaultFollowRedirect(); maxRedirects = defaultMaxRedirects(); compressionEnabled = defaultCompressionEnabled(); userAgent = defaultUserAgent(); @@ -125,8 +125,8 @@ public AsyncHttpClientConfigBean setMaxConnectionLifeTimeInMs(int maxConnectionL return this; } - public AsyncHttpClientConfigBean setRedirectEnabled(boolean redirectEnabled) { - this.redirectEnabled = redirectEnabled; + public AsyncHttpClientConfigBean setFollowRedirect(boolean followRedirect) { + this.followRedirect = followRedirect; return this; } diff --git a/src/main/java/com/ning/http/client/AsyncHttpClientConfigDefaults.java b/src/main/java/com/ning/http/client/AsyncHttpClientConfigDefaults.java index f565a3e7de..e1437a29ed 100644 --- a/src/main/java/com/ning/http/client/AsyncHttpClientConfigDefaults.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClientConfigDefaults.java @@ -56,8 +56,8 @@ public static int defaultMaxConnectionLifeTimeInMs() { return Integer.getInteger(ASYNC_CLIENT + "maxConnectionLifeTimeInMs", -1); } - public static boolean defaultRedirectEnabled() { - return Boolean.getBoolean(ASYNC_CLIENT + "redirectsEnabled"); + public static boolean defaultFollowRedirect() { + return Boolean.getBoolean(ASYNC_CLIENT + "followRedirect"); } public static int defaultMaxRedirects() { 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 92a521c777..2b431bc662 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 @@ -502,8 +502,7 @@ public T call() { logger.debug("\n\nRequest {}\n\nResponse {}\n", request, method); - boolean redirectEnabled = AsyncHttpProviderUtils.redirectEnabled(config, request); - if (redirectEnabled && (statusCode == 302 || statusCode == 301)) { + if (AsyncHttpProviderUtils.followRedirect(config, request) && (statusCode == 302 || statusCode == 301)) { isAuth.set(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 39d855a30c..c0df47f795 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 @@ -661,7 +661,7 @@ static HttpTransactionContext get(final Connection c) { this.future = future; this.request = request; this.handler = handler; - redirectsAllowed = provider.clientConfig.isRedirectEnabled(); + redirectsAllowed = provider.clientConfig.isFollowRedirect(); maxRedirectCount = provider.clientConfig.getMaxRedirects(); this.requestUrl = request.getUrl(); 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 c5fd3d9dc9..f000c92c67 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 @@ -261,8 +261,7 @@ public T call() throws Exception { return call(); } - boolean redirectEnabled = AsyncHttpProviderUtils.redirectEnabled(config, request); - if (redirectEnabled && (statusCode == 302 || statusCode == 301)) { + if (AsyncHttpProviderUtils.followRedirect(config, request) && (statusCode == 302 || statusCode == 301)) { if (currentRedirectCount++ < config.getMaxRedirects()) { String location = urlConnection.getHeaderField("Location"); 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 b78956a2b6..cacc84dff7 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 @@ -1931,7 +1931,7 @@ private static final boolean validateWebSocketRequest(Request request, AsyncHand private boolean redirect(Request request, NettyResponseFuture future, HttpResponse response, final ChannelHandlerContext ctx) throws Exception { int statusCode = response.getStatus().getCode(); - if (AsyncHttpProviderUtils.redirectEnabled(config, request) && (statusCode == 302 || statusCode == 301 || statusCode == 303 || statusCode == 307)) { + if (AsyncHttpProviderUtils.followRedirect(config, request) && (statusCode == 302 || statusCode == 301 || statusCode == 303 || statusCode == 307)) { if (future.incrementAndGetCurrentRedirectCount() < config.getMaxRedirects()) { // We must allow 401 handling again. diff --git a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java index b50a97655a..3eefea514b 100644 --- a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java +++ b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java @@ -230,8 +230,8 @@ public static int requestTimeout(AsyncHttpClientConfig config, Request request) return request.getRequestTimeoutInMs() != 0 ? request.getRequestTimeoutInMs() : config.getRequestTimeoutInMs(); } - public static boolean redirectEnabled(AsyncHttpClientConfig config, Request request) { - return request.getFollowRedirect() != null? request.getFollowRedirect().booleanValue() : config.isRedirectEnabled(); + public static boolean followRedirect(AsyncHttpClientConfig config, Request request) { + return request.getFollowRedirect() != null? request.getFollowRedirect().booleanValue() : config.isFollowRedirect(); } public static String formParams2UTF8String(List params) { 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 af4f11179b..28b0a77fde 100755 --- a/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java +++ b/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java @@ -1436,7 +1436,7 @@ public Response onCompleted(Response response) throws Exception { @Test(groups = { "online", "default_provider", "async" }) public void asyncDoGetMaxRedirectTest() throws Throwable { - AsyncHttpClient client = getAsyncHttpClient(new Builder().setMaximumNumberOfRedirects(0).setFollowRedirects(true).build()); + AsyncHttpClient client = getAsyncHttpClient(new Builder().setMaximumNumberOfRedirects(0).setFollowRedirect(true).build()); try { // Use a l in case the assert fail final CountDownLatch l = new CountDownLatch(1); 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 12973ca191..17d93e1252 100644 --- a/src/test/java/com/ning/http/client/async/AsyncStreamHandlerTest.java +++ b/src/test/java/com/ning/http/client/async/AsyncStreamHandlerTest.java @@ -373,7 +373,7 @@ public String onCompleted() throws Exception { @Test(groups = { "online", "default_provider" }) public void asyncStream302RedirectWithBody() throws Exception { - AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setFollowRedirects(true).build()); + AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setFollowRedirect(true).build()); final AtomicReference statusCode = new AtomicReference(0); final AtomicReference responseHeaders = new AtomicReference(); try { 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 b9ea90cb09..0ff695ca41 100644 --- a/src/test/java/com/ning/http/client/async/BasicAuthTest.java +++ b/src/test/java/com/ning/http/client/async/BasicAuthTest.java @@ -301,7 +301,7 @@ public void redirectAndBasicAuthTest() throws Exception, ExecutionException, Tim AsyncHttpClient client = null; try { setUpSecondServer(); - client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setFollowRedirects(true).setMaximumNumberOfRedirects(10).build()); + client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setFollowRedirect(true).setMaximumNumberOfRedirects(10).build()); AsyncHttpClient.BoundRequestBuilder r = client.prepareGet(getTargetUrl2()) // .setHeader( "X-302", "/bla" ) .setRealm((new Realm.RealmBuilder()).setPrincipal(user).setPassword(admin).build()); 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 9d4288e9ca..db355edaff 100644 --- a/src/test/java/com/ning/http/client/async/ChunkingTest.java +++ b/src/test/java/com/ning/http/client/async/ChunkingTest.java @@ -83,7 +83,7 @@ private void doTest(boolean customChunkedInputStream) throws Exception { bc.setMaximumConnectionsTotal(1); bc.setConnectionTimeoutInMs(1000); bc.setRequestTimeoutInMs(1000); - bc.setFollowRedirects(true); + bc.setFollowRedirect(true); c = getAsyncHttpClient(bc.build()); 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 82d6c6d95e..ff16c5e909 100644 --- a/src/test/java/com/ning/http/client/async/FollowingThreadTest.java +++ b/src/test/java/com/ning/http/client/async/FollowingThreadTest.java @@ -50,7 +50,7 @@ public void testFollowRedirect() throws IOException, ExecutionException, Timeout public void run() { final CountDownLatch l = new CountDownLatch(1); - final AsyncHttpClient ahc = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setFollowRedirects(true).build()); + final AsyncHttpClient ahc = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setFollowRedirect(true).build()); try { ahc.prepareGet("http://www.google.com/").execute(new AsyncHandler() { 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 b12b08ad84..8305e4fd15 100644 --- a/src/test/java/com/ning/http/client/async/HttpToHttpsRedirectTest.java +++ b/src/test/java/com/ning/http/client/async/HttpToHttpsRedirectTest.java @@ -120,7 +120,7 @@ public void setUpGlobal() throws Exception { public void httpToHttpsRedirect() throws Throwable { isSet.getAndSet(false); - AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setMaximumNumberOfRedirects(5).setFollowRedirects(true).build(); + AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setMaximumNumberOfRedirects(5).setFollowRedirect(true).build(); AsyncHttpClient c = getAsyncHttpClient(cg); Response response = c.prepareGet(getTargetUrl()).setHeader("X-redirect", getTargetUrl2()).execute().get(); @@ -138,7 +138,7 @@ public String getTargetUrl2() { public void httpToHttpsProperConfig() throws Throwable { isSet.getAndSet(false); - AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setMaximumNumberOfRedirects(5).setFollowRedirects(true).build(); + AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setMaximumNumberOfRedirects(5).setFollowRedirect(true).build(); AsyncHttpClient c = getAsyncHttpClient(cg); try { Response response = c.prepareGet(getTargetUrl()).setHeader("X-redirect", getTargetUrl2() + "/test2").execute().get(); @@ -160,7 +160,7 @@ public void httpToHttpsProperConfig() throws Throwable { public void relativeLocationUrl() throws Throwable { isSet.getAndSet(false); - AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setMaximumNumberOfRedirects(5).setFollowRedirects(true).build(); + AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setMaximumNumberOfRedirects(5).setFollowRedirect(true).build(); AsyncHttpClient c = getAsyncHttpClient(cg); try { Response response = c.prepareGet(getTargetUrl()).setHeader("X-redirect", "/foo/test").execute().get(); 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 991983e8ca..9dc51102c5 100644 --- a/src/test/java/com/ning/http/client/async/MultipartUploadTest.java +++ b/src/test/java/com/ning/http/client/async/MultipartUploadTest.java @@ -209,7 +209,7 @@ public void testSendingSmallFilesAndByteArray() { AsyncHttpClientConfig.Builder bc = new AsyncHttpClientConfig.Builder(); - bc.setFollowRedirects(true); + bc.setFollowRedirect(true); AsyncHttpClient c = new AsyncHttpClient(bc.build()); 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 21edc3529a..8521542b54 100644 --- a/src/test/java/com/ning/http/client/async/NoNullResponseTest.java +++ b/src/test/java/com/ning/http/client/async/NoNullResponseTest.java @@ -54,7 +54,7 @@ public void multipleSslRequestsWithDelayAndKeepAlive() throws Throwable { } private AsyncHttpClient create() throws GeneralSecurityException { - final AsyncHttpClientConfig.Builder configBuilder = new AsyncHttpClientConfig.Builder().setCompressionEnabled(true).setFollowRedirects(true).setSSLContext(getSSLContext()).setAllowPoolingConnection(true).setConnectionTimeoutInMs(10000) + final AsyncHttpClientConfig.Builder configBuilder = new AsyncHttpClientConfig.Builder().setCompressionEnabled(true).setFollowRedirect(true).setSSLContext(getSSLContext()).setAllowPoolingConnection(true).setConnectionTimeoutInMs(10000) .setIdleConnectionInPoolTimeoutInMs(60000).setRequestTimeoutInMs(10000).setMaximumConnectionsPerHost(-1).setMaximumConnectionsTotal(-1); return getAsyncHttpClient(configBuilder.build()); } 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 16d5a3c907..6beb81d8f5 100644 --- a/src/test/java/com/ning/http/client/async/PerRequestRelative302Test.java +++ b/src/test/java/com/ning/http/client/async/PerRequestRelative302Test.java @@ -111,7 +111,7 @@ public void redirected302Test() throws Throwable { @Test(groups = { "online", "default_provider" }) public void notRedirected302Test() throws Throwable { isSet.getAndSet(false); - AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setFollowRedirects(true).build(); + AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setFollowRedirect(true).build(); AsyncHttpClient c = getAsyncHttpClient(cg); try { // once 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 d5c6889aa2..017b63b7a9 100644 --- a/src/test/java/com/ning/http/client/async/PostRedirectGetTest.java +++ b/src/test/java/com/ning/http/client/async/PostRedirectGetTest.java @@ -72,7 +72,7 @@ public void postRedirectGet307Test() throws Exception { // --------------------------------------------------------- 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() { + AsyncHttpClient p = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setFollowRedirect(true).setStrict302Handling(strict).addResponseFilter(new ResponseFilter() { public FilterContext filter(FilterContext ctx) throws FilterException { // pass on the x-expect-get and remove the x-redirect // headers if found in the response @@ -106,7 +106,7 @@ public void onThrowable(Throwable t) { } private void doTestPositive(final int status) throws Exception { - AsyncHttpClient p = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setFollowRedirects(true).addResponseFilter(new ResponseFilter() { + AsyncHttpClient p = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setFollowRedirect(true).addResponseFilter(new ResponseFilter() { public FilterContext filter(FilterContext ctx) throws FilterException { // pass on the x-expect-get and remove the x-redirect // headers if found in the response diff --git a/src/test/java/com/ning/http/client/async/ProxyTunnellingTest.java b/src/test/java/com/ning/http/client/async/ProxyTunnellingTest.java index e2c2c134cf..588532b4a3 100644 --- a/src/test/java/com/ning/http/client/async/ProxyTunnellingTest.java +++ b/src/test/java/com/ning/http/client/async/ProxyTunnellingTest.java @@ -91,7 +91,7 @@ public void setUpGlobal() throws Exception { @Test(groups = { "online", "default_provider" }) public void testRequestProxy() throws IOException, InterruptedException, ExecutionException, TimeoutException { AsyncHttpClientConfig.Builder b = new AsyncHttpClientConfig.Builder(); - b.setFollowRedirects(true); + b.setFollowRedirect(true); ProxyServer ps = new ProxyServer(ProxyServer.Protocol.HTTPS, "127.0.0.1", port1); @@ -123,7 +123,7 @@ public Response onCompleted(Response response) throws Exception { @Test(groups = { "online", "default_provider" }) public void testConfigProxy() throws IOException, InterruptedException, ExecutionException, TimeoutException { AsyncHttpClientConfig.Builder b = new AsyncHttpClientConfig.Builder(); - b.setFollowRedirects(true); + b.setFollowRedirect(true); ProxyServer ps = new ProxyServer(ProxyServer.Protocol.HTTPS, "127.0.0.1", port1); b.setProxyServer(ps); 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 e8b6387164..8bac8c82b5 100644 --- a/src/test/java/com/ning/http/client/async/RedirectConnectionUsageTest.java +++ b/src/test/java/com/ning/http/client/async/RedirectConnectionUsageTest.java @@ -113,7 +113,7 @@ public void testGetRedirectFinalUrl() { bc.setMaximumConnectionsTotal(1); bc.setConnectionTimeoutInMs(1000); bc.setRequestTimeoutInMs(1000); - bc.setFollowRedirects(true); + bc.setFollowRedirect(true); c = getAsyncHttpClient(bc.build()); 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 578585c9ad..cb21a880fb 100644 --- a/src/test/java/com/ning/http/client/async/Relative302Test.java +++ b/src/test/java/com/ning/http/client/async/Relative302Test.java @@ -91,7 +91,7 @@ public void setUpGlobal() throws Exception { @Test(groups = { "online", "default_provider" }) public void redirected302Test() throws Throwable { isSet.getAndSet(false); - AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setFollowRedirects(true).build(); + AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setFollowRedirect(true).build(); AsyncHttpClient c = getAsyncHttpClient(cg); try { // once @@ -128,7 +128,7 @@ private static int getPort(UriComponents uri) { @Test(groups = { "standalone", "default_provider" }) public void redirected302InvalidTest() throws Throwable { isSet.getAndSet(false); - AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setFollowRedirects(true).build(); + AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setFollowRedirect(true).build(); AsyncHttpClient c = getAsyncHttpClient(cg); // If the test hit a proxy, no ConnectException will be thrown and instead of 404 will be returned. @@ -148,7 +148,7 @@ public void redirected302InvalidTest() throws Throwable { public void absolutePathRedirectTest() throws Throwable { isSet.getAndSet(false); - AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setFollowRedirects(true).build(); + AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setFollowRedirect(true).build(); AsyncHttpClient c = getAsyncHttpClient(cg); try { String redirectTarget = "/bar/test"; @@ -169,7 +169,7 @@ public void absolutePathRedirectTest() throws Throwable { public void relativePathRedirectTest() throws Throwable { isSet.getAndSet(false); - AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setFollowRedirects(true).build(); + AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setFollowRedirect(true).build(); AsyncHttpClient c = getAsyncHttpClient(cg); try { String redirectTarget = "bar/test1"; 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 50f83a4a68..7505655372 100644 --- a/src/test/java/com/ning/http/client/async/RemoteSiteTest.java +++ b/src/test/java/com/ning/http/client/async/RemoteSiteTest.java @@ -124,7 +124,7 @@ public void testGoogleComWithTimeout() throws Throwable { @Test(groups = { "online", "default_provider" }) public void asyncStatusHEADContentLenghtTest() throws Throwable { - AsyncHttpClient p = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setFollowRedirects(true).build()); + AsyncHttpClient p = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setFollowRedirect(true).build()); try { final CountDownLatch l = new CountDownLatch(1); Request request = new RequestBuilder("HEAD").setUrl("http://www.google.com/").build(); @@ -148,7 +148,7 @@ public Response onCompleted(Response response) throws Exception { @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).setFollowRedirect(true).setAllowPoolingConnection(false).setMaximumNumberOfRedirects(6).build(); AsyncHttpClient c = getAsyncHttpClient(config); try { @@ -215,7 +215,7 @@ public void testAHC60() throws Throwable { @Test(groups = { "online", "default_provider" }) public void stripQueryStringTest() throws Throwable { - AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setFollowRedirects(true).build(); + AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setFollowRedirect(true).build(); AsyncHttpClient c = getAsyncHttpClient(cg); Response response = c.prepareGet("http://www.freakonomics.com/?p=55846").execute().get(); @@ -229,7 +229,7 @@ public void stripQueryStringTest() throws Throwable { @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).setFollowRedirect(true).build(); AsyncHttpClient c = getAsyncHttpClient(cg); try { Response response = c.prepareGet("http://www.freakonomics.com/?p=55846").execute().get(); @@ -262,7 +262,7 @@ public void evilCoookieTest() throws Throwable { @Test(groups = { "online", "default_provider" }, enabled = false) public void testAHC62Com() throws Throwable { - AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setFollowRedirects(true).build()); + AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setFollowRedirect(true).build()); try { Response response = c.prepareGet("http://api.crunchbase.com/v/1/financial-organization/kinsey-hills-group.js").execute(new AsyncHandler() { diff --git a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyNoTransferEncodingTest.java b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyNoTransferEncodingTest.java index 58ad23a799..6b0aa334a3 100644 --- a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyNoTransferEncodingTest.java +++ b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyNoTransferEncodingTest.java @@ -86,7 +86,7 @@ public void testNoTransferEncoding() throws Exception { AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder() .setCompressionEnabled(true) - .setFollowRedirects(false) + .setFollowRedirect(false) .setConnectionTimeoutInMs(15000) .setRequestTimeoutInMs(15000) .setAllowPoolingConnection(false) 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 215cfce306..d02549c251 100644 --- a/src/test/java/com/ning/http/client/websocket/RedirectTest.java +++ b/src/test/java/com/ning/http/client/websocket/RedirectTest.java @@ -84,7 +84,7 @@ 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()); + AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setFollowRedirect(true).build()); try { final CountDownLatch latch = new CountDownLatch(1); final AtomicReference text = new AtomicReference(""); From c0199490d0d700d4e5f27fdaf523155757579f1b Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 9 Jul 2014 09:46:37 +0200 Subject: [PATCH 367/701] Fix followRedirect assignment --- src/main/java/com/ning/http/client/AsyncHttpClientConfig.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java b/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java index 610ef65c0e..743433a767 100644 --- a/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java @@ -98,7 +98,7 @@ private AsyncHttpClientConfig(int maxTotalConnections, int idleConnectionTimeoutInMs, int requestTimeoutInMs, int connectionMaxLifeTimeInMs, - boolean redirectEnabled, + boolean followRedirect, int maxRedirects, boolean compressionEnabled, String userAgent, From 6f1c7772736589cc4a3aa8de09ec57892e526edc Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 9 Jul 2014 09:50:43 +0200 Subject: [PATCH 368/701] Drop AsyncHttpClientConfig deprecated methods, close #605 --- .../http/client/AsyncHttpClientConfig.java | 44 +++---------------- .../grizzly/GrizzlyAsyncHttpProvider.java | 2 +- .../netty/NettyAsyncHttpProvider.java | 2 +- .../http/util/AsyncHttpProviderUtils.java | 2 +- 4 files changed, 8 insertions(+), 42 deletions(-) diff --git a/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java b/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java index 743433a767..9555133567 100644 --- a/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java @@ -250,17 +250,7 @@ public int getMaxRedirects() { * * @return true if keep-alive is enabled */ - public boolean getAllowPoolingConnection() { - return allowPoolingConnection; - } - - /** - * Is the {@link ConnectionsPool} support enabled. - * - * @return true if keep-alive is enabled - * @deprecated - Use {@link AsyncHttpClientConfig#getAllowPoolingConnection()} - */ - public boolean getKeepAlive() { + public boolean isAllowPoolingConnection() { return allowPoolingConnection; } @@ -431,17 +421,6 @@ public boolean isRemoveQueryParamOnRedirect() { return removeQueryParamOnRedirect; } - /** - * 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 !isValid(); - } - /** * @return true if both the application and reaper thread pools * haven't yet been shutdown. @@ -449,15 +428,14 @@ public boolean isClosed() { * @since 1.7.21 */ public boolean isValid() { - boolean atpRunning = true; try { - atpRunning = applicationThreadPool.isShutdown(); + return 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; + return true; } /** @@ -700,18 +678,6 @@ public Builder setAllowPoolingConnection(boolean allowPoolingConnection) { return this; } - /** - * Set true if connection can be pooled by a {@link ConnectionsPool}. Default is true. - * - * @param allowPoolingConnection true if connection can be pooled by a {@link ConnectionsPool} - * @return a {@link Builder} - * @deprecated - Use {@link com.ning.http.client.AsyncHttpClientConfig.Builder#setAllowPoolingConnection(boolean)} - */ - public Builder setKeepAlive(boolean allowPoolingConnection) { - this.allowPoolingConnection = allowPoolingConnection; - return this; - } - /** * Set the {@link java.util.concurrent.ExecutorService} an {@link AsyncHttpClient} use for handling * asynchronous response. @@ -1038,7 +1004,7 @@ public Builder setTimeConverter(TimeConverter timeConverter) { * @param prototype the configuration to use as a prototype. */ public Builder(AsyncHttpClientConfig prototype) { - allowPoolingConnection = prototype.getAllowPoolingConnection(); + allowPoolingConnection = prototype.isAllowPoolingConnection(); providerConfig = prototype.getAsyncHttpProviderConfig(); connectionsPool = prototype.getConnectionsPool(); connectionTimeOutInMs = prototype.getConnectionTimeoutInMs(); @@ -1070,7 +1036,7 @@ public Builder(AsyncHttpClientConfig prototype) { disableUrlEncodingForBoundedRequests = prototype.isDisableUrlEncodingForBoundedRequests(); ioThreadMultiplier = prototype.getIoThreadMultiplier(); maxRequestRetry = prototype.getMaxRequestRetry(); - allowSslConnectionPool = prototype.getAllowPoolingConnection(); + allowSslConnectionPool = prototype.isAllowPoolingConnection(); removeQueryParamOnRedirect = prototype.isRemoveQueryParamOnRedirect(); hostnameVerifier = prototype.getHostnameVerifier(); strict302Handling = prototype.isStrict302Handling(); 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 c0df47f795..e49aa38118 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 @@ -2369,7 +2369,7 @@ static class ConnectionManager { ConnectionsPool connectionPool; this.provider = provider; final AsyncHttpClientConfig config = provider.clientConfig; - if (config.getAllowPoolingConnection()) { + if (config.isAllowPoolingConnection()) { ConnectionsPool pool = config.getConnectionsPool(); if (pool != null) { //noinspection unchecked 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 cacc84dff7..8a01ccfc96 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 @@ -274,7 +274,7 @@ public NettyAsyncHttpProvider(AsyncHttpClientConfig config) { // This is dangerous as we can't catch a wrong typed ConnectionsPool ConnectionsPool cp = (ConnectionsPool) config.getConnectionsPool(); - if (cp == null && config.getAllowPoolingConnection()) { + if (cp == null && config.isAllowPoolingConnection()) { cp = new NettyConnectionsPool(this, nettyTimer); } else if (cp == null) { cp = new NonConnectionsPool(); diff --git a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java index 3eefea514b..430723de89 100644 --- a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java +++ b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java @@ -223,7 +223,7 @@ public static String parseCharset(String contentType) { } public static String keepAliveHeaderValue(AsyncHttpClientConfig config) { - return config.getAllowPoolingConnection() ? "keep-alive" : "close"; + return config.isAllowPoolingConnection() ? "keep-alive" : "close"; } public static int requestTimeout(AsyncHttpClientConfig config, Request request) { From cdcfaaf56822e1b5d1efd853c159ec3cf190b62b Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 9 Jul 2014 16:14:54 +0200 Subject: [PATCH 369/701] Move CleanupChannelGroup to netty package --- .../{util => client/providers/netty}/CleanupChannelGroup.java | 2 +- .../http/client/providers/netty/NettyAsyncHttpProvider.java | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) rename src/main/java/com/ning/http/{util => client/providers/netty}/CleanupChannelGroup.java (98%) diff --git a/src/main/java/com/ning/http/util/CleanupChannelGroup.java b/src/main/java/com/ning/http/client/providers/netty/CleanupChannelGroup.java similarity index 98% rename from src/main/java/com/ning/http/util/CleanupChannelGroup.java rename to src/main/java/com/ning/http/client/providers/netty/CleanupChannelGroup.java index d0ea020cb0..89e50077db 100644 --- a/src/main/java/com/ning/http/util/CleanupChannelGroup.java +++ b/src/main/java/com/ning/http/client/providers/netty/CleanupChannelGroup.java @@ -26,7 +26,7 @@ * limitations under the License. */ -package com.ning.http.util; +package com.ning.http.client.providers.netty; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFuture; 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 8a01ccfc96..b1a68c1455 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 @@ -150,7 +150,6 @@ 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.MiscUtil; import com.ning.http.util.ProxyUtils; import com.ning.http.util.SslUtils; From 1d9589737be3fc1700022d06c2d1dc8d092c0f07 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 9 Jul 2014 16:17:42 +0200 Subject: [PATCH 370/701] Minor clean up --- src/main/java/com/ning/http/util/UTF8Codec.java | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/src/main/java/com/ning/http/util/UTF8Codec.java b/src/main/java/com/ning/http/util/UTF8Codec.java index cb3a7ad2a3..01768d3d9a 100644 --- a/src/main/java/com/ning/http/util/UTF8Codec.java +++ b/src/main/java/com/ning/http/util/UTF8Codec.java @@ -24,21 +24,7 @@ public class UTF8Codec { private final static String ENCODING_UTF8 = "UTF-8"; - // When we move to JDK 1.6+, we can do this: - /* - import java.nio.charset.Charset; - - private final static Charset utf8; - static { - utf8 = Charset.forName("UTF-8"); - } - - public static byte[] toUTF8(String input) { - return input.getBytes(utf8); - } - */ - - // But until then (with 1.5) + // Until we target JDK6+ public static byte[] toUTF8(String input) { try { return input.getBytes(ENCODING_UTF8); From 6dd108e2bc46da279f4362bcbaac9e6686790a2c Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 9 Jul 2014 16:28:35 +0200 Subject: [PATCH 371/701] Minor clean up --- .../client/AsyncHttpClientConfigDefaults.java | 2 +- .../FluentCaseInsensitiveStringsMap.java | 2 +- .../ning/http/client/FluentStringsMap.java | 2 +- src/main/java/com/ning/http/client/Realm.java | 2 +- .../ning/http/client/RequestBuilderBase.java | 2 +- .../listener/TransferCompletionHandler.java | 2 +- .../com/ning/http/client/ntlm/NTLMEngine.java | 2 +- .../oauth/OAuthSignatureCalculator.java | 2 +- .../apache/ApacheAsyncHttpProvider.java | 2 +- .../providers/apache/ApacheResponse.java | 2 +- .../apache/ApacheResponseFuture.java | 2 +- .../grizzly/GrizzlyAsyncHttpProvider.java | 2 +- .../grizzly/GrizzlyConnectionsPool.java | 2 +- .../providers/grizzly/GrizzlyResponse.java | 2 +- .../providers/jdk/JDKAsyncHttpProvider.java | 2 +- .../providers/jdk/JDKDelegateFuture.java | 2 +- .../http/client/providers/jdk/JDKFuture.java | 2 +- .../client/providers/jdk/JDKResponse.java | 2 +- .../netty/NettyAsyncHttpProvider.java | 8 +- .../providers/netty/NettyConnectionsPool.java | 2 +- .../client/providers/netty/NettyResponse.java | 2 +- .../providers/netty/NettyResponseFuture.java | 2 +- .../IdleConnectionTimeoutTimerTask.java | 2 +- .../timeout/RequestTimeoutTimerTask.java | 2 +- .../multipart/MultipartRequestEntity.java | 2 +- .../http/util/AsyncHttpProviderUtils.java | 2 +- .../ning/http/util/AuthenticatorUtils.java | 2 +- .../java/com/ning/http/util/DateUtil.java | 236 ------------------ .../java/com/ning/http/util/DateUtils.java | 23 ++ .../util/{MiscUtil.java => MiscUtils.java} | 4 +- .../com/ning/http/util/QueryComputer.java | 2 +- .../com/ning/http/util/UTF8UrlEncoder.java | 2 +- .../client/async/AsyncProvidersBasicTest.java | 4 +- .../http/client/async/ParamEncodingTest.java | 2 +- .../client/async/PerRequestTimeoutTest.java | 2 +- .../http/client/async/PostWithQSTest.java | 2 +- .../client/async/QueryParametersTest.java | 2 +- 37 files changed, 63 insertions(+), 276 deletions(-) delete mode 100644 src/main/java/com/ning/http/util/DateUtil.java create mode 100644 src/main/java/com/ning/http/util/DateUtils.java rename src/main/java/com/ning/http/util/{MiscUtil.java => MiscUtils.java} (96%) diff --git a/src/main/java/com/ning/http/client/AsyncHttpClientConfigDefaults.java b/src/main/java/com/ning/http/client/AsyncHttpClientConfigDefaults.java index e1437a29ed..e42674000b 100644 --- a/src/main/java/com/ning/http/client/AsyncHttpClientConfigDefaults.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClientConfigDefaults.java @@ -13,7 +13,7 @@ package com.ning.http.client; import com.ning.http.util.AllowAllHostnameVerifier; -import static com.ning.http.util.MiscUtil.getBoolean; +import static com.ning.http.util.MiscUtils.getBoolean; import javax.net.ssl.HostnameVerifier; diff --git a/src/main/java/com/ning/http/client/FluentCaseInsensitiveStringsMap.java b/src/main/java/com/ning/http/client/FluentCaseInsensitiveStringsMap.java index 2b634011a0..46671f21d4 100644 --- a/src/main/java/com/ning/http/client/FluentCaseInsensitiveStringsMap.java +++ b/src/main/java/com/ning/http/client/FluentCaseInsensitiveStringsMap.java @@ -16,7 +16,7 @@ */ package com.ning.http.client; -import static com.ning.http.util.MiscUtil.isNonEmpty; +import static com.ning.http.util.MiscUtils.isNonEmpty; import java.util.ArrayList; import java.util.Arrays; diff --git a/src/main/java/com/ning/http/client/FluentStringsMap.java b/src/main/java/com/ning/http/client/FluentStringsMap.java index 3fdf5e2581..0a6bba1b77 100644 --- a/src/main/java/com/ning/http/client/FluentStringsMap.java +++ b/src/main/java/com/ning/http/client/FluentStringsMap.java @@ -16,7 +16,7 @@ */ package com.ning.http.client; -import static com.ning.http.util.MiscUtil.isNonEmpty; +import static com.ning.http.util.MiscUtils.isNonEmpty; import java.util.ArrayList; import java.util.Arrays; diff --git a/src/main/java/com/ning/http/client/Realm.java b/src/main/java/com/ning/http/client/Realm.java index b6e0277adc..75284d1ddd 100644 --- a/src/main/java/com/ning/http/client/Realm.java +++ b/src/main/java/com/ning/http/client/Realm.java @@ -16,7 +16,7 @@ */ package com.ning.http.client; -import static com.ning.http.util.MiscUtil.isNonEmpty; +import static com.ning.http.util.MiscUtils.isNonEmpty; import java.io.UnsupportedEncodingException; import java.security.MessageDigest; diff --git a/src/main/java/com/ning/http/client/RequestBuilderBase.java b/src/main/java/com/ning/http/client/RequestBuilderBase.java index e92f0acef5..739b7bc261 100644 --- a/src/main/java/com/ning/http/client/RequestBuilderBase.java +++ b/src/main/java/com/ning/http/client/RequestBuilderBase.java @@ -15,7 +15,7 @@ */ package com.ning.http.client; -import static com.ning.http.util.MiscUtil.isNonEmpty; +import static com.ning.http.util.MiscUtils.isNonEmpty; import java.io.File; import java.io.InputStream; 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 5088f12577..bf1ccf0e59 100644 --- a/src/main/java/com/ning/http/client/listener/TransferCompletionHandler.java +++ b/src/main/java/com/ning/http/client/listener/TransferCompletionHandler.java @@ -26,7 +26,7 @@ import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.atomic.AtomicLong; -import static com.ning.http.util.MiscUtil.isNonEmpty; +import static com.ning.http.util.MiscUtils.isNonEmpty; /** * A {@link com.ning.http.client.AsyncHandler} that can be used to notify a set of {@link com.ning.http.client.listener.TransferListener} 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 8af983e759..44c7f8ee65 100644 --- a/src/main/java/com/ning/http/client/ntlm/NTLMEngine.java +++ b/src/main/java/com/ning/http/client/ntlm/NTLMEngine.java @@ -26,7 +26,7 @@ package com.ning.http.client.ntlm; -import static com.ning.http.util.MiscUtil.isNonEmpty; +import static com.ning.http.util.MiscUtils.isNonEmpty; import java.io.UnsupportedEncodingException; import java.security.Key; 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 235aa544df..8884a6a828 100644 --- a/src/main/java/com/ning/http/client/oauth/OAuthSignatureCalculator.java +++ b/src/main/java/com/ning/http/client/oauth/OAuthSignatureCalculator.java @@ -16,7 +16,7 @@ */ package com.ning.http.client.oauth; -import static com.ning.http.util.MiscUtil.isNonEmpty; +import static com.ning.http.util.MiscUtils.isNonEmpty; import com.ning.http.client.Param; import com.ning.http.client.Request; 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 2b431bc662..25b951afb3 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,7 +12,7 @@ */ package com.ning.http.client.providers.apache; -import static com.ning.http.util.MiscUtil.isNonEmpty; +import static com.ning.http.util.MiscUtils.isNonEmpty; import com.ning.http.client.AsyncHandler; import com.ning.http.client.AsyncHttpClientConfig; 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 0865b25834..fdbe511e52 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,7 +12,7 @@ */ package com.ning.http.client.providers.apache; -import static com.ning.http.util.MiscUtil.isNonEmpty; +import static com.ning.http.util.MiscUtils.isNonEmpty; import java.io.IOException; import java.io.InputStream; 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 cdbe106c92..f91c5d9f04 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,7 +12,7 @@ */ package com.ning.http.client.providers.apache; -import static com.ning.http.util.DateUtil.millisTime; +import static com.ning.http.util.DateUtils.millisTime; import com.ning.http.client.AsyncHandler; import com.ning.http.client.Request; 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 e49aa38118..208cfd88ac 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,7 +16,7 @@ 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; -import static com.ning.http.util.MiscUtil.isNonEmpty; +import static com.ning.http.util.MiscUtils.isNonEmpty; import java.io.ByteArrayOutputStream; import java.io.File; 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 8859fb821c..b5e0925d52 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,7 +13,7 @@ package com.ning.http.client.providers.grizzly; -import static com.ning.http.util.DateUtil.millisTime; +import static com.ning.http.util.DateUtils.millisTime; import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.ConnectionsPool; 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 3e83f1bc94..863c8a9fe0 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,7 +13,7 @@ package com.ning.http.client.providers.grizzly; -import static com.ning.http.util.MiscUtil.isNonEmpty; +import static com.ning.http.util.MiscUtils.isNonEmpty; import java.io.IOException; import java.io.InputStream; 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 f000c92c67..35bea239fa 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 @@ -13,7 +13,7 @@ package com.ning.http.client.providers.jdk; import static com.ning.http.util.AsyncHttpProviderUtils.DEFAULT_CHARSET; -import static com.ning.http.util.MiscUtil.isNonEmpty; +import static com.ning.http.util.MiscUtils.isNonEmpty; import java.io.ByteArrayInputStream; import java.io.File; 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 b1dbcc3a3a..5842691b48 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,7 +12,7 @@ */ package com.ning.http.client.providers.jdk; -import static com.ning.http.util.DateUtil.millisTime; +import static com.ning.http.util.DateUtils.millisTime; import com.ning.http.client.AsyncHandler; import com.ning.http.client.ListenableFuture; 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 0ec695ae9f..9a45e2faab 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,7 +12,7 @@ */ package com.ning.http.client.providers.jdk; -import static com.ning.http.util.DateUtil.millisTime; +import static com.ning.http.util.DateUtils.millisTime; import com.ning.http.client.AsyncHandler; import com.ning.http.client.listenable.AbstractListenableFuture; 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 ef0735956c..d2c09aa5bd 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,7 +12,7 @@ */ package com.ning.http.client.providers.jdk; -import static com.ning.http.util.MiscUtil.isNonEmpty; +import static com.ning.http.util.MiscUtils.isNonEmpty; import java.io.ByteArrayInputStream; import java.io.IOException; 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 b1a68c1455..95be5c1b38 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 @@ -28,7 +28,7 @@ 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.MiscUtil.isNonEmpty; +import static com.ning.http.util.MiscUtils.isNonEmpty; import static org.jboss.netty.channel.Channels.pipeline; import static org.jboss.netty.handler.ssl.SslHandler.getDefaultBufferPool; @@ -150,7 +150,7 @@ import com.ning.http.multipart.MultipartRequestEntity; import com.ning.http.util.AsyncHttpProviderUtils; import com.ning.http.util.AuthenticatorUtils; -import com.ning.http.util.MiscUtil; +import com.ning.http.util.MiscUtils; import com.ning.http.util.ProxyUtils; import com.ning.http.util.SslUtils; @@ -1999,13 +1999,13 @@ public Object call() throws Exception { private final String computeRealmURI(Realm realm, UriComponents requestURI) { if (realm.isUseAbsoluteURI()) { - if (realm.isOmitQuery() && MiscUtil.isNonEmpty(requestURI.getQuery())) { + if (realm.isOmitQuery() && MiscUtils.isNonEmpty(requestURI.getQuery())) { return requestURI.withNewQuery(null).toString(); } else { return requestURI.toString(); } } else { - if (realm.isOmitQuery() || !MiscUtil.isNonEmpty(requestURI.getQuery())) { + if (realm.isOmitQuery() || !MiscUtils.isNonEmpty(requestURI.getQuery())) { return requestURI.getPath(); } else { return requestURI.getPath() + "?" + requestURI.getQuery(); 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 1feabcd579..94186250c4 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,7 +12,7 @@ */ package com.ning.http.client.providers.netty; -import static com.ning.http.util.DateUtil.millisTime; +import static com.ning.http.util.DateUtils.millisTime; import java.util.ArrayList; import java.util.List; 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 02c8d48509..9ce67470c2 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,7 +15,7 @@ */ package com.ning.http.client.providers.netty; -import static com.ning.http.util.MiscUtil.isNonEmpty; +import static com.ning.http.util.MiscUtils.isNonEmpty; import java.io.IOException; import java.io.InputStream; 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 b10823b193..f1a9dc7d62 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,7 +15,7 @@ */ package com.ning.http.client.providers.netty; -import static com.ning.http.util.DateUtil.millisTime; +import static com.ning.http.util.DateUtils.millisTime; import java.net.SocketAddress; import java.util.concurrent.CancellationException; diff --git a/src/main/java/com/ning/http/client/providers/netty/timeout/IdleConnectionTimeoutTimerTask.java b/src/main/java/com/ning/http/client/providers/netty/timeout/IdleConnectionTimeoutTimerTask.java index 1f6b78db91..66fac8e7d2 100644 --- a/src/main/java/com/ning/http/client/providers/netty/timeout/IdleConnectionTimeoutTimerTask.java +++ b/src/main/java/com/ning/http/client/providers/netty/timeout/IdleConnectionTimeoutTimerTask.java @@ -12,7 +12,7 @@ */ package com.ning.http.client.providers.netty.timeout; -import static com.ning.http.util.DateUtil.millisTime; +import static com.ning.http.util.DateUtils.millisTime; import org.jboss.netty.util.Timeout; diff --git a/src/main/java/com/ning/http/client/providers/netty/timeout/RequestTimeoutTimerTask.java b/src/main/java/com/ning/http/client/providers/netty/timeout/RequestTimeoutTimerTask.java index 01272605b3..ce7ea3bae8 100644 --- a/src/main/java/com/ning/http/client/providers/netty/timeout/RequestTimeoutTimerTask.java +++ b/src/main/java/com/ning/http/client/providers/netty/timeout/RequestTimeoutTimerTask.java @@ -12,7 +12,7 @@ */ package com.ning.http.client.providers.netty.timeout; -import static com.ning.http.util.DateUtil.millisTime; +import static com.ning.http.util.DateUtils.millisTime; import org.jboss.netty.util.Timeout; diff --git a/src/main/java/com/ning/http/multipart/MultipartRequestEntity.java b/src/main/java/com/ning/http/multipart/MultipartRequestEntity.java index 66e43174be..2276347545 100644 --- a/src/main/java/com/ning/http/multipart/MultipartRequestEntity.java +++ b/src/main/java/com/ning/http/multipart/MultipartRequestEntity.java @@ -15,7 +15,7 @@ */ package com.ning.http.multipart; -import static com.ning.http.util.MiscUtil.isNonEmpty; +import static com.ning.http.util.MiscUtils.isNonEmpty; import com.ning.http.client.FluentCaseInsensitiveStringsMap; diff --git a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java index 430723de89..8f6a474574 100644 --- a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java +++ b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java @@ -12,7 +12,7 @@ */ package com.ning.http.util; -import static com.ning.http.util.MiscUtil.isNonEmpty; +import static com.ning.http.util.MiscUtils.isNonEmpty; import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.AsyncHttpProvider; diff --git a/src/main/java/com/ning/http/util/AuthenticatorUtils.java b/src/main/java/com/ning/http/util/AuthenticatorUtils.java index 96d17174f8..f9434eda27 100644 --- a/src/main/java/com/ning/http/util/AuthenticatorUtils.java +++ b/src/main/java/com/ning/http/util/AuthenticatorUtils.java @@ -12,7 +12,7 @@ */ package com.ning.http.util; -import static com.ning.http.util.MiscUtil.isNonEmpty; +import static com.ning.http.util.MiscUtils.isNonEmpty; import com.ning.http.client.ProxyServer; import com.ning.http.client.Realm; diff --git a/src/main/java/com/ning/http/util/DateUtil.java b/src/main/java/com/ning/http/util/DateUtil.java deleted file mode 100644 index 03ef393ad3..0000000000 --- a/src/main/java/com/ning/http/util/DateUtil.java +++ /dev/null @@ -1,236 +0,0 @@ -/* - * 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; - -/* - * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//httpclient/src/java/org/apache/commons/httpclient/util/DateUtil.java,v 1.2 2004/12/24 20:36:13 olegk Exp $ - * $Revision: 480424 $ - * $Date: 2006-11-29 06:56:49 +0100 (Wed, 29 Nov 2006) $ - * - * ==================================================================== - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF 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. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * . - * - */ - -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.Arrays; -import java.util.Calendar; -import java.util.Collection; -import java.util.Date; -import java.util.Iterator; -import java.util.Locale; -import java.util.TimeZone; - -/** - * A utility class for parsing and formatting HTTP dates as used in cookies and - * other headers. This class handles dates as defined by RFC 2616 section - * 3.3.1 as well as some other common non-standard formats. - * - * @author Christopher Brown - * @author Michael Becke - */ -public class DateUtil { - - /** - * Date format pattern used to parse HTTP date headers in RFC 1123 format. - */ - public static final String PATTERN_RFC1123 = "EEE, dd MMM yyyy HH:mm:ss zzz"; - - /** - * Date format pattern used to parse HTTP date headers in RFC 1036 format. - */ - public static final String PATTERN_RFC1036 = "EEEE, dd-MMM-yy HH:mm:ss zzz"; - - /** - * Date format pattern used to parse HTTP date headers in ANSI C - * asctime() format. - */ - public static final String PATTERN_ASCTIME = "EEE MMM d HH:mm:ss yyyy"; - - private static final Collection DEFAULT_PATTERNS = Arrays.asList( - new String[]{PATTERN_ASCTIME, PATTERN_RFC1036, PATTERN_RFC1123}); - - private static final Date DEFAULT_TWO_DIGIT_YEAR_START; - - static { - Calendar calendar = Calendar.getInstance(); - calendar.set(2000, Calendar.JANUARY, 1, 0, 0); - DEFAULT_TWO_DIGIT_YEAR_START = calendar.getTime(); - } - - private static final TimeZone GMT = TimeZone.getTimeZone("GMT"); - - /** - * Parses a date value. The formats used for parsing the date value are retrieved from - * the default http params. - * - * @param dateValue the date value to parse - * @return the parsed date - * @throws DateParseException if the value could not be parsed using any of the - * supported date formats - */ - public static Date parseDate(String dateValue) throws DateParseException { - return parseDate(dateValue, null, null); - } - - /** - * Parses the date value using the given date formats. - * - * @param dateValue the date value to parse - * @param dateFormats the date formats to use - * @return the parsed date - * @throws DateParseException if none of the dataFormats could parse the dateValue - */ - public static Date parseDate(String dateValue, Collection dateFormats) - throws DateParseException { - return parseDate(dateValue, dateFormats, null); - } - - /** - * Parses the date value using the given date formats. - * - * @param dateValue the date value to parse - * @param dateFormats the date formats to use - * @param startDate During parsing, two digit years will be placed in the range - * startDate to startDate + 100 years. This value may - * be null. When null is given as a parameter, year - * 2000 will be used. - * @return the parsed date - * @throws DateParseException if none of the dataFormats could parse the dateValue - */ - public static Date parseDate( - String dateValue, - Collection dateFormats, - Date startDate - ) throws DateParseException { - - if (dateValue == null) - throw new NullPointerException("dateValue"); - if (dateFormats == null) { - dateFormats = DEFAULT_PATTERNS; - } - if (startDate == null) { - startDate = DEFAULT_TWO_DIGIT_YEAR_START; - } - // trim single quotes around date if present - // see issue #5279 - if (dateValue.length() > 1 - && dateValue.startsWith("'") - && dateValue.endsWith("'") - ) { - dateValue = dateValue.substring(1, dateValue.length() - 1); - } - - SimpleDateFormat dateParser = null; - Iterator formatIter = dateFormats.iterator(); - - while (formatIter.hasNext()) { - String format = (String) formatIter.next(); - if (dateParser == null) { - dateParser = new SimpleDateFormat(format, Locale.US); - dateParser.setTimeZone(TimeZone.getTimeZone("GMT")); - dateParser.set2DigitYearStart(startDate); - } else { - dateParser.applyPattern(format); - } - try { - return dateParser.parse(dateValue); - } catch (ParseException pe) { - // ignore this exception, we will try the next format - } - } - - // we were unable to parse the date - throw new DateParseException("Unable to parse the date " + dateValue); - } - - /** - * Formats the given date according to the RFC 1123 pattern. - * - * @param date The date to format. - * @return An RFC 1123 formatted date string. - * @see #PATTERN_RFC1123 - */ - public static String formatDate(Date date) { - return formatDate(date, PATTERN_RFC1123); - } - - /** - * Formats the given date according to the specified pattern. The pattern - * must conform to that used by the {@link java.text.SimpleDateFormat simple date - * format} class. - * - * @param date The date to format. - * @param pattern The pattern to use for formatting the date. - * @return A formatted date string. - * @throws IllegalArgumentException If the given date pattern is invalid. - * @see java.text.SimpleDateFormat - */ - public static String formatDate(Date date, String pattern) { - if (date == null) throw new NullPointerException("date"); - if (pattern == null) throw new NullPointerException("pattern"); - - SimpleDateFormat formatter = new SimpleDateFormat(pattern, Locale.US); - formatter.setTimeZone(GMT); - return formatter.format(date); - } - - /** - * This class should not be instantiated. - */ - private DateUtil() { - } - - public static class DateParseException extends Exception { - - /** - * - */ - public DateParseException() { - super(); - } - - /** - * @param message the exception message - */ - public DateParseException(String message) { - super(message); - } - - } - - public static long millisTime() { - return System.nanoTime() / 1000000; - } -} diff --git a/src/main/java/com/ning/http/util/DateUtils.java b/src/main/java/com/ning/http/util/DateUtils.java new file mode 100644 index 0000000000..3544f0e4e1 --- /dev/null +++ b/src/main/java/com/ning/http/util/DateUtils.java @@ -0,0 +1,23 @@ +/* + * 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; + +public final class DateUtils { + + private DateUtils() { + } + + public static long millisTime() { + return System.nanoTime() / 1000000; + } +} diff --git a/src/main/java/com/ning/http/util/MiscUtil.java b/src/main/java/com/ning/http/util/MiscUtils.java similarity index 96% rename from src/main/java/com/ning/http/util/MiscUtil.java rename to src/main/java/com/ning/http/util/MiscUtils.java index e30082eb6c..dab4d5df95 100644 --- a/src/main/java/com/ning/http/util/MiscUtil.java +++ b/src/main/java/com/ning/http/util/MiscUtils.java @@ -15,9 +15,9 @@ import java.util.Collection; import java.util.Map; -public class MiscUtil { +public final class MiscUtils { - private MiscUtil() { + private MiscUtils() { } public static boolean isNonEmpty(String string) { diff --git a/src/main/java/com/ning/http/util/QueryComputer.java b/src/main/java/com/ning/http/util/QueryComputer.java index 09b1d41c57..6ab1956c13 100644 --- a/src/main/java/com/ning/http/util/QueryComputer.java +++ b/src/main/java/com/ning/http/util/QueryComputer.java @@ -12,7 +12,7 @@ */ package com.ning.http.util; -import static com.ning.http.util.MiscUtil.isNonEmpty; +import static com.ning.http.util.MiscUtils.isNonEmpty; import com.ning.http.client.Param; diff --git a/src/main/java/com/ning/http/util/UTF8UrlEncoder.java b/src/main/java/com/ning/http/util/UTF8UrlEncoder.java index f76cf15495..c4ab9f2752 100644 --- a/src/main/java/com/ning/http/util/UTF8UrlEncoder.java +++ b/src/main/java/com/ning/http/util/UTF8UrlEncoder.java @@ -21,7 +21,7 @@ */ public final class UTF8UrlEncoder { - private static final boolean encodeSpaceUsingPlus = MiscUtil.getBoolean("com.ning.http.util.UTF8UrlEncoder.encodeSpaceUsingPlus", false); + private static final boolean encodeSpaceUsingPlus = MiscUtils.getBoolean("com.ning.http.util.UTF8UrlEncoder.encodeSpaceUsingPlus", false); /** * Encoding table used for figuring out ascii characters that must be escaped 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 28b0a77fde..bbd501eeae 100755 --- a/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java +++ b/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java @@ -15,8 +15,8 @@ */ package com.ning.http.client.async; -import static com.ning.http.util.DateUtil.millisTime; -import static com.ning.http.util.MiscUtil.isNonEmpty; +import static com.ning.http.util.DateUtils.millisTime; +import static com.ning.http.util.MiscUtils.isNonEmpty; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNull; import static org.testng.Assert.assertTrue; 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 d84668e0f8..96e23495c4 100644 --- a/src/test/java/com/ning/http/client/async/ParamEncodingTest.java +++ b/src/test/java/com/ning/http/client/async/ParamEncodingTest.java @@ -15,7 +15,7 @@ */ package com.ning.http.client.async; -import static com.ning.http.util.MiscUtil.isNonEmpty; +import static com.ning.http.util.MiscUtils.isNonEmpty; import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.Response; 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 d74316d545..323dddc4e2 100644 --- a/src/test/java/com/ning/http/client/async/PerRequestTimeoutTest.java +++ b/src/test/java/com/ning/http/client/async/PerRequestTimeoutTest.java @@ -15,7 +15,7 @@ */ package com.ning.http.client.async; -import static com.ning.http.util.DateUtil.millisTime; +import static com.ning.http.util.DateUtils.millisTime; import com.ning.http.client.AsyncCompletionHandler; import com.ning.http.client.AsyncHttpClient; 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 69b21ed70a..4873e3a446 100644 --- a/src/test/java/com/ning/http/client/async/PostWithQSTest.java +++ b/src/test/java/com/ning/http/client/async/PostWithQSTest.java @@ -15,7 +15,7 @@ */ package com.ning.http.client.async; -import static com.ning.http.util.MiscUtil.isNonEmpty; +import static com.ning.http.util.MiscUtils.isNonEmpty; import com.ning.http.client.AsyncCompletionHandlerBase; import com.ning.http.client.AsyncHttpClient; 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 c40677a583..6511880a90 100644 --- a/src/test/java/com/ning/http/client/async/QueryParametersTest.java +++ b/src/test/java/com/ning/http/client/async/QueryParametersTest.java @@ -15,7 +15,7 @@ */ package com.ning.http.client.async; -import static com.ning.http.util.MiscUtil.isNonEmpty; +import static com.ning.http.util.MiscUtils.isNonEmpty; import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.Response; From 888ea0b55079f87e143d0b9fa500530f803f10f1 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 9 Jul 2014 21:38:33 +0200 Subject: [PATCH 372/701] Make all providers honor Realm.isOmitQuery and isUseAbsoluteURI, close #607 --- src/main/java/com/ning/http/client/Realm.java | 14 +- .../grizzly/GrizzlyAsyncHttpProvider.java | 2 +- .../providers/jdk/JDKAsyncHttpProvider.java | 3 +- .../netty/NettyAsyncHttpProvider.java | 58 ++------ .../ning/http/util/AuthenticatorUtils.java | 18 ++- .../java/com/ning/http/client/RealmTest.java | 125 +++++++++--------- 6 files changed, 104 insertions(+), 116 deletions(-) diff --git a/src/main/java/com/ning/http/client/Realm.java b/src/main/java/com/ning/http/client/Realm.java index 75284d1ddd..4163432c7e 100644 --- a/src/main/java/com/ning/http/client/Realm.java +++ b/src/main/java/com/ning/http/client/Realm.java @@ -18,6 +18,8 @@ import static com.ning.http.util.MiscUtils.isNonEmpty; +import com.ning.http.client.uri.UriComponents; + import java.io.UnsupportedEncodingException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; @@ -40,7 +42,7 @@ public class Realm { private final String qop; private final String nc; private final String cnonce; - private final String uri; + private final UriComponents uri; private final String methodName; private final boolean usePreemptiveAuth; private final String enc; @@ -70,7 +72,7 @@ private Realm(AuthScheme scheme, String qop, String nc, String cnonce, - String uri, + UriComponents uri, String method, boolean usePreemptiveAuth, String ntlmDomain, @@ -152,7 +154,7 @@ public String getCnonce() { return cnonce; } - public String getUri() { + public UriComponents getUri() { return uri; } @@ -284,7 +286,7 @@ public static class RealmBuilder { private String qop = "auth"; private String nc = "00000001"; private String cnonce = ""; - private String uri = ""; + private UriComponents uri; private String methodName = "GET"; private boolean usePreemptive = false; private String ntlmDomain = System.getProperty("http.auth.ntlm.domain", ""); @@ -403,11 +405,11 @@ public RealmBuilder setNc(String nc) { return this; } - public String getUri() { + public UriComponents getUri() { return uri; } - public RealmBuilder setUri(String uri) { + public RealmBuilder setUri(UriComponents uri) { this.uri = uri; return this; } 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 208cfd88ac..3c28f1d195 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 @@ -1569,7 +1569,7 @@ public boolean handleStatus(final HttpResponsePacket responsePacket, final Request req = httpTransactionContext.request; realm = new Realm.RealmBuilder().clone(realm) .setScheme(realm.getAuthScheme()) - .setUri(httpTransactionContext.request.getURI().getPath()) + .setUri(httpTransactionContext.request.getURI()) .setMethodName(req.getMethod()) .setUsePreemptiveAuth(true) .parseWWWAuthenticateHeader(auth) 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 35bea239fa..71f27489d2 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 @@ -30,7 +30,6 @@ import java.net.Proxy; import java.net.SocketAddress; import java.net.SocketTimeoutException; -import java.net.URI; import java.net.URISyntaxException; import java.net.UnknownHostException; import java.nio.ByteBuffer; @@ -290,7 +289,7 @@ public T call() throws Exception { Realm nr = new Realm.RealmBuilder().clone(realm) .parseWWWAuthenticateHeader(wwwAuth) - .setUri(URI.create(request.getUrl()).getPath()) + .setUri(UriComponents.create(request.getUrl())) .setMethodName(request.getMethod()) .setUsePreemptiveAuth(true) .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 95be5c1b38..2691741d6d 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 @@ -150,7 +150,6 @@ import com.ning.http.multipart.MultipartRequestEntity; import com.ning.http.util.AsyncHttpProviderUtils; import com.ning.http.util.AuthenticatorUtils; -import com.ning.http.util.MiscUtils; import com.ning.http.util.ProxyUtils; import com.ning.http.util.SslUtils; @@ -1213,11 +1212,10 @@ private Realm kerberosChallenge(List proxyAuth, Request request, ProxySe } else { realmBuilder = new Realm.RealmBuilder(); } - return realmBuilder.setUri(uri.getPath()).setMethodName(request.getMethod()).setScheme(Realm.AuthScheme.KERBEROS).build(); + return realmBuilder.setUri(uri).setMethodName(request.getMethod()).setScheme(Realm.AuthScheme.KERBEROS).build(); } catch (Throwable throwable) { - if (isNTLM(proxyAuth)) { + if (isNTLM(proxyAuth)) return ntlmChallenge(proxyAuth, request, proxyServer, headers, realm, future, proxyInd); - } abort(future, throwable); return null; } @@ -1252,32 +1250,25 @@ private Realm ntlmChallenge(List wwwAuth, Request request, ProxyServer p String ntlmHost = useRealm ? realm.getNtlmHost() : proxyServer.getHost(); String principal = useRealm ? realm.getPrincipal() : proxyServer.getPrincipal(); String password = useRealm ? realm.getPassword() : proxyServer.getPassword(); + UriComponents uri = request.getURI(); - Realm newRealm; + Realm.RealmBuilder realmBuilder; if (realm != null && !realm.isNtlmMessageType2Received()) { String challengeHeader = ntlmEngine.generateType1Msg(ntlmDomain, ntlmHost); - - UriComponents uri = request.getURI(); addNTLMAuthorization(headers, challengeHeader, proxyInd); - newRealm = new Realm.RealmBuilder().clone(realm).setScheme(realm.getAuthScheme()).setUri(uri.getPath()).setMethodName(request.getMethod()) - .setNtlmMessageType2Received(true).build(); + realmBuilder = new Realm.RealmBuilder().clone(realm).setScheme(realm.getAuthScheme()).setNtlmMessageType2Received(true); future.getAndSetAuth(false); } else { addType3NTLMAuthorizationHeader(wwwAuth, headers, principal, password, ntlmDomain, ntlmHost, proxyInd); - Realm.RealmBuilder realmBuilder; - Realm.AuthScheme authScheme; if (realm != null) { - realmBuilder = new Realm.RealmBuilder().clone(realm); - authScheme = realm.getAuthScheme(); + realmBuilder = new Realm.RealmBuilder().clone(realm).setScheme(realm.getAuthScheme()); } else { - realmBuilder = new Realm.RealmBuilder(); - authScheme = Realm.AuthScheme.NTLM; + realmBuilder = new Realm.RealmBuilder().setScheme(Realm.AuthScheme.NTLM); } - newRealm = realmBuilder.setScheme(authScheme).setUri(request.getURI().getPath()).setMethodName(request.getMethod()).build(); } - return newRealm; + return realmBuilder.setUri(uri).setMethodName(request.getMethod()).build(); } private Realm ntlmProxyChallenge(List wwwAuth, Request request, ProxyServer proxyServer, FluentCaseInsensitiveStringsMap headers, Realm realm, @@ -1285,15 +1276,12 @@ private Realm ntlmProxyChallenge(List wwwAuth, Request request, ProxySer future.getAndSetAuth(false); addType3NTLMAuthorizationHeader(wwwAuth, headers, proxyServer.getPrincipal(), proxyServer.getPassword(), proxyServer.getNtlmDomain(), proxyServer.getHost(), true); - Realm newRealm; Realm.RealmBuilder realmBuilder = new Realm.RealmBuilder(); if (realm != null) { realmBuilder = realmBuilder.clone(realm); } - newRealm = realmBuilder.setUri(request.getURI().getPath()).setMethodName(request.getMethod()).build(); - - return newRealm; + return realmBuilder.setUri(request.getURI()).setMethodName(request.getMethod()).build(); } private String getPoolKey(NettyResponseFuture future) { @@ -1996,23 +1984,6 @@ public Object call() throws Exception { return false; } - private final String computeRealmURI(Realm realm, UriComponents requestURI) { - if (realm.isUseAbsoluteURI()) { - - if (realm.isOmitQuery() && MiscUtils.isNonEmpty(requestURI.getQuery())) { - return requestURI.withNewQuery(null).toString(); - } else { - return requestURI.toString(); - } - } else { - if (realm.isOmitQuery() || !MiscUtils.isNonEmpty(requestURI.getQuery())) { - return requestURI.getPath(); - } else { - return requestURI.getPath() + "?" + requestURI.getQuery(); - } - } - } - private final class HttpProtocol implements Protocol { // @Override public void handle(final ChannelHandlerContext ctx, final MessageEvent e) throws Exception { @@ -2085,26 +2056,25 @@ public void handle(final ChannelHandlerContext ctx, final MessageEvent e) throws future.setState(NettyResponseFuture.STATE.NEW); Realm newRealm = null; - // NTLM if (!wwwAuth.contains("Kerberos") && (isNTLM(wwwAuth) || (wwwAuth.contains("Negotiate")))) { + // NTLM newRealm = ntlmChallenge(wwwAuth, request, proxyServer, headers, realm, future, false); - // SPNEGO KERBEROS } else if (wwwAuth.contains("Negotiate")) { + // SPNEGO KERBEROS newRealm = kerberosChallenge(wwwAuth, request, proxyServer, headers, realm, future, false); if (newRealm == null) return; } else { newRealm = new Realm.RealmBuilder().clone(realm) // .setScheme(realm.getAuthScheme()) // - .setUri(request.getURI().getPath()) // + .setUri(request.getURI()) // .setMethodName(request.getMethod()) // .setUsePreemptiveAuth(true) // - .parseWWWAuthenticateHeader(wwwAuth.get(0)) // + .parseWWWAuthenticateHeader(wwwAuth.get(0))// .build(); } - String realmURI = computeRealmURI(newRealm, request.getURI()); - final Realm nr = new Realm.RealmBuilder().clone(newRealm).setUri(realmURI).build(); + final Realm nr = newRealm; log.debug("Sending authentication to {}", request.getURI()); AsyncCallable ac = new AsyncCallable(future) { diff --git a/src/main/java/com/ning/http/util/AuthenticatorUtils.java b/src/main/java/com/ning/http/util/AuthenticatorUtils.java index f9434eda27..8071ac7d1d 100644 --- a/src/main/java/com/ning/http/util/AuthenticatorUtils.java +++ b/src/main/java/com/ning/http/util/AuthenticatorUtils.java @@ -16,6 +16,7 @@ import com.ning.http.client.ProxyServer; import com.ning.http.client.Realm; +import com.ning.http.client.uri.UriComponents; import java.io.UnsupportedEncodingException; import java.security.NoSuchAlgorithmException; @@ -31,14 +32,25 @@ public static String computeBasicAuthentication(ProxyServer proxyServer) throws String s = proxyServer.getPrincipal() + ":" + proxyServer.getPassword(); return "Basic " + Base64.encode(s.getBytes(proxyServer.getEncoding())); } - + + private static String computeRealmURI(Realm realm) { + UriComponents uri = realm.getUri(); + boolean omitQuery = realm.isOmitQuery() && MiscUtils.isNonEmpty(uri.getQuery()); + if (realm.isUseAbsoluteURI()) { + return omitQuery ? uri.withNewQuery(null).toUrl() : uri.toUrl(); + } else { + String path = uri.getPath(); + return omitQuery ? path : path + "?" + uri.getQuery(); + } + } + public static String computeDigestAuthentication(Realm realm) throws NoSuchAlgorithmException, UnsupportedEncodingException { StringBuilder builder = new StringBuilder().append("Digest "); construct(builder, "username", realm.getPrincipal()); construct(builder, "realm", realm.getRealmName()); construct(builder, "nonce", realm.getNonce()); - construct(builder, "uri", realm.getUri()); + construct(builder, "uri", computeRealmURI(realm)); builder.append("algorithm").append('=').append(realm.getAlgorithm()).append(", "); construct(builder, "response", realm.getResponse()); @@ -48,7 +60,7 @@ public static String computeDigestAuthentication(Realm realm) throws NoSuchAlgor builder.append("nc").append('=').append(realm.getNc()).append(", "); construct(builder, "cnonce", realm.getCnonce(), true); - return new String(builder.toString().getBytes("ISO_8859_1")); + return new String(builder.toString().getBytes("ISO-8859-1")); } private static StringBuilder construct(StringBuilder builder, String name, String value) { diff --git a/src/test/java/com/ning/http/client/RealmTest.java b/src/test/java/com/ning/http/client/RealmTest.java index 6bd2a622b5..df2d4f75d4 100644 --- a/src/test/java/com/ning/http/client/RealmTest.java +++ b/src/test/java/com/ning/http/client/RealmTest.java @@ -14,107 +14,112 @@ import com.ning.http.client.Realm.AuthScheme; import com.ning.http.client.Realm.RealmBuilder; +import com.ning.http.client.uri.UriComponents; + import org.testng.Assert; + import java.math.BigInteger; import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; + import org.testng.annotations.Test; public class RealmTest { @Test(groups = "fast") public void testClone() { RealmBuilder builder = new RealmBuilder(); - builder.setPrincipal( "user" ).setPassword( "pass" ); - builder.setEnconding( "enc" ).setUsePreemptiveAuth( true ); - builder.setRealmName( "realm" ).setAlgorithm( "algo" ); - builder.setScheme( AuthScheme.BASIC ); + builder.setPrincipal("user").setPassword("pass"); + builder.setEnconding("enc").setUsePreemptiveAuth(true); + builder.setRealmName("realm").setAlgorithm("algo"); + builder.setScheme(AuthScheme.BASIC); Realm orig = builder.build(); - - Realm clone = new RealmBuilder().clone( orig ).build(); - Assert.assertEquals( clone.getPrincipal(), orig.getPrincipal() ); - Assert.assertEquals( clone.getPassword(), orig.getPassword() ); - Assert.assertEquals( clone.getEncoding(), orig.getEncoding() ); - Assert.assertEquals( clone.getUsePreemptiveAuth(), orig.getUsePreemptiveAuth() ); - Assert.assertEquals( clone.getRealmName(), orig.getRealmName() ); - Assert.assertEquals( clone.getAlgorithm(), orig.getAlgorithm() ); - Assert.assertEquals( clone.getAuthScheme(), orig.getAuthScheme() ); + + Realm clone = new RealmBuilder().clone(orig).build(); + Assert.assertEquals(clone.getPrincipal(), orig.getPrincipal()); + Assert.assertEquals(clone.getPassword(), orig.getPassword()); + Assert.assertEquals(clone.getEncoding(), orig.getEncoding()); + Assert.assertEquals(clone.getUsePreemptiveAuth(), orig.getUsePreemptiveAuth()); + Assert.assertEquals(clone.getRealmName(), orig.getRealmName()); + Assert.assertEquals(clone.getAlgorithm(), orig.getAlgorithm()); + Assert.assertEquals(clone.getAuthScheme(), orig.getAuthScheme()); } + @Test(groups = "fast") public void testOldDigestEmptyString() { - String qop=""; + String qop = ""; testOldDigest(qop); } + @Test(groups = "fast") public void testOldDigestNull() { - String qop=null; + String qop = null; testOldDigest(qop); } - private void testOldDigest(String qop){ - String user="user"; - String pass="pass"; - String realm="realm"; - String nonce="nonce"; - String method="GET"; - String uri="/foo"; + private void testOldDigest(String qop) { + String user = "user"; + String pass = "pass"; + String realm = "realm"; + String nonce = "nonce"; + String method = "GET"; + UriComponents uri = UriComponents.create("http://ahc.io/foo"); RealmBuilder builder = new RealmBuilder(); - builder.setPrincipal( user ).setPassword( pass ); - builder.setNonce( nonce ); - builder.setUri( uri ); + builder.setPrincipal(user).setPassword(pass); + builder.setNonce(nonce); + builder.setUri(uri); builder.setMethodName(method); - builder.setRealmName( realm ); + builder.setRealmName(realm); builder.setQop(qop); - builder.setScheme( AuthScheme.DIGEST ); + builder.setScheme(AuthScheme.DIGEST); Realm orig = builder.build(); - String ha1=getMd5(user +":" + realm +":"+pass); - String ha2=getMd5(method +":"+ uri); - String expectedResponse=getMd5(ha1 +":" + nonce +":" + ha2); + String ha1 = getMd5(user + ":" + realm + ":" + pass); + String ha2 = getMd5(method + ":" + uri); + String expectedResponse = getMd5(ha1 + ":" + nonce + ":" + ha2); - Assert.assertEquals(expectedResponse,orig.getResponse()); + Assert.assertEquals(expectedResponse, orig.getResponse()); } @Test(groups = "fast") public void testStrongDigest() { - String user="user"; - String pass="pass"; - String realm="realm"; - String nonce="nonce"; - String method="GET"; - String uri="/foo"; - String qop="auth"; + String user = "user"; + String pass = "pass"; + String realm = "realm"; + String nonce = "nonce"; + String method = "GET"; + UriComponents uri = UriComponents.create("http://ahc.io/foo"); + String qop = "auth"; RealmBuilder builder = new RealmBuilder(); - builder.setPrincipal( user ).setPassword( pass ); - builder.setNonce( nonce ); - builder.setUri( uri ); + builder.setPrincipal(user).setPassword(pass); + builder.setNonce(nonce); + builder.setUri(uri); builder.setMethodName(method); - builder.setRealmName( realm ); + builder.setRealmName(realm); builder.setQop(qop); - builder.setScheme( AuthScheme.DIGEST ); + builder.setScheme(AuthScheme.DIGEST); Realm orig = builder.build(); String nc = orig.getNc(); String cnonce = orig.getCnonce(); - String ha1=getMd5(user +":" + realm +":"+pass); - String ha2=getMd5(method +":"+ uri); - String expectedResponse=getMd5(ha1 +":" + nonce +":" + nc + ":" + cnonce +":" + qop + ":" + ha2); + String ha1 = getMd5(user + ":" + realm + ":" + pass); + String ha2 = getMd5(method + ":" + uri); + String expectedResponse = getMd5(ha1 + ":" + nonce + ":" + nc + ":" + cnonce + ":" + qop + ":" + ha2); - Assert.assertEquals(expectedResponse,orig.getResponse()); + Assert.assertEquals(expectedResponse, orig.getResponse()); } - private String getMd5(String what){ - try { + private String getMd5(String what) { + try { MessageDigest md = MessageDigest.getInstance("MD5"); - md.update(what.getBytes("ISO-8859-1")); - byte[] hash = md.digest(); - BigInteger bi = new BigInteger(1, hash); - String result = bi.toString(16); - if (result.length() % 2 != 0) { - return "0" + result; - } - return result; - } catch (Exception e) { - throw new RuntimeException(e); + md.update(what.getBytes("ISO-8859-1")); + byte[] hash = md.digest(); + BigInteger bi = new BigInteger(1, hash); + String result = bi.toString(16); + if (result.length() % 2 != 0) { + return "0" + result; } + return result; + } catch (Exception e) { + throw new RuntimeException(e); + } } } From d60c8db271366db43df256a698524a6f527f22f0 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 9 Jul 2014 22:57:16 +0200 Subject: [PATCH 373/701] Don't replace empty path with a / in Request, back port #606 --- .../java/com/ning/http/client/Request.java | 7 ---- .../ning/http/client/RequestBuilderBase.java | 28 ++------------- .../http/client/SimpleAsyncHttpClient.java | 24 ++++++------- .../apache/ApacheAsyncHttpProvider.java | 10 +++--- .../grizzly/GrizzlyAsyncHttpProvider.java | 34 ++++++++----------- .../providers/jdk/JDKAsyncHttpProvider.java | 6 ++-- .../netty/NettyAsyncHttpProvider.java | 9 ++--- .../resumable/ResumableAsyncHandler.java | 6 ++-- .../simple/SimpleAHCTransferListener.java | 19 ++++++----- .../http/util/AsyncHttpProviderUtils.java | 25 +++++--------- .../ning/http/util/AuthenticatorUtils.java | 3 +- .../client/async/AsyncProvidersBasicTest.java | 2 +- .../http/client/async/RequestBuilderTest.java | 13 ++++--- .../async/SimpleAsyncHttpClientTest.java | 22 ++++++------ .../resumable/ResumableAsyncHandlerTest.java | 4 +-- 15 files changed, 86 insertions(+), 126 deletions(-) diff --git a/src/main/java/com/ning/http/client/Request.java b/src/main/java/com/ning/http/client/Request.java index 7368063632..115d98b71d 100644 --- a/src/main/java/com/ning/http/client/Request.java +++ b/src/main/java/com/ning/http/client/Request.java @@ -54,13 +54,6 @@ public static interface EntityWriter { */ String getMethod(); - /** - * Return the decoded url - * - * @return the decoded url - */ - String getUrl(); - UriComponents getURI(); /** diff --git a/src/main/java/com/ning/http/client/RequestBuilderBase.java b/src/main/java/com/ning/http/client/RequestBuilderBase.java index 739b7bc261..18420f99e8 100644 --- a/src/main/java/com/ning/http/client/RequestBuilderBase.java +++ b/src/main/java/com/ning/http/client/RequestBuilderBase.java @@ -114,19 +114,6 @@ public InetAddress getLocalAddress() { return localAddress; } - private String removeTrailingSlash(UriComponents uri) { - String uriString = uri.toUrl(); - if (uriString.endsWith("/")) { - return uriString.substring(0, uriString.length() - 1); - } else { - return uriString; - } - } - - public String getUrl() { - return removeTrailingSlash(getURI()); - } - public UriComponents getURI() { return uri; } @@ -286,8 +273,6 @@ public T setUrl(String url) { } public T setURI(UriComponents uri) { - if (uri.getPath() == null) - throw new NullPointerException("uri.path"); request.uri = uri; return derived.cast(this); } @@ -600,23 +585,14 @@ private void computeRequestLength() { private void computeFinalUri() { if (request.uri == null) { - logger.debug("setUrl hasn't been invoked. Using http://localhost"); + logger.debug("setUrl hasn't been invoked. Using {}", DEFAULT_REQUEST_URL); request.uri = DEFAULT_REQUEST_URL; } AsyncHttpProviderUtils.validateSupportedScheme(request.uri); - // FIXME is that right? - String newPath = isNonEmpty(request.uri.getPath()) ? request.uri.getPath() : "/"; String newQuery = queryComputer.computeFullQueryString(request.uri.getQuery(), queryParams); - - request.uri = new UriComponents(// - request.uri.getScheme(),// - request.uri.getUserInfo(),// - request.uri.getHost(),// - request.uri.getPort(),// - newPath,// - newQuery); + request.uri = request.uri.withNewQuery(newQuery); } public Request build() { diff --git a/src/main/java/com/ning/http/client/SimpleAsyncHttpClient.java b/src/main/java/com/ning/http/client/SimpleAsyncHttpClient.java index f21c149433..85fa2e2963 100644 --- a/src/main/java/com/ning/http/client/SimpleAsyncHttpClient.java +++ b/src/main/java/com/ning/http/client/SimpleAsyncHttpClient.java @@ -29,6 +29,7 @@ import com.ning.http.client.resumable.ResumableIOExceptionFilter; import com.ning.http.client.simple.HeaderMap; import com.ning.http.client.simple.SimpleAHCTransferListener; +import com.ning.http.client.uri.UriComponents; /** * Simple implementation of {@link AsyncHttpClient} and it's related builders ({@link com.ning.http.client.AsyncHttpClientConfig}, @@ -276,7 +277,7 @@ private Future execute(RequestBuilder rb, BodyConsumer bodyConsumer, T } Request request = rb.build(); - ProgressAsyncHandler handler = new BodyConsumerAsyncHandler(bodyConsumer, throwableHandler, errorDocumentBehaviour, request.getUrl(), listener); + ProgressAsyncHandler handler = new BodyConsumerAsyncHandler(bodyConsumer, throwableHandler, errorDocumentBehaviour, request.getURI(), listener); if (resumeEnabled && request.getMethod().equals("GET") && bodyConsumer != null && bodyConsumer instanceof ResumableBodyConsumer) { @@ -715,7 +716,7 @@ private final static class BodyConsumerAsyncHandler extends AsyncCompletionHandl private final BodyConsumer bodyConsumer; private final ThrowableHandler exceptionHandler; private final ErrorDocumentBehaviour errorDocumentBehaviour; - private final String url; + private final UriComponents uri; private final SimpleAHCTransferListener listener; private boolean accumulateBody = false; @@ -723,11 +724,11 @@ private final static class BodyConsumerAsyncHandler extends AsyncCompletionHandl private int amount = 0; private long total = -1; - public BodyConsumerAsyncHandler(BodyConsumer bodyConsumer, ThrowableHandler exceptionHandler, ErrorDocumentBehaviour errorDocumentBehaviour, String url, SimpleAHCTransferListener listener) { + public BodyConsumerAsyncHandler(BodyConsumer bodyConsumer, ThrowableHandler exceptionHandler, ErrorDocumentBehaviour errorDocumentBehaviour, UriComponents uri, SimpleAHCTransferListener listener) { this.bodyConsumer = bodyConsumer; this.exceptionHandler = exceptionHandler; this.errorDocumentBehaviour = errorDocumentBehaviour; - this.url = url; + this.uri = uri; this.listener = listener; } @@ -828,13 +829,13 @@ private void calculateTotal(HttpResponseHeaders headers) { @Override public STATE onContentWriteProgress(long amount, long current, long total) { - fireSent(url, amount, current, total); + fireSent(uri, amount, current, total); return super.onContentWriteProgress(amount, current, total); } private void fireStatus(HttpResponseStatus status) { if (listener != null) { - listener.onStatus(url, status.getStatusCode(), status.getStatusText()); + listener.onStatus(uri, status.getStatusCode(), status.getStatusText()); } } @@ -844,27 +845,26 @@ private void fireReceived(HttpResponseBodyPart content) { amount += remaining; if (listener != null) { - listener.onBytesReceived(url, amount, remaining, total); + listener.onBytesReceived(uri, amount, remaining, total); } } private void fireHeaders(HttpResponseHeaders headers) { if (listener != null) { - listener.onHeaders(url, new HeaderMap(headers.getHeaders())); + listener.onHeaders(uri, new HeaderMap(headers.getHeaders())); } } - private void fireSent(String url, long amount, long current, long total) { + private void fireSent(UriComponents uri, long amount, long current, long total) { if (listener != null) { - listener.onBytesSent(url, amount, current, total); + listener.onBytesSent(uri, amount, current, total); } } private void fireCompleted(Response response) { if (listener != null) { - listener.onCompleted(url, response.getStatusCode(), response.getStatusText()); + listener.onCompleted(uri, response.getStatusCode(), response.getStatusText()); } } } - } 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 25b951afb3..976e305cb2 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 @@ -250,7 +250,7 @@ private HttpMethodBase createMethod(HttpClient client, Request request) throws I String methodName = request.getMethod(); HttpMethodBase method = null; if (methodName.equalsIgnoreCase("POST") || methodName.equalsIgnoreCase("PUT")) { - EntityEnclosingMethod post = methodName.equalsIgnoreCase("POST") ? new PostMethod(request.getUrl()) : new PutMethod(request.getUrl()); + EntityEnclosingMethod post = methodName.equalsIgnoreCase("POST") ? new PostMethod(request.getURI().toUrl()) : new PutMethod(request.getURI().toUrl()); String bodyCharset = request.getBodyEncoding() == null ? DEFAULT_CHARSET : request.getBodyEncoding(); @@ -346,13 +346,13 @@ private HttpMethodBase createMethod(HttpClient client, Request request) throws I } method = post; } else if (methodName.equalsIgnoreCase("DELETE")) { - method = new DeleteMethod(request.getUrl()); + method = new DeleteMethod(request.getURI().toUrl()); } else if (methodName.equalsIgnoreCase("HEAD")) { - method = new HeadMethod(request.getUrl()); + method = new HeadMethod(request.getURI().toUrl()); } else if (methodName.equalsIgnoreCase("GET")) { - method = new GetMethod(request.getUrl()); + method = new GetMethod(request.getURI().toUrl()); } else if (methodName.equalsIgnoreCase("OPTIONS")) { - method = new OptionsMethod(request.getUrl()); + method = new OptionsMethod(request.getURI().toUrl()); } else { throw new IllegalStateException(String.format("Invalid Method", methodName)); } 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 3c28f1d195..c42c150cce 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 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; +import static com.ning.http.util.AsyncHttpProviderUtils.getNonEmptyPath; import static com.ning.http.util.MiscUtils.isNonEmpty; import java.io.ByteArrayOutputStream; @@ -592,7 +593,7 @@ static final class HttpTransactionContext { final GrizzlyAsyncHttpProvider provider; Request request; - String requestUrl; + UriComponents requestUri; AsyncHandler handler; BodyHandler bodyHandler; StatusHandler statusHandler; @@ -604,7 +605,7 @@ static final class HttpTransactionContext { AtomicLong totalBodyWritten = new AtomicLong(); AsyncHandler.STATE currentState; - String wsRequestURI; + UriComponents wsRequestURI; boolean isWSRequest; HandShake handshake; ProtocolHandler protocolHandler; @@ -663,7 +664,7 @@ static HttpTransactionContext get(final Connection c) { this.handler = handler; redirectsAllowed = provider.clientConfig.isFollowRedirect(); maxRedirectCount = provider.clientConfig.getMaxRedirects(); - this.requestUrl = request.getUrl(); + this.requestUri = request.getURI(); } @@ -838,7 +839,7 @@ private boolean sendAsGrizzlyRequest(final Request request, final Connection connection = ctx.getConnection(); final HttpTransactionContext httpCtx = HttpTransactionContext.get(connection); - if (isUpgradeRequest(httpCtx.handler) && isWSRequest(httpCtx.requestUrl)) { + if (isUpgradeRequest(httpCtx.handler) && isWSRequest(httpCtx.requestUri)) { httpCtx.isWSRequest = true; convertToUpgradeRequest(httpCtx); } @@ -868,12 +869,12 @@ private boolean sendAsGrizzlyRequest(final Request request, builder.method(Method.CONNECT); builder.uri(AsyncHttpProviderUtils.getAuthority(uri)); } else if (secure && config.isUseRelativeURIsWithSSLProxies()){ - builder.uri(uri.getPath()); + builder.uri(getNonEmptyPath(uri)); } else { builder.uri(uri.toUrl()); } } else { - builder.uri(uri.getPath()); + builder.uri(getNonEmptyPath(uri)); } final BodyHandler bodyHandler = isPayloadAllowed(method) ? @@ -893,7 +894,7 @@ private boolean sendAsGrizzlyRequest(final Request request, HttpRequestPacket requestPacket; if (httpCtx.isWSRequest && !httpCtx.establishingTunnel) { try { - final URI wsURI = new URI(httpCtx.wsRequestURI); + final URI wsURI = httpCtx.wsRequestURI.toURI(); secure = "wss".equalsIgnoreCase(wsURI.getScheme()); httpCtx.protocolHandler = Version.RFC6455.createHandler(true); httpCtx.handshake = httpCtx.protocolHandler.createHandShake(wsURI); @@ -1001,22 +1002,17 @@ private boolean isUpgradeRequest(final AsyncHandler handler) { } - private boolean isWSRequest(final String requestUri) { - return (requestUri.charAt(0) == 'w' && requestUri.charAt(1) == 's'); + private boolean isWSRequest(final UriComponents requestUri) { + return requestUri.getScheme().startsWith("ws"); } private void convertToUpgradeRequest(final HttpTransactionContext ctx) { - final int colonIdx = ctx.requestUrl.indexOf(':'); + UriComponents originalUri = ctx.requestUri; + String newScheme = originalUri.getScheme().equalsIgnoreCase("https") ? "wss" : "ws"; - if (colonIdx < 2 || colonIdx > 3) { - throw new IllegalArgumentException("Invalid websocket URL: " + ctx.requestUrl); - } - - final StringBuilder sb = new StringBuilder(ctx.requestUrl); - sb.replace(0, colonIdx, ((colonIdx == 2) ? "http" : "https")); - ctx.wsRequestURI = ctx.requestUrl; - ctx.requestUrl = sb.toString(); + ctx.wsRequestURI = originalUri; + ctx.requestUri = originalUri.withNewScheme(newScheme); } private void addHeaders(final Request request, @@ -1690,7 +1686,7 @@ public boolean handleStatus(final HttpResponsePacket responsePacket, httpTransactionContext.future = null; newContext.invocationStatus = InvocationStatus.CONTINUE; newContext.request = requestToSend; - newContext.requestUrl = requestToSend.getUrl(); + newContext.requestUri = requestToSend.getURI(); HttpTransactionContext.set(c, newContext); httpTransactionContext.provider.execute(c, requestToSend, 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 71f27489d2..f853160cac 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 @@ -181,7 +181,7 @@ private HttpURLConnection createUrlConnection(Request request) throws IOExceptio HttpURLConnection urlConnection = (HttpURLConnection) request.getURI().toURI().toURL().openConnection(proxy == null ? Proxy.NO_PROXY : proxy); - if (request.getUrl().startsWith("https")) { + if (request.getURI().getScheme().equals("https")) { HttpsURLConnection secure = (HttpsURLConnection) urlConnection; SSLContext sslContext = config.getSSLContext(); if (sslContext == null) { @@ -285,11 +285,11 @@ public T call() throws Exception { if (statusCode == 401 && !isAuth.getAndSet(true) && realm != null) { String wwwAuth = urlConnection.getHeaderField("WWW-Authenticate"); - logger.debug("Sending authentication to {}", request.getUrl()); + logger.debug("Sending authentication to {}", request.getURI()); Realm nr = new Realm.RealmBuilder().clone(realm) .parseWWWAuthenticateHeader(wwwAuth) - .setUri(UriComponents.create(request.getUrl())) + .setUri(request.getURI()) .setMethodName(request.getMethod()) .setUsePreemptiveAuth(true) .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 2691741d6d..7e9f6fb82c 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 @@ -28,6 +28,7 @@ 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.AsyncHttpProviderUtils.getNonEmptyPath; import static com.ning.http.util.MiscUtils.isNonEmpty; import static org.jboss.netty.channel.Channels.pipeline; import static org.jboss.netty.handler.ssl.SslHandler.getDefaultBufferPool; @@ -657,10 +658,10 @@ private static SpnegoEngine getSpnegoEngine() { private static String computeNonConnectRequestPath(AsyncHttpClientConfig config, UriComponents uri, ProxyServer proxyServer) { if (proxyServer != null && !(isSecure(uri) && config.isUseRelativeURIsWithSSLProxies())) return uri.toString(); - else if (uri.getQuery() != null) - return uri.getPath() + "?" + uri.getQuery(); - else - return uri.getPath(); + else { + String path = getNonEmptyPath(uri); + return uri.getQuery() != null ? path + "?" + uri.getQuery() : path; + } } private static HttpRequest construct(AsyncHttpClientConfig config, Request request, HttpMethod m, UriComponents uri, ChannelBuffer buffer, ProxyServer proxyServer) throws IOException { 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 a928b93dd5..6b11ce45dc 100644 --- a/src/main/java/com/ning/http/client/resumable/ResumableAsyncHandler.java +++ b/src/main/java/com/ning/http/client/resumable/ResumableAsyncHandler.java @@ -104,7 +104,7 @@ public ResumableAsyncHandler(ResumableProcessor resumableProcessor, boolean accu public AsyncHandler.STATE onStatusReceived(final HttpResponseStatus status) throws Exception { responseBuilder.accumulate(status); if (status.getStatusCode() == 200 || status.getStatusCode() == 206) { - url = status.getUri().toString(); + url = status.getUri().toUrl(); } else { return AsyncHandler.STATE.ABORT; } @@ -198,8 +198,8 @@ public AsyncHandler.STATE onHeadersReceived(HttpResponseHeaders headers) throws */ public Request adjustRequestRange(Request request) { - if (resumableIndex.get(request.getUrl()) != null) { - byteTransferred.set(resumableIndex.get(request.getUrl())); + if (resumableIndex.get(request.getURI().toUrl()) != null) { + byteTransferred.set(resumableIndex.get(request.getURI().toUrl())); } // The Resumbale diff --git a/src/main/java/com/ning/http/client/simple/SimpleAHCTransferListener.java b/src/main/java/com/ning/http/client/simple/SimpleAHCTransferListener.java index 726e770043..b25aa8eeaa 100644 --- a/src/main/java/com/ning/http/client/simple/SimpleAHCTransferListener.java +++ b/src/main/java/com/ning/http/client/simple/SimpleAHCTransferListener.java @@ -14,6 +14,7 @@ */ import com.ning.http.client.SimpleAsyncHttpClient; +import com.ning.http.client.uri.UriComponents; /** * A simple transfer listener for use with the {@link SimpleAsyncHttpClient}. @@ -33,47 +34,47 @@ public interface SimpleAHCTransferListener { * @param statusCode the received status code. * @param statusText the received status text. */ - void onStatus(String url, int statusCode, String statusText); + void onStatus(UriComponents uri, int statusCode, String statusText); /** * This method is called after the response headers are received. * - * @param url the url for the connection. + * @param uri the uri * @param headers the received headers, never {@code null}. */ - void onHeaders(String url, HeaderMap headers); + void onHeaders(UriComponents uri, HeaderMap headers); /** * This method is called when bytes of the responses body are received. * - * @param url the url for the connection. + * @param uri the uri * @param amount the number of transferred bytes so far. * @param current the number of transferred bytes since the last call to this * method. * @param total the total number of bytes to be transferred. This is taken * from the Content-Length-header and may be unspecified (-1). */ - void onBytesReceived(String url, long amount, long current, long total); + void onBytesReceived(UriComponents uri, long amount, long current, long total); /** * This method is called when bytes are sent. * - * @param url the url for the connection. + * @param uri the uri * @param amount the number of transferred bytes so far. * @param current the number of transferred bytes since the last call to this * method. * @param total the total number of bytes to be transferred. This is taken * from the Content-Length-header and may be unspecified (-1). */ - void onBytesSent(String url, long amount, long current, long total); + void onBytesSent(UriComponents uri, long amount, long current, long total); /** * This method is called when the request is completed. * - * @param url the url for the connection. + * @param uri the uri * @param statusCode the received status code. * @param statusText the received status text. */ - void onCompleted(String url, int statusCode, String statusText); + void onCompleted(UriComponents uri, int statusCode, String statusText); } diff --git a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java index 8f6a474574..3d33f5f1d8 100644 --- a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java +++ b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java @@ -57,22 +57,6 @@ public static final void validateSupportedScheme(UriComponents uri) { } } - public final static UriComponents createNonEmptyPathURI(String u) { - UriComponents uri = UriComponents.create(u); - validateSupportedScheme(uri); - - String path = uri.getPath(); - if (path == null) { - throw new IllegalArgumentException("The URI path, of the URI " + uri + ", must be non-null"); - } else if (isNonEmpty(path) && path.charAt(0) != '/') { - throw new IllegalArgumentException("The URI path, of the URI " + uri + ". must start with a '/'"); - } else if (!isNonEmpty(path)) { - return UriComponents.create(u + "/"); - } - - return uri; - } - public final static String getBaseUrl(UriComponents uri) { return uri.getScheme() + "://" + getAuthority(uri); } @@ -118,6 +102,15 @@ public final static int getDefaultPort(UriComponents uri) { return port; } + /** + * Convenient for HTTP layer when targeting server root + * + * @return the raw path or "/" if it's null + */ + public final static String getNonEmptyPath(UriComponents uri) { + return isNonEmpty(uri.getPath()) ? uri.getPath() : "/"; + } + /** * This is quite ugly as our internal names are duplicated, but we build on top of HTTP Client implementation. * diff --git a/src/main/java/com/ning/http/util/AuthenticatorUtils.java b/src/main/java/com/ning/http/util/AuthenticatorUtils.java index 8071ac7d1d..d38baadc89 100644 --- a/src/main/java/com/ning/http/util/AuthenticatorUtils.java +++ b/src/main/java/com/ning/http/util/AuthenticatorUtils.java @@ -12,6 +12,7 @@ */ package com.ning.http.util; +import static com.ning.http.util.AsyncHttpProviderUtils.getNonEmptyPath; import static com.ning.http.util.MiscUtils.isNonEmpty; import com.ning.http.client.ProxyServer; @@ -39,7 +40,7 @@ private static String computeRealmURI(Realm realm) { if (realm.isUseAbsoluteURI()) { return omitQuery ? uri.withNewQuery(null).toUrl() : uri.toUrl(); } else { - String path = uri.getPath(); + String path = getNonEmptyPath(uri); return omitQuery ? path : path + "?" + uri.getQuery(); } } 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 bbd501eeae..6f28bf1ecb 100755 --- a/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java +++ b/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java @@ -70,7 +70,7 @@ public void asyncProviderEncodingTest() throws Throwable { AsyncHttpClient client = getAsyncHttpClient(null); try { Request request = new RequestBuilder("GET").setUrl(getTargetUrl() + "?q=+%20x").build(); - String requestUrl = request.getUrl(); + String requestUrl = request.getURI().toUrl(); Assert.assertEquals(requestUrl, getTargetUrl() + "?q=%20%20x"); Future responseFuture = client.executeRequest(request, new AsyncCompletionHandler() { @Override diff --git a/src/test/java/com/ning/http/client/async/RequestBuilderTest.java b/src/test/java/com/ning/http/client/async/RequestBuilderTest.java index b73f08a5c1..669f3d0422 100644 --- a/src/test/java/com/ning/http/client/async/RequestBuilderTest.java +++ b/src/test/java/com/ning/http/client/async/RequestBuilderTest.java @@ -72,7 +72,7 @@ public void testEncodesQueryParameters() throws UnsupportedEncodingException { } String expValue = sb.toString(); Request request = builder.build(); - assertEquals(request.getUrl(), "http://example.com/?name=" + expValue); + assertEquals(request.getURI().toUrl(), "http://example.com/?name=" + expValue); } } @@ -85,7 +85,7 @@ public void testChaining() throws IOException, ExecutionException, InterruptedEx Request request2 = new RequestBuilder(request).build(); - assertEquals(request2.getUrl(), request.getUrl()); + assertEquals(request2.getURI(), request.getURI()); } @Test(groups = {"standalone", "default_provider"}) @@ -95,7 +95,7 @@ public void testParsesQueryParams() throws IOException, ExecutionException, Inte .addQueryParam("param2", "value2") .build(); - assertEquals(request.getUrl(), "http://foo.com/?param1=value1¶m2=value2"); + assertEquals(request.getURI().toUrl(), "http://foo.com/?param1=value1¶m2=value2"); List params = request.getQueryParams(); assertEquals(params.size(), 2); assertEquals(params.get(0), new Param("param1", "value1")); @@ -106,14 +106,14 @@ public void testParsesQueryParams() throws IOException, ExecutionException, Inte public void testUserProvidedRequestMethod() { Request req = new RequestBuilder("ABC").setUrl("http://foo.com").build(); assertEquals(req.getMethod(), "ABC"); - assertEquals(req.getUrl(), "http://foo.com"); + assertEquals(req.getURI().toUrl(), "http://foo.com"); } @Test(groups = {"standalone", "default_provider"}) public void testPercentageEncodedUserInfo() { final Request req = new RequestBuilder("GET").setUrl("http://hello:wor%20ld@foo.com").build(); assertEquals(req.getMethod(), "GET"); - assertEquals(req.getUrl(), "http://hello:wor%20ld@foo.com"); + assertEquals(req.getURI().toUrl(), "http://hello:wor%20ld@foo.com"); } @Test(groups = {"standalone", "default_provider"}) @@ -130,7 +130,7 @@ public void testAddQueryParameter() throws UnsupportedEncodingException { .addQueryParam("a", "1?&") .addQueryParam("b", "+ ="); Request request = rb.build(); - assertEquals(request.getUrl(), "http://example.com/path?a=1%3F%26&b=%2B%20%3D"); + assertEquals(request.getURI().toUrl(), "http://example.com/path?a=1%3F%26&b=%2B%20%3D"); } @Test(groups = {"standalone", "default_provider"}) @@ -138,7 +138,6 @@ public void testRawUrlQuery() throws UnsupportedEncodingException, URISyntaxExce String preEncodedUrl = "http://example.com/space%20mirror.php?%3Bteile"; RequestBuilder rb = new RequestBuilder("GET", true).setUrl(preEncodedUrl); Request request = rb.build(); - assertEquals(request.getUrl(), preEncodedUrl); assertEquals(request.getURI().toUrl(), preEncodedUrl); assertEquals(request.getURI().toURI().toString(), preEncodedUrl); } 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 f2874cf73c..73c306aadc 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 com.ning.http.client.uri.UriComponents; import org.testng.annotations.Test; @@ -28,7 +29,6 @@ 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; @@ -171,30 +171,30 @@ public void testSimpleTransferListener() throws Exception { SimpleAHCTransferListener listener = new SimpleAHCTransferListener() { - public void onStatus(String url, int statusCode, String statusText) { + public void onStatus(UriComponents uri, int statusCode, String statusText) { assertEquals(statusCode, 200); - assertEquals(url, getTargetUrl()); + assertEquals(uri.toUrl(), getTargetUrl()); } - public void onHeaders(String url, HeaderMap headers) { - assertEquals(url, getTargetUrl()); + public void onHeaders(UriComponents uri, HeaderMap headers) { + assertEquals(uri.toUrl(), getTargetUrl()); assertNotNull(headers); assertTrue(!headers.isEmpty()); assertEquals(headers.getFirstValue("X-Custom"), "custom"); } - public void onCompleted(String url, int statusCode, String statusText) { + public void onCompleted(UriComponents uri, int statusCode, String statusText) { assertEquals(statusCode, 200); - assertEquals(url, getTargetUrl()); + assertEquals(uri.toUrl(), getTargetUrl()); } - public void onBytesSent(String url, long amount, long current, long total) { - assertEquals(url, getTargetUrl()); + public void onBytesSent(UriComponents uri, long amount, long current, long total) { + assertEquals(uri.toUrl(), getTargetUrl()); assertEquals(total, MY_MESSAGE.getBytes().length); } - public void onBytesReceived(String url, long amount, long current, long total) { - assertEquals(url, getTargetUrl()); + public void onBytesReceived(UriComponents uri, long amount, long current, long total) { + assertEquals(uri.toUrl(), getTargetUrl()); assertEquals(total, -1); } }; diff --git a/src/test/java/com/ning/http/client/resumable/ResumableAsyncHandlerTest.java b/src/test/java/com/ning/http/client/resumable/ResumableAsyncHandlerTest.java index 8c9160eb37..3b620df322 100644 --- a/src/test/java/com/ning/http/client/resumable/ResumableAsyncHandlerTest.java +++ b/src/test/java/com/ning/http/client/resumable/ResumableAsyncHandlerTest.java @@ -32,13 +32,13 @@ public void testAdjustRange() { ResumableAsyncHandler h = new ResumableAsyncHandler(proc); Request request = new RequestBuilder("GET").setUrl("http://test/url").build(); Request newRequest = h.adjustRequestRange(request); - assertEquals(newRequest.getUrl(), request.getUrl()); + assertEquals(newRequest.getURI(), request.getURI()); String rangeHeader = newRequest.getHeaders().getFirstValue("Range"); assertNull(rangeHeader); proc.put("http://test/url", 5000); newRequest = h.adjustRequestRange(request); - assertEquals(newRequest.getUrl(), request.getUrl()); + assertEquals(newRequest.getURI(), request.getURI()); rangeHeader = newRequest.getHeaders().getFirstValue("Range"); assertEquals(rangeHeader, "bytes=5000-"); } From 5914bc37ebc4d8f34131659ad1ebb471158e5774 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 9 Jul 2014 23:06:39 +0200 Subject: [PATCH 374/701] Disable GrizzlyProxyTunnellingTest for now, see #608 --- .../client/websocket/grizzly/GrizzlyProxyTunnellingTest.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/test/java/com/ning/http/client/websocket/grizzly/GrizzlyProxyTunnellingTest.java b/src/test/java/com/ning/http/client/websocket/grizzly/GrizzlyProxyTunnellingTest.java index d76c131944..cb6251e6b9 100644 --- a/src/test/java/com/ning/http/client/websocket/grizzly/GrizzlyProxyTunnellingTest.java +++ b/src/test/java/com/ning/http/client/websocket/grizzly/GrizzlyProxyTunnellingTest.java @@ -26,4 +26,9 @@ public class GrizzlyProxyTunnellingTest extends ProxyTunnellingTest { public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { return ProviderUtil.grizzlyProvider(config); } + + @Test(timeOut = 60000, enabled = false) + public void echoText() throws Exception { + // FIXME + } } From b66218f787df992e0cfa8410886f4f6182338e61 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 9 Jul 2014 23:46:36 +0200 Subject: [PATCH 375/701] Backport Netty proxy authentication support to 1.9, cose #609 --- src/main/java/com/ning/http/client/Realm.java | 13 +++++++++++++ .../providers/netty/NettyAsyncHttpProvider.java | 9 ++++++++- .../com/ning/http/client/uri/UriComponents.java | 9 +++++++++ 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/ning/http/client/Realm.java b/src/main/java/com/ning/http/client/Realm.java index 4163432c7e..9ccc8020ea 100644 --- a/src/main/java/com/ning/http/client/Realm.java +++ b/src/main/java/com/ning/http/client/Realm.java @@ -467,6 +467,19 @@ public RealmBuilder parseWWWAuthenticateHeader(String headerLine) { return this; } + public RealmBuilder parseProxyAuthenticateHeader(String headerLine) { + setRealmName(match(headerLine, "realm")); + setNonce(match(headerLine, "nonce")); + setOpaque(match(headerLine, "opaque")); + setQop(match(headerLine, "qop")); + if (isNonEmpty(getNonce())) { + setScheme(AuthScheme.DIGEST); + } else { + setScheme(AuthScheme.BASIC); + } + return this; + } + public RealmBuilder setNtlmMessageType2Received(boolean messageType2Received) { this.messageType2Received = messageType2Received; return this; 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 7e9f6fb82c..1fc35f67ad 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 @@ -2118,7 +2118,14 @@ public Object call() throws Exception { if (newRealm == null) return; } else { - newRealm = future.getRequest().getRealm(); + newRealm = new Realm.RealmBuilder().clone(realm)// + .setScheme(realm.getAuthScheme())// + .setUri(request.getURI().withNewPath("/"))// + .setOmitQuery(true)// + .setMethodName("CONNECT")// + .setUsePreemptiveAuth(true)// + .parseProxyAuthenticateHeader(proxyAuth.get(0))// + .build(); } Request req = builder.setHeaders(headers).setRealm(newRealm).build(); diff --git a/src/main/java/com/ning/http/client/uri/UriComponents.java b/src/main/java/com/ning/http/client/uri/UriComponents.java index fff21ac7ab..4e41c97600 100644 --- a/src/main/java/com/ning/http/client/uri/UriComponents.java +++ b/src/main/java/com/ning/http/client/uri/UriComponents.java @@ -119,6 +119,15 @@ public UriComponents withNewScheme(String newScheme) { query); } + public UriComponents withNewPath(String newPath) { + return new UriComponents(scheme,// + userInfo,// + host,// + port,// + newPath,// + query); + } + public UriComponents withNewQuery(String newQuery) { return new UriComponents(scheme,// userInfo,// From 213ebc526a442d479ea9fb00175a357aff31f7d6 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 10 Jul 2014 05:43:36 +0200 Subject: [PATCH 376/701] Better proxy auth handling --- src/main/java/com/ning/http/client/Realm.java | 24 +++++++++++++++++-- .../netty/NettyAsyncHttpProvider.java | 4 ++-- .../ning/http/client/uri/UriComponents.java | 9 ------- .../ning/http/util/AuthenticatorUtils.java | 14 +++++++---- 4 files changed, 33 insertions(+), 18 deletions(-) diff --git a/src/main/java/com/ning/http/client/Realm.java b/src/main/java/com/ning/http/client/Realm.java index 9ccc8020ea..3d42e1afb0 100644 --- a/src/main/java/com/ning/http/client/Realm.java +++ b/src/main/java/com/ning/http/client/Realm.java @@ -50,6 +50,7 @@ public class Realm { private final boolean messageType2Received; private final boolean useAbsoluteURI; private final boolean omitQuery; + private final boolean targetProxy; private final String ntlmDomain; @@ -81,7 +82,8 @@ private Realm(AuthScheme scheme, boolean messageType2Received, String opaque, boolean useAbsoluteURI, - boolean omitQuery) { + boolean omitQuery, + boolean targetProxy) { this.principal = principal; this.password = password; @@ -103,6 +105,7 @@ private Realm(AuthScheme scheme, this.messageType2Received = messageType2Received; this.useAbsoluteURI = useAbsoluteURI; this.omitQuery = omitQuery; + this.targetProxy = targetProxy; } public String getPrincipal() { @@ -205,6 +208,10 @@ public boolean isOmitQuery() { return omitQuery; } + public boolean isTargetProxy() { + return targetProxy; + } + @Override public boolean equals(Object o) { if (this == o) return true; @@ -295,6 +302,7 @@ public static class RealmBuilder { private boolean messageType2Received = false; private boolean useAbsoluteURI = true; private boolean omitQuery = false; + private boolean targetProxy = false; public String getNtlmDomain() { return ntlmDomain; @@ -449,6 +457,15 @@ public RealmBuilder setOmitQuery(boolean omitQuery) { this.omitQuery = omitQuery; return this; } + + public boolean isTargetProxy() { + return targetProxy; + } + + public RealmBuilder setTargetProxy(boolean targetProxy) { + this.targetProxy = targetProxy; + return this; + } public RealmBuilder parseWWWAuthenticateHeader(String headerLine) { setRealmName(match(headerLine, "realm")); @@ -477,6 +494,7 @@ public RealmBuilder parseProxyAuthenticateHeader(String headerLine) { } else { setScheme(AuthScheme.BASIC); } + setTargetProxy(true); return this; } @@ -504,6 +522,7 @@ public RealmBuilder clone(Realm clone) { setNtlmMessageType2Received(clone.isNtlmMessageType2Received()); setUseAbsoluteURI(clone.isUseAbsoluteURI()); setOmitQuery(clone.isOmitQuery()); + setTargetProxy(clone.isTargetProxy()); return this; } @@ -657,7 +676,8 @@ public Realm build() { messageType2Received, opaque, useAbsoluteURI, - omitQuery); + omitQuery, + targetProxy); } } 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 1fc35f67ad..1dbb82abf8 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 @@ -2120,9 +2120,9 @@ public Object call() throws Exception { } else { newRealm = new Realm.RealmBuilder().clone(realm)// .setScheme(realm.getAuthScheme())// - .setUri(request.getURI().withNewPath("/"))// - .setOmitQuery(true)// + .setUri(request.getURI())// .setMethodName("CONNECT")// + .setTargetProxy(true)// .setUsePreemptiveAuth(true)// .parseProxyAuthenticateHeader(proxyAuth.get(0))// .build(); diff --git a/src/main/java/com/ning/http/client/uri/UriComponents.java b/src/main/java/com/ning/http/client/uri/UriComponents.java index 4e41c97600..fff21ac7ab 100644 --- a/src/main/java/com/ning/http/client/uri/UriComponents.java +++ b/src/main/java/com/ning/http/client/uri/UriComponents.java @@ -119,15 +119,6 @@ public UriComponents withNewScheme(String newScheme) { query); } - public UriComponents withNewPath(String newPath) { - return new UriComponents(scheme,// - userInfo,// - host,// - port,// - newPath,// - query); - } - public UriComponents withNewQuery(String newQuery) { return new UriComponents(scheme,// userInfo,// diff --git a/src/main/java/com/ning/http/util/AuthenticatorUtils.java b/src/main/java/com/ning/http/util/AuthenticatorUtils.java index d38baadc89..d15425b4c5 100644 --- a/src/main/java/com/ning/http/util/AuthenticatorUtils.java +++ b/src/main/java/com/ning/http/util/AuthenticatorUtils.java @@ -36,12 +36,16 @@ public static String computeBasicAuthentication(ProxyServer proxyServer) throws private static String computeRealmURI(Realm realm) { UriComponents uri = realm.getUri(); - boolean omitQuery = realm.isOmitQuery() && MiscUtils.isNonEmpty(uri.getQuery()); - if (realm.isUseAbsoluteURI()) { - return omitQuery ? uri.withNewQuery(null).toUrl() : uri.toUrl(); + if (realm.isTargetProxy()) { + return "/"; } else { - String path = getNonEmptyPath(uri); - return omitQuery ? path : path + "?" + uri.getQuery(); + boolean omitQuery = realm.isOmitQuery() && MiscUtils.isNonEmpty(uri.getQuery()); + if (realm.isUseAbsoluteURI()) { + return omitQuery ? uri.withNewQuery(null).toUrl() : uri.toUrl(); + } else { + String path = getNonEmptyPath(uri); + return omitQuery ? path : path + "?" + uri.getQuery(); + } } } From dc138e2f938b4542917a8871cf70ea3c821e147f Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 10 Jul 2014 05:45:50 +0200 Subject: [PATCH 377/701] Minor clean up --- .../ning/http/client/resumable/ResumableAsyncHandler.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) 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 6b11ce45dc..a788e3b346 100644 --- a/src/main/java/com/ning/http/client/resumable/ResumableAsyncHandler.java +++ b/src/main/java/com/ning/http/client/resumable/ResumableAsyncHandler.java @@ -198,8 +198,9 @@ public AsyncHandler.STATE onHeadersReceived(HttpResponseHeaders headers) throws */ public Request adjustRequestRange(Request request) { - if (resumableIndex.get(request.getURI().toUrl()) != null) { - byteTransferred.set(resumableIndex.get(request.getURI().toUrl())); + Long ri = resumableIndex.get(request.getURI().toUrl()); + if (ri != null) { + byteTransferred.set(ri); } // The Resumbale From 899fd7a6fc84d7f7a1a8ed64d5ded88117c11d64 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 10 Jul 2014 10:03:18 +0200 Subject: [PATCH 378/701] Move the hostname verification to after the SSL handshake has completed (Netty Only), back port #525 --- .../providers/netty/NettyConnectListener.java | 56 +++++--- .../http/client/async/BasicHttpsTest.java | 136 +++++++++++------- .../async/grizzly/GrizzlyBasicHttpsTest.java | 5 - 3 files changed, 122 insertions(+), 75 deletions(-) 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 de6ed82eb4..ca05843964 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 @@ -21,7 +21,7 @@ import com.ning.http.client.ProxyServer; import com.ning.http.client.Request; import com.ning.http.client.uri.UriComponents; -import com.ning.http.util.AllowAllHostnameVerifier; +import com.ning.http.util.Base64; import com.ning.http.util.ProxyUtils; import org.jboss.netty.buffer.ChannelBuffer; @@ -34,22 +34,21 @@ import org.slf4j.LoggerFactory; import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.SSLEngine; +import javax.net.ssl.SSLSession; import java.io.IOException; import java.net.ConnectException; -import java.net.InetSocketAddress; import java.nio.channels.ClosedChannelException; -import java.util.concurrent.atomic.AtomicBoolean; /** * Non Blocking connect. */ final class NettyConnectListener implements ChannelFutureListener { - private final static Logger logger = LoggerFactory.getLogger(NettyConnectListener.class); + private static final Logger LOGGER = LoggerFactory.getLogger(NettyConnectListener.class); private final AsyncHttpClientConfig config; private final NettyResponseFuture future; private final HttpRequest nettyRequest; - private final AtomicBoolean handshakeDone = new AtomicBoolean(false); private NettyConnectListener(AsyncHttpClientConfig config, NettyResponseFuture future) { @@ -66,38 +65,51 @@ public final void operationComplete(ChannelFuture f) throws Exception { if (f.isSuccess()) { Channel channel = f.getChannel(); channel.getPipeline().getContext(NettyAsyncHttpProvider.class).setAttachment(future); - SslHandler sslHandler = (SslHandler) channel.getPipeline().get(NettyAsyncHttpProvider.SSL_HANDLER); - if (!handshakeDone.getAndSet(true) && (sslHandler != null)) { - ((SslHandler) channel.getPipeline().get(NettyAsyncHttpProvider.SSL_HANDLER)).handshake().addListener(this); - return; - } - - HostnameVerifier v = config.getHostnameVerifier(); - 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())) { - throw new ConnectException("HostnameVerifier exception."); - } + final SslHandler sslHandler = (SslHandler) channel.getPipeline().get(NettyAsyncHttpProvider.SSL_HANDLER); + + final HostnameVerifier hostnameVerifier = config.getHostnameVerifier(); + if (hostnameVerifier != null && sslHandler != null) { + final String host = future.getURI().getHost(); + sslHandler.handshake().addListener(new ChannelFutureListener() { + @Override + public void operationComplete(ChannelFuture handshakeFuture) throws Exception { + if (handshakeFuture.isSuccess()) { + Channel channel = (Channel) handshakeFuture.getChannel(); + SSLEngine engine = sslHandler.getEngine(); + SSLSession session = engine.getSession(); + + LOGGER.debug("onFutureSuccess: session = {}, id = {}, isValid = {}, host = {}", session.toString(), + Base64.encode(session.getId()), session.isValid(), host); + if (!hostnameVerifier.verify(host, session)) { + ConnectException exception = new ConnectException("HostnameVerifier exception"); + future.abort(exception); + throw exception; + } else { + future.provider().writeRequest(channel, config, future); + } + } + } + }); + } else { + future.provider().writeRequest(f.getChannel(), config, future); } - future.provider().writeRequest(f.getChannel(), config, future); } else { Throwable cause = f.getCause(); boolean canRetry = future.canRetry(); - logger.debug("Trying to recover a dead cached channel {} with a retry value of {} ", f.getChannel(), canRetry); + LOGGER.debug("Trying to recover a dead cached channel {} with a retry value of {} ", f.getChannel(), canRetry); if (canRetry && cause != null && (NettyAsyncHttpProvider.abortOnDisconnectException(cause) || cause instanceof ClosedChannelException || future.getState() != NettyResponseFuture.STATE.NEW)) { - logger.debug("Retrying {} ", nettyRequest); + LOGGER.debug("Retrying {} ", nettyRequest); if (future.provider().remotelyClosed(f.getChannel(), future)) { return; } } - logger.debug("Failed to recover from exception: {} with channel {}", cause, f.getChannel()); + LOGGER.debug("Failed to recover from exception: {} with channel {}", cause, f.getChannel()); boolean printCause = f.getCause() != null && cause.getMessage() != null; ConnectException e = new ConnectException(printCause ? cause.getMessage() + " to " + future.getURI().toString() : future.getURI().toString()); 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 2d2c180fd2..24ef8052a5 100644 --- a/src/test/java/com/ning/http/client/async/BasicHttpsTest.java +++ b/src/test/java/com/ning/http/client/async/BasicHttpsTest.java @@ -18,6 +18,7 @@ import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClientConfig.Builder; import com.ning.http.client.Response; + import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.handler.AbstractHandler; @@ -34,16 +35,19 @@ import javax.net.ssl.SSLContext; import javax.net.ssl.SSLHandshakeException; import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; import javax.net.ssl.X509TrustManager; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; + import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.ConnectException; import java.net.ServerSocket; import java.net.URL; +import java.security.GeneralSecurityException; import java.security.KeyStore; import java.security.SecureRandom; import java.security.cert.CertificateException; @@ -207,7 +211,7 @@ public void setUpGlobal() throws Exception { @Test(groups = { "standalone", "default_provider" }) public void zeroCopyPostTest() throws Throwable { - final AsyncHttpClient client = getAsyncHttpClient(new Builder().setSSLContext(createSSLContext()).build()); + final AsyncHttpClient client = getAsyncHttpClient(new Builder().setSSLContext(createSSLContext(new AtomicBoolean(true))).build()); try { ClassLoader cl = getClass().getClassLoader(); // override system properties @@ -226,7 +230,7 @@ public void zeroCopyPostTest() throws Throwable { @Test(groups = { "standalone", "default_provider" }) public void multipleSSLRequestsTest() throws Throwable { - final AsyncHttpClient c = getAsyncHttpClient(new Builder().setSSLContext(createSSLContext()).build()); + final AsyncHttpClient c = getAsyncHttpClient(new Builder().setSSLContext(createSSLContext(new AtomicBoolean(true))).build()); try { String body = "hello there"; @@ -246,7 +250,7 @@ public void multipleSSLRequestsTest() throws Throwable { @Test(groups = { "standalone", "default_provider" }) public void multipleSSLWithoutCacheTest() throws Throwable { - final AsyncHttpClient c = getAsyncHttpClient(new Builder().setSSLContext(createSSLContext()).setAllowSslConnectionPool(false).build()); + final AsyncHttpClient c = getAsyncHttpClient(new Builder().setSSLContext(createSSLContext(new AtomicBoolean(true))).setAllowSslConnectionPool(false).build()); try { String body = "hello there"; c.preparePost(getTargetUrl()).setBody(body).setHeader("Content-Type", "text/html").execute(); @@ -262,55 +266,72 @@ public void multipleSSLWithoutCacheTest() throws Throwable { } @Test(groups = { "standalone", "default_provider" }) - public void reconnectsAfterFailedCertificationPath() throws Throwable { - final AsyncHttpClient c = getAsyncHttpClient(new Builder().setSSLContext(createSSLContext()).build()); + public void reconnectsAfterFailedCertificationPath() throws Exception { + + AtomicBoolean trust = new AtomicBoolean(false); + AsyncHttpClient c = getAsyncHttpClient(new Builder().setSSLContext(createSSLContext(trust)).build()); try { - final String body = "hello there"; + String body = "hello there"; - TRUST_SERVER_CERT.set(false); + // first request fails because server certificate is rejected + Throwable cause = null; try { - // 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); - } + c.preparePost(getTargetUrl()).setBody(body).setHeader("Content-Type", "text/html").execute().get(TIMEOUT, TimeUnit.SECONDS); + } catch (final ExecutionException e) { + cause = e.getCause(); + if (cause instanceof ConnectException) { + //assertNotNull(cause.getCause()); + assertTrue(cause.getCause() instanceof SSLHandshakeException, "Expected an SSLHandshakeException, got a " + cause.getCause()); + } else { + assertTrue(cause instanceof IOException, "Expected an IOException, got a " + cause); } + } catch (Exception e) { + System.err.println("WTF"+ e.getMessage()); + } + assertNotNull(cause); - 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 + trust.set(true); + 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 { c.close(); } } - private static SSLContext createSSLContext() { + private static KeyManager[] createKeyManagers() throws GeneralSecurityException, IOException { + InputStream keyStoreStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("ssltest-cacerts.jks"); + char[] keyStorePassword = "changeit".toCharArray(); + KeyStore ks = KeyStore.getInstance("JKS"); + ks.load(keyStoreStream, keyStorePassword); + assert(ks.size() > 0); + + // Set up key manager factory to use our key store + char[] certificatePassword = "changeit".toCharArray(); + KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); + kmf.init(ks, certificatePassword); + + // Initialize the SSLContext to work with our key managers. + return kmf.getKeyManagers(); + } + + private static TrustManager[] createTrustManagers() throws GeneralSecurityException, IOException { + InputStream keyStoreStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("ssltest-keystore.jks"); + char[] keyStorePassword = "changeit".toCharArray(); + KeyStore ks = KeyStore.getInstance("JKS"); + ks.load(keyStoreStream, keyStorePassword); + assert(ks.size() > 0); + + TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + tmf.init(ks); + return tmf.getTrustManagers(); + } + + public static SSLContext createSSLContext(AtomicBoolean trust) { try { - InputStream keyStoreStream = BasicHttpsTest.class.getResourceAsStream("ssltest-cacerts.jks"); - char[] keyStorePassword = "changeit".toCharArray(); - KeyStore ks = KeyStore.getInstance("JKS"); - ks.load(keyStoreStream, keyStorePassword); - - // Set up key manager factory to use our key store - char[] certificatePassword = "changeit".toCharArray(); - KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); - kmf.init(ks, certificatePassword); - - // Initialize the SSLContext to work with our key managers. - KeyManager[] keyManagers = kmf.getKeyManagers(); - TrustManager[] trustManagers = new TrustManager[] { DUMMY_TRUST_MANAGER }; + KeyManager[] keyManagers = createKeyManagers(); + TrustManager[] trustManagers = new TrustManager[] { dummyTrustManager(trust, (X509TrustManager) createTrustManagers()[0]) }; SecureRandom secureRandom = new SecureRandom(); SSLContext sslContext = SSLContext.getInstance("TLS"); @@ -322,20 +343,39 @@ private static SSLContext createSSLContext() { } } - private static final AtomicBoolean TRUST_SERVER_CERT = new AtomicBoolean(true); - private static final TrustManager DUMMY_TRUST_MANAGER = new X509TrustManager() { - public X509Certificate[] getAcceptedIssuers() { - return new X509Certificate[0]; + public static class DummyTrustManager implements X509TrustManager { + + private final X509TrustManager tm; + private final AtomicBoolean trust; + + public DummyTrustManager(final AtomicBoolean trust, final X509TrustManager tm) { + this.trust = trust; + this.tm = tm; } - public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { + @Override + public void checkClientTrusted(X509Certificate[] chain, String authType) + throws CertificateException { + tm.checkClientTrusted(chain, authType); } - public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { - if (!TRUST_SERVER_CERT.get()) { + @Override + public void checkServerTrusted(X509Certificate[] chain, String authType) + throws CertificateException { + if (!trust.get()) { throw new CertificateException("Server certificate not trusted."); } + tm.checkServerTrusted(chain, authType); } - }; + @Override + public X509Certificate[] getAcceptedIssuers() { + return tm.getAcceptedIssuers(); + } + } + + private static TrustManager dummyTrustManager(final AtomicBoolean trust, final X509TrustManager tm) { + return new DummyTrustManager(trust, tm); + + } } 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 2ebeedc182..19d2397199 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 @@ -24,9 +24,4 @@ public class GrizzlyBasicHttpsTest extends BasicHttpsTest { public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { return ProviderUtil.grizzlyProvider(config); } - - @Override - public void zeroCopyPostTest() throws Throwable { - super.zeroCopyPostTest(); // To change body of overridden methods use File | Settings | File Templates. - } } From a894583921c11c3b01f160ada36a8bb9d5158e96 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 10 Jul 2014 10:34:24 +0200 Subject: [PATCH 379/701] Use a hostname verifier that does hostname verification, backport #510, close #197 --- .../client/AsyncHttpClientConfigDefaults.java | 5 +- .../http/util/DefaultHostnameVerifier.java | 142 ++++++++++++++++++ .../com/ning/http/util/HostnameChecker.java | 27 ++++ .../ning/http/util/ProxyHostnameChecker.java | 83 ++++++++++ src/test/resources/ssltest-cacerts.jks | Bin 29888 -> 31507 bytes src/test/resources/ssltest-keystore.jks | Bin 1445 -> 2358 bytes 6 files changed, 255 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/ning/http/util/DefaultHostnameVerifier.java create mode 100644 src/main/java/com/ning/http/util/HostnameChecker.java create mode 100644 src/main/java/com/ning/http/util/ProxyHostnameChecker.java diff --git a/src/main/java/com/ning/http/client/AsyncHttpClientConfigDefaults.java b/src/main/java/com/ning/http/client/AsyncHttpClientConfigDefaults.java index e42674000b..d13b47ac45 100644 --- a/src/main/java/com/ning/http/client/AsyncHttpClientConfigDefaults.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClientConfigDefaults.java @@ -12,9 +12,10 @@ */ package com.ning.http.client; -import com.ning.http.util.AllowAllHostnameVerifier; import static com.ning.http.util.MiscUtils.getBoolean; +import com.ning.http.util.DefaultHostnameVerifier; + import javax.net.ssl.HostnameVerifier; public final class AsyncHttpClientConfigDefaults { @@ -118,6 +119,6 @@ public static boolean defaultRemoveQueryParamOnRedirect() { } public static HostnameVerifier defaultHostnameVerifier() { - return new AllowAllHostnameVerifier(); + return new DefaultHostnameVerifier(); } } diff --git a/src/main/java/com/ning/http/util/DefaultHostnameVerifier.java b/src/main/java/com/ning/http/util/DefaultHostnameVerifier.java new file mode 100644 index 0000000000..b33bd6e650 --- /dev/null +++ b/src/main/java/com/ning/http/util/DefaultHostnameVerifier.java @@ -0,0 +1,142 @@ +/* + * To the extent possible under law, Kevin Locke has waived all copyright and + * related or neighboring rights to this work. + *

    + * A legal description of this waiver is available in LICENSE.txt + */ +package com.ning.http.util; + +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.SSLPeerUnverifiedException; +import javax.net.ssl.SSLSession; +import javax.security.auth.kerberos.KerberosPrincipal; +import java.security.Principal; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Uses the internal HostnameChecker to verify the server's hostname matches with the + * certificate. This is a requirement for HTTPS, but the raw SSLEngine does not have + * this functionality. As such, it has to be added in manually. For a more complete + * description of hostname verification and why it's important, + * please read + * Fixing + * Hostname Verification. + *

    + * This code is based on Kevin Locke's guide . + *

    + */ +public class DefaultHostnameVerifier implements HostnameVerifier { + + private HostnameChecker checker; + + private HostnameVerifier extraHostnameVerifier; + + // Logger to log exceptions. + private static final Logger log = Logger.getLogger(DefaultHostnameVerifier.class.getName()); + + /** + * A hostname verifier that uses the {{sun.security.util.HostnameChecker}} under the hood. + */ + public DefaultHostnameVerifier() { + this.checker = new ProxyHostnameChecker(); + } + + /** + * A hostname verifier that takes an external hostname checker. Useful for testing. + * + * @param checker a hostnamechecker. + */ + public DefaultHostnameVerifier(HostnameChecker checker) { + this.checker = checker; + } + + /** + * A hostname verifier that falls back to another hostname verifier if not found. + * + * @param extraHostnameVerifier another hostname verifier. + */ + public DefaultHostnameVerifier(HostnameVerifier extraHostnameVerifier) { + this.checker = new ProxyHostnameChecker(); + this.extraHostnameVerifier = extraHostnameVerifier; + } + + /** + * A hostname verifier with a hostname checker, that falls back to another hostname verifier if not found. + * + * @param checker a custom HostnameChecker. + * @param extraHostnameVerifier another hostname verifier. + */ + public DefaultHostnameVerifier(HostnameChecker checker, HostnameVerifier extraHostnameVerifier) { + this.checker = checker; + this.extraHostnameVerifier = extraHostnameVerifier; + } + + /** + * Matches the hostname against the peer certificate in the session. + * + * @param hostname the IP address or hostname of the expected server. + * @param session the SSL session containing the certificates with the ACTUAL hostname/ipaddress. + * @return true if the hostname matches, false otherwise. + */ + private boolean hostnameMatches(String hostname, SSLSession session) { + log.log(Level.FINE, "hostname = {0}, session = {1}", new Object[] { hostname, Base64.encode(session.getId()) }); + + try { + final Certificate[] peerCertificates = session.getPeerCertificates(); + if (peerCertificates.length == 0) { + log.log(Level.FINE, "No peer certificates"); + return false; + } + + if (peerCertificates[0] instanceof X509Certificate) { + X509Certificate peerCertificate = (X509Certificate) peerCertificates[0]; + log.log(Level.FINE, "peerCertificate = {0}", peerCertificate); + try { + checker.match(hostname, peerCertificate); + // Certificate matches hostname if no exception is thrown. + return true; + } catch (CertificateException ex) { + log.log(Level.FINE, "Certificate does not match hostname", ex); + } + } else { + log.log(Level.FINE, "Peer does not have any certificates or they aren't X.509"); + } + return false; + } catch (SSLPeerUnverifiedException ex) { + log.log(Level.FINE, "Not using certificates for peers, try verifying the principal"); + try { + Principal peerPrincipal = session.getPeerPrincipal(); + log.log(Level.FINE, "peerPrincipal = {0}", peerPrincipal); + if (peerPrincipal instanceof KerberosPrincipal) { + return checker.match(hostname, (KerberosPrincipal) peerPrincipal); + } else { + log.log(Level.FINE, "Can't verify principal, not Kerberos"); + } + } catch (SSLPeerUnverifiedException ex2) { + // Can't verify principal, no principal + log.log(Level.FINE, "Can't verify principal, no principal", ex2); + } + return false; + } + } + + /** + * Verifies the hostname against the peer certificates in a session. Falls back to extraHostnameVerifier if + * there is no match. + * + * @param hostname the IP address or hostname of the expected server. + * @param session the SSL session containing the certificates with the ACTUAL hostname/ipaddress. + * @return true if the hostname matches, false otherwise. + */ + public boolean verify(String hostname, SSLSession session) { + if (hostnameMatches(hostname, session)) { + return true; + } else { + return extraHostnameVerifier != null && extraHostnameVerifier.verify(hostname, session); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/ning/http/util/HostnameChecker.java b/src/main/java/com/ning/http/util/HostnameChecker.java new file mode 100644 index 0000000000..1a02ddb660 --- /dev/null +++ b/src/main/java/com/ning/http/util/HostnameChecker.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) Will Sargent. 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.security.Principal; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; + +/** + * Hostname checker interface. + */ +public interface HostnameChecker { + + public void match(String hostname, X509Certificate peerCertificate) throws CertificateException; + + public boolean match(String hostname, Principal principal); +} diff --git a/src/main/java/com/ning/http/util/ProxyHostnameChecker.java b/src/main/java/com/ning/http/util/ProxyHostnameChecker.java new file mode 100644 index 0000000000..a7d0914004 --- /dev/null +++ b/src/main/java/com/ning/http/util/ProxyHostnameChecker.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) Will Sargent. 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.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.security.Principal; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; + +/** + * A HostnameChecker proxy. + */ +public class ProxyHostnameChecker implements HostnameChecker { + + public final static byte TYPE_TLS = 1; + + private final Object checker = getHostnameChecker(); + + public ProxyHostnameChecker() { + } + + private Object getHostnameChecker() { + final ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); + try { + final Class hostnameCheckerClass = (Class) classLoader.loadClass("sun.security.util.HostnameChecker"); + final Method instanceMethod = hostnameCheckerClass.getMethod("getInstance", Byte.TYPE); + return instanceMethod.invoke(null, TYPE_TLS); + } catch (ClassNotFoundException e) { + throw new IllegalStateException(e); + } catch (NoSuchMethodException e) { + throw new IllegalStateException(e); + } catch (InvocationTargetException e) { + throw new IllegalStateException(e); + } catch (IllegalAccessException e) { + throw new IllegalStateException(e); + } + } + + public void match(String hostname, X509Certificate peerCertificate) throws CertificateException { + try { + final Class hostnameCheckerClass = checker.getClass(); + final Method checkMethod = hostnameCheckerClass.getMethod("match", String.class, X509Certificate.class); + checkMethod.invoke(checker, hostname, peerCertificate); + } catch (NoSuchMethodException e) { + throw new IllegalStateException(e); + } catch (InvocationTargetException e) { + Throwable t = e.getCause(); + if (t instanceof CertificateException) { + throw (CertificateException) t; + } else { + throw new IllegalStateException(e); + } + } catch (IllegalAccessException e) { + throw new IllegalStateException(e); + } + } + + public boolean match(String hostname, Principal principal) { + try { + final Class hostnameCheckerClass = checker.getClass(); + final Method checkMethod = hostnameCheckerClass.getMethod("match", String.class, Principal.class); + return (Boolean) checkMethod.invoke(null, hostname, principal); + } catch (NoSuchMethodException e) { + throw new IllegalStateException(e); + } catch (InvocationTargetException e) { + throw new IllegalStateException(e); + } catch (IllegalAccessException e) { + throw new IllegalStateException(e); + } + } + +} diff --git a/src/test/resources/ssltest-cacerts.jks b/src/test/resources/ssltest-cacerts.jks index 9c1ffbe49a7b27a250fc7d00fedd45405744fc38..207b9646e63d85590d802ab896acf786224968df 100644 GIT binary patch delta 2136 zcmV-e2&ebJ=>e1W0Sx}_{_Ow&00IC203nm@ZXUC91g!$GA3Fq-b|en7AO~#+v$+zr z1hb6}Ed;Y~7fJ`S3?ga*v$-Bq1G9D{F$1#+D**+wrzc_qvkEY20+V(m4zs^CIs~(G zGCl*d`8n<%e*pjlb1`9a0003*`|*Li000F7FoFdBFb)O^D+U1s0V)C!0RaU71cC(W z*~~l$6FAW`zNu*l;7Vc4)2YZ>{B_X?4jlr()4-o>+4E|LK7+QSGGR}J5S(r5z*O1P zCh=|eOLJp3lhkeTf|$m({pQ!wAlP9>&{JdeXXtO*e=v!{@H+&yvLV4cDO|QD6v@B- zS?BRd$uYoPpi3SSL@M#@<+*JPGavmLm z+*7k;eW?~0bFYep4;ZUHC_py=JQm6Rgq%PaDj!{&h6=y*_B#kDgiKuZxi~x`^@Xui z?S4que`EE-CAXM&D#UHOa5-wnMq4%f(3E|OEhTF6`l%wL!pI_I0_NX_8K;8;YMSPK z7V{ycy_nXa5G-A--Xz*k{o3`Thie#1v2HZ&1)VYX{SfLQm^cNQ7WacoS5P!fTq0p!~&%MmL!x0nde|gHcxG?X3;-nYY=#OA%@USpC2k&9u z@oL>bk1Y5_PmHAtq6Z3*rq<9)V zwjq4H@MREXXW7T^j=PFm*uA#9?d!zuIVyd6?AIFDaBoTdFpy-f9CeXXpahwhb%E6~ zf3?^*G9SfNN7P90M}(g%C}w=AXlEKSnM;<6h`LUKQ%CF8t-*t?oh}O;8FME?hh%YX z2Fr}Jsf+4Wypu;PYGaOm9dM~o6-Sm*a~d!!VO*rh2{7(Kq%iH28D>TYqrO(0ypg$0 zp;n?1BD)gjz}#v;2-A^LeopUe&3Ov@e+edecOzp2t^p#fSxdae^omY)9j#rI>tk18;!1_u1s~;SDXazNBlB_8ivMQy+S^2LI zKl04hOb=?mY3R~3e{N<<&w!w4e|67Nt52a5w23VyUI*mv#sZz&WVA)N(Qck}?7}bI zYYiV@vln8UfV+Os8uywaGGhqAy`D+=Xmw;V*Ey3_t!KFa1{9dj^?X zU69)3O%Sta-6G@~_Zng5lxoOoc$t!fe|2O3L+76HW^rJJ7wq?3?0`Luf2hQ4nH`t@ z9JWP#lKS}BC}mMaeoYAy5-RQzUY5+|cF99KZ?P)%4n_$cVCDN)jC$-I8FjA7f=|Xt z7MvQ5MN_Lmg?>CHOSE~40lqn5jHfO%q%E0FCzKhsFH1iLwxh5XJL7j+4tuK-DX6nrKDsI4-Uf3!&iXGh{_OncH%6##(uafB&l(LPs5tKc-Zi(GX) za*i!{Q$*y>$K?jRDd=Rs8H1*CZ4_$Z3NPfid)&Y>PYa$l%gJOWPS9+q&z){H&1_AW z1}H}-&30nzlE`8Y^U8D(VK2cs0000100mesH842<00ZwZf&=R?f&$Z^0|Eg80t8+a zL-jBX1_>&LNQU99p0pF*GnUGBq+YG&wObS{Ds8F)%nVIWjXeIWaL>lO9@| zlTcJ3f0YoJtkeO_^qYnWs6BrFHyQ^Zhm}eUqv-k+!Eoa&;9y1-_qfsGzCe4`VPFo1 zJ9%Mvt*-AbU+U)d+F&grc%4F(A+hDe6@4FLfQ1potr0RaFeW!p)TF@tV?WDRoW zK>7i%VKCtOI@c1}Aa#KrD~kn$K{I`{f8s!yufhP=BjrJeYlR-&^7WppCkS31JFJRb zK)x!#m0kDS#cPJ3BbLv9l!bG4wf zU=b2&Om2e#%&HEIKba-A1)@1FCpeumb)6}AesK?5MoKXo3~O_4l~ofAG@aHPgc14v zadvXL O?b_CY5k7ykl~;#8!Ou+q delta 490 zcmV0<(4`F$1%xEMfz*rzZggvkEY20<*g|J_D0>Bo4EI zGCBma`8n<%H39$xb1`9a0003KMws7<00mesH842<00O2kf&!v2f&vQy1V(sy3NQ@@ z2`Yw2hW8Bt0R)pPU!WW?H!wCbFfcGQH!wC@7Y#8tFg7taFfcSXFg99~Enl0H!5AEW zpFMG)NN$(T-X zPQeREhU(uBk=G81qbg|xsH;nOzC7Up^OIc}7=M!|SUbwlUk`QK#pEj)I$RTLZt#8O zUu|QXr$0vJ~UdDtqZpSUhS2_OO#3?BaZW|8g? gC;^?b`eFqb6fPVE^vo_bj)tUd3Gz$n_3$_xF8Gl6k@+kNK00jatf&~6B4h9M<1_1;CDgqG!0R;dAf&}XJ>~=6H z{?54uFOE?Pfak5_5v1{~(+-60dA=Ekw(Nr_x>VN;LbpDJICS=T7@FCZaR#++7Q#t+iX^+a&6ae}7_1xl_AQTvsvWPoq0M zy^%Db!^Z@dtg+zH;lakZb_@n;eV@e11K4pw3W6{tg5m-OaDPY>jUQtIdwZD%%bXMyQ^Y!gxD%G$2H61R1LO^!k9O8a38es@fqJ>1 zz3k28f8wI-0aN-HQtdM8~vY%>RPd#Q-8=3M&;hVN07qg@%nRjU3?4E zH1!P}kAkV%Kz)1~Suj`pdha|~@;Pv%eWV zb32l%)qj}Du~*-=X2>6DwcZTQ;F;pxOfbQ%#|diq{+l;2?H=&7T1-f4(7G_7 zR^&cOtoFzwBY#RWld+9wnYxk0*1Nc^~5~#JC0|yzNF%gnHjXXyCBM=pXOL1l# zWPbzZ`>k?{8m&~hZ_$3$(h(7v^1qv`)Mk%i468Fp1nyG6;b3Y7J*~?lw^l+HS0+kO zzwzs%x;e(l^jql!WbIs#(BS!#2A4^;93v-MtX#M4u3ypt^vQJiYJ9WSZZ+4(_x$B7 zB6qHzVI66Gm^GhiQ06~xC*t#ZH=LA*oqy;>(Ieb_4vn)~(lUQuv~+SpGE6z@qK9U33TGtvBN9t!^R_x|;Utyg+Al6%cg93V$`U`1o2*v{fMz_0Q_k zc!KvnaWk0)?Pm3Bd?7=`f@Ni*3`*RACAMKUYB8=f7htv6!&}DW*7)xOlR+(Q!zU`?R@8`tS z@${}B5FYd7zO{?sG6+)MVYh}}mwy>bdzoW;W!}AbwGmc){5Q2K1ISkzSs9`G!~gw^ zSmDphS-Cu7O2Leq$dcv&q7u8GhfF1Lj<=Y>;Zy}f^yVI>-N7D$tCZs#R9FO0z=i&v z&A-ByGGg7vh*(~CGcEGbx?n#CD5jto!P;bE!5Tw-XFfs2kWJ40$H!h|DMTU$C`TvF zc4F(2$YKxk%5)H6FTptg000311z0XMFgXAK1Me_`1M4t?0@I)a0s#U71YQ+G^)L+v z2`Yw2hW8Bt0Sl7`1E3o*G%zzVH8L|aIWaL>7Y#HqFgP$dGBY$eF)@?D1Dt&LNQU9d(~lJ4u(5yU-J49aK#5m~Tw)QQoM&@wls8G{!K-6dc=HLU~R^54jpCojrdTD07VaPr|H+ z7D)^ixt%v;26;8#-45|G!R_0wH5Br zXm4|LhXj8B00A%^1_Mw;>X-wR}hP68vtQN zHCOAV-#Cw))g(@PSyw}D6C`uBptN8S5@}3sg8|H{4vasUCANPBqB$-nIGrj9I)c^!5~T}}8GjQ-n9;8Q00O!&f&#WM4h9M<1_1;CDgqG!0R;dAf&!xSe|z@m zT2)yVJKij1+zxRUtz?efkb^IV&wtk$`K-&R%t75YuwdHpj}iB_2jil@Uc2*cf!H_z z+rpttdsO3;P8nD>K&DvpHZ`HFc>dr}6HjMwGgKVpIY$-}EPt2PBXq6X=Y!!P5(RUs zuM`x>+Xgk?HC>Y`5lE7NA4Xwo;CS)4-aS|>?k6~?vyRu>-h@rt^k9Slbq!3+E?ZJ% zT&L}(wLv<*BSKY_bOeoTNuB_>7Gjt{lXeg^OzhgB>s{pVRSg|w$DAk&>Wr*Hc7HM{ z4Kr;}WU!ixXMe>JZGb@ovh6^D_!g&6)}W4cP#%cUl^N1$ zoz)vZBD%DL+ZnEX(V5Mxt&O4)#rXDQv$pIy$=ti;!k5_59_l3tJj71fr2d{5{Tj*! zv?~Kb{ALN{O*-b{9YNsgJlx+SslaEYq@K?0KT=A@$m0sT_X*QKvYm;c=$j-cvYNAoN1FS}dIg8Vh&8S5`i$9%s5{PQnf$ zP-QB#-XpCCvk)O%mC`1K_%0X^HEnmX^MBfZal8k6t!lD16d_*X)F^E4G+>ps zTW*oaBs(G#T#~a3xMAmxs)o^lHpx{fJ^x6P63@Xf09Z5`*9ODk&GC})TVQr4(~1B9 z00966SS~d%IRF3xrZ9p6qA-F23jzd2czFsi4F(A+hDe6@4FLfJ1pqLCmoW=42?hgI z1d|#DkRBcv4KOz_HZm|UFf=zXHd+@AF*h(aF*h(UG&e9dlMV))e}SJc4F(A+hDe6@ z4FLfG1potqjQ}u#i2{Lv0G~Z^ph#|)&f|ySUbwlUk`QK#pEj)I$RTLZt#8OUu|QXr$0J&6`f)~WgwCi&=-Fet5rk}VjKnWlM6bv5z`DT&s5GbAe;WU=WCe39Tq6C@O KW;nz!2r Date: Thu, 10 Jul 2014 11:55:10 +0200 Subject: [PATCH 380/701] Introduce acceptAnyCertificate config, defaulting to false, backport df6ed70e86c8fc340ed75563e016c8baa94d7e72, close #352 --- .../http/client/AsyncHttpClientConfig.java | 135 ++++++---------- .../client/AsyncHttpClientConfigBean.java | 11 +- .../client/AsyncHttpClientConfigDefaults.java | 4 + .../ning/http/client/SSLEngineFactory.java | 32 ---- .../http/client/SimpleAsyncHttpClient.java | 10 +- .../grizzly/GrizzlyAsyncHttpProvider.java | 2 +- .../providers/jdk/JDKAsyncHttpProvider.java | 2 +- .../netty/NettyAsyncHttpProvider.java | 16 +- .../java/com/ning/http/util/MiscUtils.java | 4 + .../java/com/ning/http/util/SslUtils.java | 150 ++++-------------- .../client/async/HttpToHttpsRedirectTest.java | 18 ++- .../client/async/ProxyTunnellingTest.java | 35 ++-- .../GrizzlyFeedableBodyGeneratorTest.java | 2 + .../client/websocket/ProxyTunnellingTest.java | 2 +- 14 files changed, 146 insertions(+), 277 deletions(-) delete mode 100644 src/main/java/com/ning/http/client/SSLEngineFactory.java diff --git a/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java b/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java index 9555133567..84aa24e898 100644 --- a/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java @@ -25,9 +25,7 @@ import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLEngine; -import java.security.GeneralSecurityException; import java.util.Collections; import java.util.LinkedList; import java.util.List; @@ -68,7 +66,6 @@ public class AsyncHttpClientConfig { protected ExecutorService applicationThreadPool; protected ProxyServerSelector proxyServerSelector; protected SSLContext sslContext; - protected SSLEngineFactory sslEngineFactory; protected AsyncHttpProviderConfig providerConfig; protected ConnectionsPool connectionsPool; protected Realm realm; @@ -86,6 +83,7 @@ public class AsyncHttpClientConfig { protected boolean useRelativeURIsWithSSLProxies; protected int maxConnectionLifeTimeInMs; protected TimeConverter timeConverter; + protected boolean acceptAnyCertificate; protected AsyncHttpClientConfig() { } @@ -106,7 +104,6 @@ private AsyncHttpClientConfig(int maxTotalConnections, ExecutorService applicationThreadPool, ProxyServerSelector proxyServerSelector, SSLContext sslContext, - SSLEngineFactory sslEngineFactory, AsyncHttpProviderConfig providerConfig, ConnectionsPool connectionsPool, Realm realm, List requestFilters, @@ -121,7 +118,8 @@ private AsyncHttpClientConfig(int maxTotalConnections, int ioThreadMultiplier, boolean strict302Handling, boolean useRelativeURIsWithSSLProxies, - TimeConverter timeConverter) { + TimeConverter timeConverter, // + boolean acceptAnyCertificate) { this.maxTotalConnections = maxTotalConnections; this.maxConnectionPerHost = maxConnectionPerHost; @@ -137,7 +135,6 @@ private AsyncHttpClientConfig(int maxTotalConnections, this.userAgent = userAgent; this.allowPoolingConnection = keepAlive; this.sslContext = sslContext; - this.sslEngineFactory = sslEngineFactory; this.providerConfig = providerConfig; this.connectionsPool = connectionsPool; this.realm = realm; @@ -161,6 +158,7 @@ private AsyncHttpClientConfig(int maxTotalConnections, this.proxyServerSelector = proxyServerSelector; this.disableUrlEncodingForBoundedRequests = disableUrlEncodingForBoundedRequests; this.timeConverter = timeConverter; + this.acceptAnyCertificate = acceptAnyCertificate; } /** @@ -310,28 +308,6 @@ public SSLContext getSSLContext() { return connectionsPool; } - /** - * Return an instance of {@link SSLEngineFactory} used for SSL connection. - * - * @return an instance of {@link SSLEngineFactory} used for SSL connection. - */ - public SSLEngineFactory getSSLEngineFactory() { - if (sslEngineFactory == null) { - return new SSLEngineFactory() { - public SSLEngine newSSLEngine() { - if (sslContext != null) { - SSLEngine sslEngine = sslContext.createSSLEngine(); - sslEngine.setUseClientMode(true); - return sslEngine; - } else { - return null; - } - } - }; - } - return sslEngineFactory; - } - /** * Return the {@link com.ning.http.client.AsyncHttpProviderConfig} * @@ -491,12 +467,19 @@ public int getMaxConnectionLifeTimeInMs() { } /** - * @return 1.8.2 + * since 1.8.2 */ public TimeConverter getTimeConverter() { return timeConverter; } + /** + * since 1.9.0 + */ + public boolean isAcceptAnyCertificate() { + return acceptAnyCertificate; + } + /** * Builder for an {@link AsyncHttpClient} */ @@ -525,11 +508,11 @@ public static class Builder { private boolean removeQueryParamOnRedirect = defaultRemoveQueryParamOnRedirect(); private boolean strict302Handling = defaultStrict302Handling(); private HostnameVerifier hostnameVerifier = defaultHostnameVerifier(); + private boolean acceptAnyCertificate = defaultAcceptAnyCertificate(); private ExecutorService applicationThreadPool; private ProxyServerSelector proxyServerSelector = null; private SSLContext sslContext; - private SSLEngineFactory sslEngineFactory; private AsyncHttpProviderConfig providerConfig; private ConnectionsPool connectionsPool; private Realm realm; @@ -713,17 +696,6 @@ public Builder setProxyServer(ProxyServer proxyServer) { return this; } - /** - * Set the {@link SSLEngineFactory} for secure connection. - * - * @param sslEngineFactory the {@link SSLEngineFactory} for secure connection - * @return a {@link Builder} - */ - public Builder setSSLEngineFactory(SSLEngineFactory sslEngineFactory) { - this.sslEngineFactory = sslEngineFactory; - return this; - } - /** * Set the {@link SSLContext} for secure connection. * @@ -731,13 +703,6 @@ public Builder setSSLEngineFactory(SSLEngineFactory sslEngineFactory) { * @return a {@link Builder} */ public Builder setSSLContext(final SSLContext sslContext) { - this.sslEngineFactory = new SSLEngineFactory() { - public SSLEngine newSSLEngine() throws GeneralSecurityException { - SSLEngine sslEngine = sslContext.createSSLEngine(); - sslEngine.setUseClientMode(true); - return sslEngine; - } - }; this.sslContext = sslContext; return this; } @@ -998,6 +963,11 @@ public Builder setTimeConverter(TimeConverter timeConverter) { return this; } + public Builder setAcceptAnyCertificate(boolean acceptAnyCertificate) { + this.acceptAnyCertificate = acceptAnyCertificate; + return this; + } + /** * Create a config builder with values taken from the given prototype configuration. * @@ -1018,7 +988,6 @@ public Builder(AsyncHttpClientConfig prototype) { realm = prototype.getRealm(); requestTimeoutInMs = prototype.getRequestTimeoutInMs(); sslContext = prototype.getSSLContext(); - sslEngineFactory = prototype.getSSLEngineFactory(); userAgent = prototype.getUserAgent(); followRedirect = prototype.isFollowRedirect(); compressionEnabled = prototype.isCompressionEnabled(); @@ -1041,6 +1010,7 @@ public Builder(AsyncHttpClientConfig prototype) { hostnameVerifier = prototype.getHostnameVerifier(); strict302Handling = prototype.isStrict302Handling(); timeConverter = prototype.timeConverter; + acceptAnyCertificate = prototype.acceptAnyCertificate; } /** @@ -1073,40 +1043,39 @@ public Thread newThread(Runnable r) { proxyServerSelector = ProxyServerSelector.NO_PROXY_SELECTOR; } - return new AsyncHttpClientConfig(maxTotalConnections, - maxConnectionPerHost, - connectionTimeOutInMs, - webSocketIdleTimeoutInMs, - idleConnectionInPoolTimeoutInMs, - idleConnectionTimeoutInMs, - requestTimeoutInMs, - maxConnectionLifeTimeInMs, - followRedirect, - maxDefaultRedirects, - compressionEnabled, - userAgent, - allowPoolingConnection, - applicationThreadPool, - proxyServerSelector, - sslContext, - sslEngineFactory, - providerConfig, - connectionsPool, - realm, - requestFilters, - responseFilters, - ioExceptionFilters, - requestCompressionLevel, - maxRequestRetry, - allowSslConnectionPool, - disableUrlEncodingForBoundedRequests, - removeQueryParamOnRedirect, - hostnameVerifier, - ioThreadMultiplier, - strict302Handling, - useRelativeURIsWithSSLProxies, - timeConverter); + return new AsyncHttpClientConfig(maxTotalConnections, // + maxConnectionPerHost, // + connectionTimeOutInMs, // + webSocketIdleTimeoutInMs, // + idleConnectionInPoolTimeoutInMs, // + idleConnectionTimeoutInMs, // + requestTimeoutInMs, // + maxConnectionLifeTimeInMs, // + followRedirect, // + maxDefaultRedirects, // + compressionEnabled, // + userAgent, // + allowPoolingConnection, // + applicationThreadPool, // + proxyServerSelector, // + sslContext, // + providerConfig, // + connectionsPool, // + realm, // + requestFilters, // + responseFilters, // + ioExceptionFilters, // + requestCompressionLevel, // + maxRequestRetry, // + allowSslConnectionPool, // + disableUrlEncodingForBoundedRequests, // + removeQueryParamOnRedirect, // + hostnameVerifier, // + ioThreadMultiplier, // + strict302Handling, // + useRelativeURIsWithSSLProxies, // + timeConverter, // + acceptAnyCertificate); } } } - diff --git a/src/main/java/com/ning/http/client/AsyncHttpClientConfigBean.java b/src/main/java/com/ning/http/client/AsyncHttpClientConfigBean.java index 1a2618decb..170fbf31a1 100644 --- a/src/main/java/com/ning/http/client/AsyncHttpClientConfigBean.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClientConfigBean.java @@ -67,6 +67,7 @@ void configureDefaults() { removeQueryParamOnRedirect = defaultRemoveQueryParamOnRedirect(); strict302Handling = defaultStrict302Handling(); hostnameVerifier = defaultHostnameVerifier(); + acceptAnyCertificate = defaultAcceptAnyCertificate(); if (defaultUseProxySelector()) { proxyServerSelector = ProxyUtils.getJdkDefaultProxyServerSelector(); @@ -173,11 +174,6 @@ public AsyncHttpClientConfigBean setSslContext(SSLContext sslContext) { return this; } - public AsyncHttpClientConfigBean setSslEngineFactory(SSLEngineFactory sslEngineFactory) { - this.sslEngineFactory = sslEngineFactory; - return this; - } - public AsyncHttpClientConfigBean setProviderConfig(AsyncHttpProviderConfig providerConfig) { this.providerConfig = providerConfig; return this; @@ -242,4 +238,9 @@ public AsyncHttpClientConfigBean setIoThreadMultiplier(int ioThreadMultiplier) { this.ioThreadMultiplier = ioThreadMultiplier; return this; } + + public AsyncHttpClientConfigBean setAcceptAnyCertificate(boolean acceptAnyCertificate) { + this.acceptAnyCertificate = acceptAnyCertificate; + return this; + } } diff --git a/src/main/java/com/ning/http/client/AsyncHttpClientConfigDefaults.java b/src/main/java/com/ning/http/client/AsyncHttpClientConfigDefaults.java index d13b47ac45..0168768699 100644 --- a/src/main/java/com/ning/http/client/AsyncHttpClientConfigDefaults.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClientConfigDefaults.java @@ -121,4 +121,8 @@ public static boolean defaultRemoveQueryParamOnRedirect() { public static HostnameVerifier defaultHostnameVerifier() { return new DefaultHostnameVerifier(); } + + public static boolean defaultAcceptAnyCertificate() { + return getBoolean(ASYNC_CLIENT + "acceptAnyCertificate", false); + } } diff --git a/src/main/java/com/ning/http/client/SSLEngineFactory.java b/src/main/java/com/ning/http/client/SSLEngineFactory.java deleted file mode 100644 index 1e5fc5873f..0000000000 --- a/src/main/java/com/ning/http/client/SSLEngineFactory.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * 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 javax.net.ssl.SSLEngine; -import java.security.GeneralSecurityException; - -/** - * Factory that creates an {@link SSLEngine} to be used for a single SSL connection. - */ -public interface SSLEngineFactory { - /** - * Creates new {@link SSLEngine}. - * - * @return new engine - * @throws GeneralSecurityException if the SSLEngine cannot be created - */ - SSLEngine newSSLEngine() throws GeneralSecurityException; -} diff --git a/src/main/java/com/ning/http/client/SimpleAsyncHttpClient.java b/src/main/java/com/ning/http/client/SimpleAsyncHttpClient.java index 85fa2e2963..9f9e87d5ea 100644 --- a/src/main/java/com/ning/http/client/SimpleAsyncHttpClient.java +++ b/src/main/java/com/ning/http/client/SimpleAsyncHttpClient.java @@ -539,11 +539,6 @@ public Builder setExecutorService(ExecutorService applicationThreadPool) { return this; } - public Builder setSSLEngineFactory(SSLEngineFactory sslEngineFactory) { - configBuilder.setSSLEngineFactory(sslEngineFactory); - return this; - } - public Builder setSSLContext(final SSLContext sslContext) { configBuilder.setSSLContext(sslContext); return this; @@ -669,6 +664,11 @@ public Builder setProviderClass(String providerClass) { return this; } + public Builder setAcceptAnyCertificate(boolean acceptAnyCertificate) { + configBuilder.setAcceptAnyCertificate(acceptAnyCertificate); + return this; + } + public SimpleAsyncHttpClient build() { if (realmBuilder != 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 c42c150cce..a419c64a60 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 @@ -383,7 +383,7 @@ public void onTimeout(Connection connection) { boolean defaultSecState = (context != null); if (context == null) { try { - context = SslUtils.getSSLContext(); + context = SslUtils.getInstance().getSSLContext(clientConfig.isAcceptAnyCertificate()); } catch (Exception e) { throw new IllegalStateException(e); } 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 f853160cac..233d70b592 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 @@ -186,7 +186,7 @@ private HttpURLConnection createUrlConnection(Request request) throws IOExceptio SSLContext sslContext = config.getSSLContext(); if (sslContext == null) { try { - sslContext = SslUtils.getSSLContext(); + sslContext = SslUtils.getInstance().getSSLContext(config.isAcceptAnyCertificate()); } catch (NoSuchAlgorithmException e) { throw new IOException(e.getMessage()); } catch (GeneralSecurityException e) { 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 1dbb82abf8..7c9dcc8ce7 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 @@ -373,7 +373,7 @@ public ChannelPipeline getPipeline() throws Exception { ChannelPipeline pipeline = pipeline(); try { - SSLEngine sslEngine = createSSLEngine(); + SSLEngine sslEngine = SslUtils.getInstance().createClientSSLEngine(config); SslHandler sslHandler = handshakeTimeoutInMillis > 0 ? new SslHandler(sslEngine, getDefaultBufferPool(), false, ImmediateExecutor.INSTANCE, nettyTimer, handshakeTimeoutInMillis) : new SslHandler(sslEngine); pipeline.addLast(SSL_HANDLER, sslHandler); @@ -399,7 +399,7 @@ public ChannelPipeline getPipeline() throws Exception { ChannelPipeline pipeline = pipeline(); try { - pipeline.addLast(SSL_HANDLER, new SslHandler(createSSLEngine())); + pipeline.addLast(SSL_HANDLER, new SslHandler(SslUtils.getInstance().createClientSSLEngine(config))); } catch (Throwable ex) { abort(cl.future(), ex); } @@ -437,14 +437,6 @@ private Channel lookupInCache(UriComponents uri, ProxyServer proxy, ConnectionPo return null; } - private SSLEngine createSSLEngine() throws IOException, GeneralSecurityException { - SSLEngine sslEngine = config.getSSLEngineFactory().newSSLEngine(); - if (sslEngine == null) { - sslEngine = SslUtils.getSSLEngine(); - } - return sslEngine; - } - private HttpClientCodec createHttpClientCodec() { return new HttpClientCodec(httpClientCodecMaxInitialLineLength, httpClientCodecMaxHeaderSize, httpClientCodecMaxChunkSize); } @@ -460,7 +452,7 @@ private Channel verifyChannelPipeline(Channel channel, String scheme) throws IOE } else if (channel.getPipeline().get(HTTP_HANDLER) != null && HTTP.equalsIgnoreCase(scheme)) { return channel; } else if (channel.getPipeline().get(SSL_HANDLER) == null && isSecure(scheme)) { - channel.getPipeline().addFirst(SSL_HANDLER, new SslHandler(createSSLEngine())); + channel.getPipeline().addFirst(SSL_HANDLER, new SslHandler(SslUtils.getInstance().createClientSSLEngine(config))); } return channel; } @@ -1383,7 +1375,7 @@ 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(SSL_HANDLER, new SslHandler(createSSLEngine())); + p.addFirst(SSL_HANDLER, new SslHandler(SslUtils.getInstance().createClientSSLEngine(config))); } else { p.addAfter(SSL_HANDLER, HTTP_HANDLER, createHttpClientCodec()); } diff --git a/src/main/java/com/ning/http/util/MiscUtils.java b/src/main/java/com/ning/http/util/MiscUtils.java index dab4d5df95..0db03068e3 100644 --- a/src/main/java/com/ning/http/util/MiscUtils.java +++ b/src/main/java/com/ning/http/util/MiscUtils.java @@ -44,4 +44,8 @@ public static boolean getBoolean(String systemPropName, boolean defaultValue) { String systemPropValue = System.getProperty(systemPropName); return systemPropValue != null ? systemPropValue.equalsIgnoreCase("true") : defaultValue; } + + public static T withDefault(T value, T defaults) { + return value != null? value : value; + } } diff --git a/src/main/java/com/ning/http/util/SslUtils.java b/src/main/java/com/ning/http/util/SslUtils.java index 9fc62cf926..1c47b35d79 100644 --- a/src/main/java/com/ning/http/util/SslUtils.java +++ b/src/main/java/com/ning/http/util/SslUtils.java @@ -15,101 +15,43 @@ */ package com.ning.http.util; -import javax.net.ssl.KeyManager; -import javax.net.ssl.KeyManagerFactory; +import com.ning.http.client.AsyncHttpClientConfig; + import javax.net.ssl.SSLContext; import javax.net.ssl.SSLEngine; import javax.net.ssl.TrustManager; -import javax.net.ssl.TrustManagerFactory; import javax.net.ssl.X509TrustManager; -import java.io.FileInputStream; + import java.io.IOException; -import java.io.InputStream; import java.security.GeneralSecurityException; -import java.security.KeyStore; import java.security.SecureRandom; -import java.security.Security; -/** - * This class is a copy of http://github.com/sonatype/wagon-ning/raw/master/src/main/java/org/apache/maven/wagon/providers/http/SslUtils.java - */ public class SslUtils { - private static SSLContext context = null; - - public static SSLEngine getSSLEngine() - throws GeneralSecurityException, IOException { - SSLEngine engine = null; - - SSLContext context = getSSLContext(); - if (context != null) { - engine = context.createSSLEngine(); - engine.setUseClientMode(true); - } - - return engine; + private static class SingletonHolder { + public static final SslUtils instance = new SslUtils(); } - public static SSLContext getSSLContext() - throws GeneralSecurityException, IOException { - if (context == null) { - SSLConfig config = new SSLConfig(); - if (config.keyStoreLocation == null - || config.trustStoreLocation == null) { - context = getLooseSSLContext(); - } else { - context = getStrictSSLContext(config); - } - } - return context; + public static SslUtils getInstance() { + return SingletonHolder.instance; } - static SSLContext getStrictSSLContext(SSLConfig config) - throws GeneralSecurityException, IOException { - KeyStore keyStore = KeyStore.getInstance(config.keyStoreType); - InputStream keystoreInputStream = new FileInputStream(config.keyStoreLocation); - try { - keyStore.load(keystoreInputStream, (config.keyStorePassword == null) ? null - : config.keyStorePassword.toCharArray()); - } finally { - keystoreInputStream.close(); + public SSLEngine createClientSSLEngine(AsyncHttpClientConfig config) throws GeneralSecurityException, IOException { + SSLContext sslContext = config.getSSLContext(); + if (sslContext == null) { + sslContext = SslUtils.getInstance().getSSLContext(config.isAcceptAnyCertificate()); } - - KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(config.keyManagerAlgorithm); - keyManagerFactory.init(keyStore, (config.keyManagerPassword == null) ? null - : config.keyManagerPassword.toCharArray()); - KeyManager[] keyManagers = keyManagerFactory.getKeyManagers(); - - KeyStore trustStore = KeyStore.getInstance(config.trustStoreType); - InputStream truststoreInputStream = new FileInputStream(config.trustStoreLocation); - try { - trustStore.load(truststoreInputStream, (config.trustStorePassword == null) ? null - : config.trustStorePassword.toCharArray()); - } finally { - truststoreInputStream.close(); - } - - TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(config.trustManagerAlgorithm); - trustManagerFactory.init(trustStore); - TrustManager[] trustManagers = trustManagerFactory.getTrustManagers(); - - SSLContext context = SSLContext.getInstance("TLS"); - context.init(keyManagers, trustManagers, null); - - return context; + SSLEngine sslEngine = sslContext.createSSLEngine(); + sslEngine.setUseClientMode(true); + return sslEngine; } - - static SSLContext getLooseSSLContext() - throws GeneralSecurityException { - SSLContext sslContext = SSLContext.getInstance("TLS"); - sslContext.init(null, new TrustManager[]{LooseTrustManager.INSTANCE}, new SecureRandom()); - return sslContext; + + public SSLContext getSSLContext(boolean acceptAnyCertificate) throws GeneralSecurityException, IOException { + // SSLContext.getDefault() doesn't exist in JDK5 + return acceptAnyCertificate ? looseTrustManagerSSLContext : SSLContext.getInstance("Default"); } - static class LooseTrustManager - implements X509TrustManager { - - public static final LooseTrustManager INSTANCE = new LooseTrustManager(); + static class LooseTrustManager implements X509TrustManager { public java.security.cert.X509Certificate[] getAcceptedIssuers() { return new java.security.cert.X509Certificate[0]; @@ -122,53 +64,15 @@ public void checkServerTrusted(java.security.cert.X509Certificate[] certs, Strin } } - private final static class SSLConfig { - - public String keyStoreLocation; - - public String keyStoreType = "JKS"; - - public String keyStorePassword = "changeit"; - - public String keyManagerAlgorithm = "SunX509"; - - public String keyManagerPassword = "changeit"; - - public String trustStoreLocation; - - public String trustStoreType = "JKS"; + private SSLContext looseTrustManagerSSLContext = looseTrustManagerSSLContext(); - public String trustStorePassword = "changeit"; - - public String trustManagerAlgorithm = "SunX509"; - - public SSLConfig() { - keyStoreLocation = System.getProperty("javax.net.ssl.keyStore"); - keyStorePassword = System.getProperty("javax.net.ssl.keyStorePassword", "changeit"); - keyStoreType = System.getProperty("javax.net.ssl.keyStoreType", KeyStore.getDefaultType()); - keyManagerAlgorithm = Security.getProperty("ssl.KeyManagerFactory.algorithm"); - - if (keyManagerAlgorithm == null) { - keyManagerAlgorithm = "SunX509"; - } - - keyManagerPassword = System.getProperty("javax.net.ssl.keyStorePassword", "changeit"); - - trustStoreLocation = System.getProperty("javax.net.ssl.trustStore"); - if (trustStoreLocation == null) { - trustStoreLocation = keyStoreLocation; - trustStorePassword = keyStorePassword; - trustStoreType = keyStoreType; - } else { - trustStorePassword = System.getProperty("javax.net.ssl.trustStorePassword", "changeit"); - trustStoreType = System.getProperty("javax.net.ssl.trustStoreType", KeyStore.getDefaultType()); - } - trustManagerAlgorithm = Security.getProperty("ssl.TrustManagerFactory.algorithm"); - - if (trustManagerAlgorithm == null) { - trustManagerAlgorithm = "SunX509"; - } + private SSLContext looseTrustManagerSSLContext() { + try { + SSLContext sslContext = SSLContext.getInstance("TLS"); + sslContext.init(null, new TrustManager[] { new LooseTrustManager() }, new SecureRandom()); + return sslContext; + } catch (Exception e) { + throw new ExceptionInInitializerError(e); } } - } 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 8305e4fd15..a757e41eff 100644 --- a/src/test/java/com/ning/http/client/async/HttpToHttpsRedirectTest.java +++ b/src/test/java/com/ning/http/client/async/HttpToHttpsRedirectTest.java @@ -120,7 +120,11 @@ public void setUpGlobal() throws Exception { public void httpToHttpsRedirect() throws Throwable { isSet.getAndSet(false); - AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setMaximumNumberOfRedirects(5).setFollowRedirect(true).build(); + AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder()// + .setMaximumNumberOfRedirects(5)// + .setFollowRedirect(true)// + .setAcceptAnyCertificate(true)// + .build(); AsyncHttpClient c = getAsyncHttpClient(cg); Response response = c.prepareGet(getTargetUrl()).setHeader("X-redirect", getTargetUrl2()).execute().get(); @@ -138,7 +142,11 @@ public String getTargetUrl2() { public void httpToHttpsProperConfig() throws Throwable { isSet.getAndSet(false); - AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setMaximumNumberOfRedirects(5).setFollowRedirect(true).build(); + AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder()// + .setMaximumNumberOfRedirects(5)// + .setFollowRedirect(true)// + .setAcceptAnyCertificate(true)// + .build(); AsyncHttpClient c = getAsyncHttpClient(cg); try { Response response = c.prepareGet(getTargetUrl()).setHeader("X-redirect", getTargetUrl2() + "/test2").execute().get(); @@ -160,7 +168,11 @@ public void httpToHttpsProperConfig() throws Throwable { public void relativeLocationUrl() throws Throwable { isSet.getAndSet(false); - AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setMaximumNumberOfRedirects(5).setFollowRedirect(true).build(); + AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder()// + .setMaximumNumberOfRedirects(5)// + .setFollowRedirect(true)// + .setAcceptAnyCertificate(true)// + .build(); AsyncHttpClient c = getAsyncHttpClient(cg); try { Response response = c.prepareGet(getTargetUrl()).setHeader("X-redirect", "/foo/test").execute().get(); diff --git a/src/test/java/com/ning/http/client/async/ProxyTunnellingTest.java b/src/test/java/com/ning/http/client/async/ProxyTunnellingTest.java index 588532b4a3..56b775c51b 100644 --- a/src/test/java/com/ning/http/client/async/ProxyTunnellingTest.java +++ b/src/test/java/com/ning/http/client/async/ProxyTunnellingTest.java @@ -90,12 +90,14 @@ public void setUpGlobal() throws Exception { @Test(groups = { "online", "default_provider" }) public void testRequestProxy() throws IOException, InterruptedException, ExecutionException, TimeoutException { - AsyncHttpClientConfig.Builder b = new AsyncHttpClientConfig.Builder(); - b.setFollowRedirect(true); ProxyServer ps = new ProxyServer(ProxyServer.Protocol.HTTPS, "127.0.0.1", port1); - AsyncHttpClientConfig config = b.build(); + AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder()// + .setFollowRedirect(true)// + .setAcceptAnyCertificate(true)// + .build(); + AsyncHttpClient asyncHttpClient = getAsyncHttpClient(config); try { RequestBuilder rb = new RequestBuilder("GET").setProxyServer(ps).setUrl(getTargetUrl2()); @@ -122,13 +124,12 @@ public Response onCompleted(Response response) throws Exception { @Test(groups = { "online", "default_provider" }) public void testConfigProxy() throws IOException, InterruptedException, ExecutionException, TimeoutException { - AsyncHttpClientConfig.Builder b = new AsyncHttpClientConfig.Builder(); - b.setFollowRedirect(true); - - ProxyServer ps = new ProxyServer(ProxyServer.Protocol.HTTPS, "127.0.0.1", port1); - b.setProxyServer(ps); + AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder()// + .setProxyServer(new ProxyServer(ProxyServer.Protocol.HTTPS, "127.0.0.1", port1))// + .setAcceptAnyCertificate(true)// + .setFollowRedirect(true)// + .build(); - AsyncHttpClientConfig config = b.build(); AsyncHttpClient asyncHttpClient = getAsyncHttpClient(config); try { RequestBuilder rb = new RequestBuilder("GET").setUrl(getTargetUrl2()); @@ -155,7 +156,14 @@ public Response onCompleted(Response response) throws Exception { @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(); + SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder()// + .setProxyProtocol(ProxyServer.Protocol.HTTPS)// + .setProxyHost("127.0.0.1")// + .setProxyPort(port1)// + .setFollowRedirects(true)// + .setUrl(getTargetUrl2())// + .setAcceptAnyCertificate(true)// + .setHeader("Content-Type", "text/html").build(); try { Response r = client.get().get(); @@ -168,7 +176,12 @@ public void testSimpleAHCConfigProxy() throws IOException, InterruptedException, @Test(groups = { "standalone", "default_provider" }) public void testNonProxyHostsSsl() throws IOException, ExecutionException, TimeoutException, InterruptedException { - AsyncHttpClient client = getAsyncHttpClient(null); + + AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder()// + .setAcceptAnyCertificate(true)// + .build(); + + AsyncHttpClient client = getAsyncHttpClient(config); 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); 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 e023f35908..0b89f7709a 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 @@ -139,6 +139,7 @@ private void doSimpleFeeder(final boolean secure) { AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder() .setMaximumConnectionsPerHost(60) .setMaximumConnectionsTotal(60) + .setAcceptAnyCertificate(true) .build(); final AsyncHttpClient client = new AsyncHttpClient(new GrizzlyAsyncHttpProvider(config), config); @@ -243,6 +244,7 @@ private void doNonBlockingFeeder(final boolean secure) { AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder() .setMaximumConnectionsPerHost(60) .setMaximumConnectionsTotal(60) + .setAcceptAnyCertificate(true) .build(); final AsyncHttpClient client = new AsyncHttpClient(new GrizzlyAsyncHttpProvider(config), config); diff --git a/src/test/java/com/ning/http/client/websocket/ProxyTunnellingTest.java b/src/test/java/com/ning/http/client/websocket/ProxyTunnellingTest.java index 932fcaf20c..324a5321d4 100644 --- a/src/test/java/com/ning/http/client/websocket/ProxyTunnellingTest.java +++ b/src/test/java/com/ning/http/client/websocket/ProxyTunnellingTest.java @@ -102,7 +102,7 @@ protected String getTargetUrl() { public void echoText() throws Exception { ProxyServer ps = new ProxyServer(ProxyServer.Protocol.HTTPS, "127.0.0.1", port1); - AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder().setProxyServer(ps).build(); + AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder().setProxyServer(ps).setAcceptAnyCertificate(true).build(); AsyncHttpClient asyncHttpClient = getAsyncHttpClient(config); try { final CountDownLatch latch = new CountDownLatch(1); From 300ba99b265d030214031a4eed36c8f051c5df60 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 10 Jul 2014 13:38:39 +0200 Subject: [PATCH 381/701] Add host and port to SSLEngine, backport fix #513 --- .../netty/NettyAsyncHttpProvider.java | 39 +++++++-------- .../providers/netty/SslInitializer.java | 50 +++++++++++++++++++ .../java/com/ning/http/util/SslUtils.java | 4 +- 3 files changed, 69 insertions(+), 24 deletions(-) create mode 100644 src/main/java/com/ning/http/client/providers/netty/SslInitializer.java 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 7c9dcc8ce7..0fd1eb3c49 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 @@ -364,6 +364,12 @@ protected void configureHttpsClientCodec() { httpsClientCodecMaxChunkSize = providerConfig.getProperty(HTTPS_CLIENT_CODEC_MAX_CHUNK_SIZE, Integer.class, httpsClientCodecMaxChunkSize); } + SslHandler createSslHandler(String peerHost, int peerPort) throws GeneralSecurityException, IOException { + SSLEngine sslEngine = SslUtils.getInstance().createClientSSLEngine(config, peerHost, peerPort); + return handshakeTimeoutInMillis > 0 ? new SslHandler(sslEngine, getDefaultBufferPool(), false, ImmediateExecutor.INSTANCE, nettyTimer, + handshakeTimeoutInMillis) : new SslHandler(sslEngine); + } + void constructSSLPipeline(final NettyConnectListener cl) { secureBootstrap.setPipelineFactory(new ChannelPipelineFactory() { @@ -371,16 +377,7 @@ void constructSSLPipeline(final NettyConnectListener cl) { /* @Override */ public ChannelPipeline getPipeline() throws Exception { ChannelPipeline pipeline = pipeline(); - - try { - SSLEngine sslEngine = SslUtils.getInstance().createClientSSLEngine(config); - SslHandler sslHandler = handshakeTimeoutInMillis > 0 ? new SslHandler(sslEngine, getDefaultBufferPool(), false, ImmediateExecutor.INSTANCE, nettyTimer, - handshakeTimeoutInMillis) : new SslHandler(sslEngine); - pipeline.addLast(SSL_HANDLER, sslHandler); - } catch (Throwable ex) { - abort(cl.future(), ex); - } - + pipeline.addLast(SSL_HANDLER, new SslInitializer(NettyAsyncHttpProvider.this)); pipeline.addLast(HTTP_HANDLER, createHttpsClientCodec()); if (config.isCompressionEnabled()) { @@ -397,13 +394,7 @@ public ChannelPipeline getPipeline() throws Exception { /* @Override */ public ChannelPipeline getPipeline() throws Exception { ChannelPipeline pipeline = pipeline(); - - try { - pipeline.addLast(SSL_HANDLER, new SslHandler(SslUtils.getInstance().createClientSSLEngine(config))); - } catch (Throwable ex) { - abort(cl.future(), ex); - } - + pipeline.addLast(SSL_HANDLER, new SslInitializer(NettyAsyncHttpProvider.this)); pipeline.addLast(HTTP_HANDLER, createHttpsClientCodec()); pipeline.addLast(WS_PROCESSOR, NettyAsyncHttpProvider.this); @@ -452,7 +443,7 @@ private Channel verifyChannelPipeline(Channel channel, String scheme) throws IOE } else if (channel.getPipeline().get(HTTP_HANDLER) != null && HTTP.equalsIgnoreCase(scheme)) { return channel; } else if (channel.getPipeline().get(SSL_HANDLER) == null && isSecure(scheme)) { - channel.getPipeline().addFirst(SSL_HANDLER, new SslHandler(SslUtils.getInstance().createClientSSLEngine(config))); + channel.getPipeline().addFirst(SSL_HANDLER, new SslInitializer(NettyAsyncHttpProvider.this)); } return channel; } @@ -1367,7 +1358,7 @@ public void abort(NettyResponseFuture future, Throwable t) { future.abort(t); } - private void upgradeProtocol(ChannelPipeline p, String scheme) throws IOException, GeneralSecurityException { + private void upgradeProtocol(ChannelPipeline p, String scheme, String host, int port) throws IOException, GeneralSecurityException { if (p.get(HTTP_HANDLER) != null) { p.remove(HTTP_HANDLER); } @@ -1375,7 +1366,7 @@ 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(SSL_HANDLER, new SslHandler(SslUtils.getInstance().createClientSSLEngine(config))); + p.addFirst(SSL_HANDLER, createSslHandler(host, port)); } else { p.addAfter(SSL_HANDLER, HTTP_HANDLER, createHttpClientCodec()); } @@ -2136,9 +2127,13 @@ public Object call() throws Exception { } try { - String scheme = request.getURI().getScheme(); + UriComponents requestURI = request.getURI(); + String scheme = requestURI.getScheme(); + String host = requestURI.getHost(); + int port = AsyncHttpProviderUtils.getDefaultPort(requestURI); + log.debug("Connecting to proxy {} for scheme {}", proxyServer, scheme); - upgradeProtocol(ctx.getChannel().getPipeline(), scheme); + upgradeProtocol(ctx.getChannel().getPipeline(), scheme, host, port); } catch (Throwable ex) { abort(future, ex); } diff --git a/src/main/java/com/ning/http/client/providers/netty/SslInitializer.java b/src/main/java/com/ning/http/client/providers/netty/SslInitializer.java new file mode 100644 index 0000000000..29c90299a6 --- /dev/null +++ b/src/main/java/com/ning/http/client/providers/netty/SslInitializer.java @@ -0,0 +1,50 @@ +/* + * Copyright 2014 AsyncHttpClient Project. + * + * 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.channel.ChannelHandlerContext; +import org.jboss.netty.channel.ChannelStateEvent; +import org.jboss.netty.channel.SimpleChannelDownstreamHandler; +import org.jboss.netty.handler.ssl.SslHandler; + +import java.net.InetSocketAddress; + +/** + * On connect, replaces itself with a SslHandler that has a SSLEngine configured with the remote host and port. + * + * @author slandelle + */ +public class SslInitializer extends SimpleChannelDownstreamHandler { + + private final NettyAsyncHttpProvider provider; + + public SslInitializer(NettyAsyncHttpProvider provider) { + this.provider = provider; + } + + public void connectRequested(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { + + InetSocketAddress remoteInetSocketAddress = (InetSocketAddress) e.getValue(); + String peerHost = remoteInetSocketAddress.getHostName(); + int peerPort = remoteInetSocketAddress.getPort(); + + SslHandler sslHandler = provider.createSslHandler(peerHost, peerPort); + + ctx.getPipeline().replace(NettyAsyncHttpProvider.SSL_HANDLER, NettyAsyncHttpProvider.SSL_HANDLER, sslHandler); + + ctx.sendDownstream(e); + } +} diff --git a/src/main/java/com/ning/http/util/SslUtils.java b/src/main/java/com/ning/http/util/SslUtils.java index 1c47b35d79..ec4d84716e 100644 --- a/src/main/java/com/ning/http/util/SslUtils.java +++ b/src/main/java/com/ning/http/util/SslUtils.java @@ -36,12 +36,12 @@ public static SslUtils getInstance() { return SingletonHolder.instance; } - public SSLEngine createClientSSLEngine(AsyncHttpClientConfig config) throws GeneralSecurityException, IOException { + public SSLEngine createClientSSLEngine(AsyncHttpClientConfig config, String peerHost, int peerPort) throws GeneralSecurityException, IOException { SSLContext sslContext = config.getSSLContext(); if (sslContext == null) { sslContext = SslUtils.getInstance().getSSLContext(config.isAcceptAnyCertificate()); } - SSLEngine sslEngine = sslContext.createSSLEngine(); + SSLEngine sslEngine = sslContext.createSSLEngine(peerHost, peerPort); sslEngine.setUseClientMode(true); return sslEngine; } From 356fec7ef7c22a0ad7748bbf39fead7d2d1a3b18 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 10 Jul 2014 13:51:52 +0200 Subject: [PATCH 382/701] Add #355 test on 1.9: Netty OK, Grizzly KO, see #610 --- .../http/client/async/BasicHttpsTest.java | 32 +++++++++++++++++++ .../async/grizzly/GrizzlyBasicHttpsTest.java | 6 ++++ 2 files changed, 38 insertions(+) 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 24ef8052a5..295cc788e2 100644 --- a/src/test/java/com/ning/http/client/async/BasicHttpsTest.java +++ b/src/test/java/com/ning/http/client/async/BasicHttpsTest.java @@ -25,15 +25,18 @@ import org.eclipse.jetty.server.ssl.SslSocketConnector; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.testng.Assert; import org.testng.annotations.AfterClass; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; +import javax.net.ssl.HostnameVerifier; import javax.net.ssl.KeyManager; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLHandshakeException; +import javax.net.ssl.SSLSession; import javax.net.ssl.TrustManager; import javax.net.ssl.TrustManagerFactory; import javax.net.ssl.X509TrustManager; @@ -300,6 +303,35 @@ public void reconnectsAfterFailedCertificationPath() throws Exception { } } + @Test(timeOut = 5000) + public void failInstantlyIfHostNamesDiffer() throws Exception { + AsyncHttpClient client = null; + + try { + final Builder builder = new Builder().setHostnameVerifier(new HostnameVerifier() { + + public boolean verify(String arg0, SSLSession arg1) { + return false; + } + }).setRequestTimeoutInMs(20000); + + client = getAsyncHttpClient(builder.build()); + + try { + client.prepareGet("https://github.com/AsyncHttpClient/async-http-client/issues/355").execute().get(TIMEOUT, TimeUnit.SECONDS); + + Assert.assertTrue(false, "Shouldn't be here: should get an Exception"); + } catch (ExecutionException e) { + Assert.assertTrue(e.getCause() instanceof ConnectException, "Cause should be a ConnectException"); + } catch (Exception e) { + Assert.assertTrue(false, "Shouldn't be here: should get a ConnectException wrapping a ConnectException"); + } + + } finally { + client.close(); + } + } + private static KeyManager[] createKeyManagers() throws GeneralSecurityException, IOException { InputStream keyStoreStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("ssltest-cacerts.jks"); char[] keyStorePassword = "changeit".toCharArray(); 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 19d2397199..46c4cfdbb7 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 @@ -13,6 +13,8 @@ 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.BasicHttpsTest; @@ -24,4 +26,8 @@ public class GrizzlyBasicHttpsTest extends BasicHttpsTest { public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { return ProviderUtil.grizzlyProvider(config); } + + @Test(enabled = false) + public void failInstantlyIfHostNamesDiffer() throws Exception { + } } From 54ae70d084d8e1230c86fefdedf2d096f0c34288 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 10 Jul 2014 16:01:08 +0200 Subject: [PATCH 383/701] Remove EntityWriter, backport #372 --- .../com/ning/http/client/AsyncHttpClient.java | 11 ---- .../java/com/ning/http/client/Request.java | 16 ------ .../com/ning/http/client/RequestBuilder.java | 11 ---- .../ning/http/client/RequestBuilderBase.java | 21 -------- .../apache/ApacheAsyncHttpProvider.java | 29 ----------- .../grizzly/GrizzlyAsyncHttpProvider.java | 36 ------------- .../providers/jdk/JDKAsyncHttpProvider.java | 7 --- .../netty/NettyAsyncHttpProvider.java | 12 ----- .../client/async/AsyncProvidersBasicTest.java | 51 ------------------- 9 files changed, 194 deletions(-) diff --git a/src/main/java/com/ning/http/client/AsyncHttpClient.java b/src/main/java/com/ning/http/client/AsyncHttpClient.java index 3e761639b2..efe4fd50c5 100755 --- a/src/main/java/com/ning/http/client/AsyncHttpClient.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClient.java @@ -31,7 +31,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.ning.http.client.Request.EntityWriter; import com.ning.http.client.cookie.Cookie; import com.ning.http.client.filter.FilterContext; import com.ning.http.client.filter.FilterException; @@ -269,16 +268,6 @@ public BoundRequestBuilder setBody(byte[] data) { return super.setBody(data); } - @Override - public BoundRequestBuilder setBody(EntityWriter dataWriter, long length) { - return super.setBody(dataWriter, length); - } - - @Override - public BoundRequestBuilder setBody(EntityWriter dataWriter) { - return super.setBody(dataWriter); - } - @Override public BoundRequestBuilder setBody(InputStream stream) { return super.setBody(stream); diff --git a/src/main/java/com/ning/http/client/Request.java b/src/main/java/com/ning/http/client/Request.java index 115d98b71d..54b04aa3d7 100644 --- a/src/main/java/com/ning/http/client/Request.java +++ b/src/main/java/com/ning/http/client/Request.java @@ -17,9 +17,7 @@ package com.ning.http.client; import java.io.File; -import java.io.IOException; import java.io.InputStream; -import java.io.OutputStream; import java.net.InetAddress; import java.util.Collection; import java.util.List; @@ -40,13 +38,6 @@ */ public interface Request { - /** - * An entity that can be used to manipulate the Request's body output before it get sent. - */ - public static interface EntityWriter { - void writeEntity(OutputStream out) throws IOException; - } - /** * Return the request's method name (GET, POST, etc.) * @@ -100,13 +91,6 @@ public static interface EntityWriter { */ InputStream getStreamData(); - /** - * Return the current request's body as an EntityWriter - * - * @return an EntityWriter representation of the current request's body. - */ - EntityWriter getEntityWriter(); - /** * Return the current request's body generator. * diff --git a/src/main/java/com/ning/http/client/RequestBuilder.java b/src/main/java/com/ning/http/client/RequestBuilder.java index 4771d4906a..861570143b 100644 --- a/src/main/java/com/ning/http/client/RequestBuilder.java +++ b/src/main/java/com/ning/http/client/RequestBuilder.java @@ -20,7 +20,6 @@ import java.util.List; import java.util.Map; -import com.ning.http.client.Request.EntityWriter; import com.ning.http.client.cookie.Cookie; import com.ning.http.util.QueryComputer; @@ -109,16 +108,6 @@ public RequestBuilder setBody(byte[] data) { return super.setBody(data); } - @Override - public RequestBuilder setBody(EntityWriter dataWriter, long length) { - return super.setBody(dataWriter, length); - } - - @Override - public RequestBuilder setBody(EntityWriter dataWriter) { - return super.setBody(dataWriter); - } - /** * Deprecated - Use setBody(new InputStreamBodyGenerator(inputStream)). * diff --git a/src/main/java/com/ning/http/client/RequestBuilderBase.java b/src/main/java/com/ning/http/client/RequestBuilderBase.java index 18420f99e8..bc3e8b1163 100644 --- a/src/main/java/com/ning/http/client/RequestBuilderBase.java +++ b/src/main/java/com/ning/http/client/RequestBuilderBase.java @@ -29,7 +29,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.ning.http.client.Request.EntityWriter; import com.ning.http.client.cookie.Cookie; import com.ning.http.client.uri.UriComponents; import com.ning.http.util.AsyncHttpProviderUtils; @@ -55,7 +54,6 @@ private static final class RequestImpl implements Request { private byte[] byteData; private String stringData; private InputStream streamData; - private EntityWriter entityWriter; private BodyGenerator bodyGenerator; private List formParams; private List parts; @@ -85,7 +83,6 @@ public RequestImpl(Request prototype) { this.byteData = prototype.getByteData(); this.stringData = prototype.getStringData(); this.streamData = prototype.getStreamData(); - this.entityWriter = prototype.getEntityWriter(); this.bodyGenerator = prototype.getBodyGenerator(); this.formParams = prototype.getFormParams() == null ? null : new ArrayList(prototype.getFormParams()); this.parts = prototype.getParts() == null ? null : new ArrayList(prototype.getParts()); @@ -138,10 +135,6 @@ public InputStream getStreamData() { return streamData; } - public EntityWriter getEntityWriter() { - return entityWriter; - } - public BodyGenerator getBodyGenerator() { return bodyGenerator; } @@ -376,7 +369,6 @@ public void resetNonMultipartData() { request.byteData = null; request.stringData = null; request.streamData = null; - request.entityWriter = null; request.length = -1; } @@ -413,19 +405,6 @@ public T setBody(InputStream stream) { return derived.cast(this); } - public T setBody(EntityWriter dataWriter) { - return setBody(dataWriter, -1); - } - - public T setBody(EntityWriter dataWriter, long length) { - resetFormParams(); - resetNonMultipartData(); - resetMultipartData(); - request.entityWriter = dataWriter; - request.length = length; - return derived.cast(this); - } - public T setBody(BodyGenerator bodyGenerator) { request.bodyGenerator = bodyGenerator; return derived.cast(this); 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 976e305cb2..f2924653d5 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 @@ -94,7 +94,6 @@ import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; -import java.io.OutputStream; import java.net.ConnectException; import java.net.InetAddress; import java.net.Socket; @@ -290,8 +289,6 @@ private HttpMethodBase createMethod(HttpClient client, Request request) throws I post.setRequestEntity(mre); post.setRequestHeader("Content-Type", mre.getContentType()); post.setRequestHeader("Content-Length", String.valueOf(mre.getContentLength())); - } else if (request.getEntityWriter() != null) { - post.setRequestEntity(new EntityWriterRequestEntity(request.getEntityWriter(), computeAndSetContentLength(request, post))); } else if (request.getFile() != null) { File file = request.getFile(); if (!file.isFile()) { @@ -712,32 +709,6 @@ private MultipartRequestEntity createMultipartRequestEntity(String charset, List return new MultipartRequestEntity(parts, methodParams); } - public class EntityWriterRequestEntity implements org.apache.commons.httpclient.methods.RequestEntity { - private Request.EntityWriter entityWriter; - private long contentLength; - - public EntityWriterRequestEntity(Request.EntityWriter entityWriter, long contentLength) { - this.entityWriter = entityWriter; - this.contentLength = contentLength; - } - - public long getContentLength() { - return contentLength; - } - - public String getContentType() { - return null; - } - - public boolean isRepeatable() { - return false; - } - - public void writeRequest(OutputStream out) throws IOException { - entityWriter.writeEntity(out); - } - } - private static class TrustingSSLSocketFactory extends SSLSocketFactory { private SSLSocketFactory delegate; 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 a419c64a60..bd883f5260 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 @@ -1848,7 +1848,6 @@ private final class BodyHandlerFactory { new StringBodyHandler(), new ByteArrayBodyHandler(), new ParamsBodyHandler(), - new EntityWriterBodyHandler(), new StreamDataBodyHandler(), new PartsBodyHandler(), new FileBodyHandler(), @@ -2040,41 +2039,6 @@ public boolean doHandle(final FilterChainContext ctx, } // END ParamsBodyHandler - - private static final class EntityWriterBodyHandler extends BodyHandler { - - // -------------------------------------------- Methods from BodyHandler - - - public boolean handlesBodyType(final Request request) { - return (request.getEntityWriter() != null); - } - - @SuppressWarnings({"unchecked"}) - public boolean doHandle(final FilterChainContext ctx, - final Request request, - final HttpRequestPacket requestPacket) - throws IOException { - - final MemoryManager mm = ctx.getMemoryManager(); - Buffer b = mm.allocate(512); - BufferOutputStream o = new BufferOutputStream(mm, b, true); - final Request.EntityWriter writer = request.getEntityWriter(); - writer.writeEntity(o); - b = o.getBuffer(); - b.trim(); - if (b.hasRemaining()) { - final HttpContent content = requestPacket.httpContentBuilder().content(b).build(); - content.setLast(true); - ctx.write(content, ((!requestPacket.isCommitted()) ? ctx.getTransportContext().getCompletionHandler() : null)); - } - - return true; - } - - } // END EntityWriterBodyHandler - - private static final class StreamDataBodyHandler extends BodyHandler { // -------------------------------------------- Methods from BodyHandler 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 233d70b592..46ba6be474 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 @@ -597,13 +597,6 @@ private void configure(UriComponents uri, HttpURLConnection urlConnection, Reque urlConnection.setRequestProperty("Content-Length", String.valueOf(mre.getContentLength())); mre.writeRequest(urlConnection.getOutputStream()); - } else if (request.getEntityWriter() != null) { - int lenght = (int) request.getContentLength(); - if (lenght != -1) { - urlConnection.setRequestProperty("Content-Length", String.valueOf(lenght)); - urlConnection.setFixedLengthStreamingMode(lenght); - } - request.getEntityWriter().writeEntity(urlConnection.getOutputStream()); } else if (request.getFile() != null) { File file = request.getFile(); if (!file.isFile()) { 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 0fd1eb3c49..7ebb12ff12 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 @@ -62,7 +62,6 @@ import org.jboss.netty.bootstrap.ClientBootstrap; import org.jboss.netty.buffer.ChannelBuffer; -import org.jboss.netty.buffer.ChannelBufferOutputStream; import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFuture; @@ -835,17 +834,6 @@ private static HttpRequest construct(AsyncHttpClientConfig config, Request reque nettyRequest.setHeader(HttpHeaders.Names.CONTENT_LENGTH, String.valueOf(contentLength)); } - } else if (request.getEntityWriter() != null) { - int length = (int) request.getContentLength(); - - if (length == -1) { - length = MAX_BUFFERED_BYTES; - } - - ChannelBuffer b = ChannelBuffers.dynamicBuffer(length); - request.getEntityWriter().writeEntity(new ChannelBufferOutputStream(b)); - nettyRequest.setHeader(HttpHeaders.Names.CONTENT_LENGTH, b.writerIndex()); - nettyRequest.setContent(b); } else if (request.getFile() != null) { File file = request.getFile(); if (!file.isFile()) { 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 6f28bf1ecb..4e026fec02 100755 --- a/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java +++ b/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java @@ -24,7 +24,6 @@ import java.io.ByteArrayInputStream; import java.io.IOException; -import java.io.OutputStream; import java.net.ConnectException; import java.net.HttpURLConnection; import java.net.URL; @@ -669,56 +668,6 @@ public Response onCompleted(Response response) throws Exception { } } - @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.setLength(sb.length() - 1); - byte[] bytes = sb.toString().getBytes(); - h.add("Content-Length", String.valueOf(bytes.length)); - - 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 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(); - } - return response; - } - }).get(); - if (!l.await(TIMEOUT, TimeUnit.SECONDS)) { - Assert.fail("Timeout out"); - } - } finally { - client.close(); - } - } - @Test(groups = { "standalone", "default_provider", "async" }) public void asyncDoPostMultiPartTest() throws Throwable { AsyncHttpClient client = getAsyncHttpClient(null); From d2f7b38cdd5c5b4f85d0986e751229b71ca01e4c Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 10 Jul 2014 16:17:08 +0200 Subject: [PATCH 384/701] [maven-release-plugin] prepare release async-http-client-1.9.0-BETA1 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 201d84a35f..5027d7f86a 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.9.0-SNAPSHOT + 1.9.0-BETA1 jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From 8797d29bbf90e93a248a48eb5ce22a07f219a8f5 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 10 Jul 2014 16:17:13 +0200 Subject: [PATCH 385/701] [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 5027d7f86a..201d84a35f 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.9.0-BETA1 + 1.9.0-SNAPSHOT jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From d4170ac22dc1d498ef7dab39c5116fe3c4482863 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 11 Jul 2014 14:36:44 +0200 Subject: [PATCH 386/701] Major Netty provider refactoring --- .../http/client/AsyncHttpClientConfig.java | 33 +- .../client/AsyncHttpClientConfigBean.java | 5 - .../http/client/AsyncHttpProviderConfig.java | 2 +- .../grizzly/ConnectionPool.java} | 14 +- .../grizzly/GrizzlyAsyncHttpProvider.java | 29 +- .../GrizzlyAsyncHttpProviderConfig.java | 12 +- ...nsPool.java => GrizzlyConnectionPool.java} | 18 +- .../client/providers/netty/ChannelPool.java | 63 + .../providers/netty/DefaultChannelPool.java | 353 ++++++ .../netty/NettyAsyncHttpProvider.java | 1060 ++++++++--------- .../netty/NettyAsyncHttpProviderConfig.java | 176 +-- .../providers/netty/NettyConnectionsPool.java | 300 ----- .../providers/netty/NettyResponseFuture.java | 7 +- .../http/client/providers/netty/Protocol.java | 2 +- .../java/com/ning/http/util/MiscUtils.java | 4 - .../client/async/RetryNonBlockingIssue.java | 10 - .../netty/NettyAsyncHttpProviderTest.java | 2 +- .../async/netty/NettyConnectionPoolTest.java | 27 +- .../NettyRedirectConnectionUsageTest.java | 7 +- 19 files changed, 1120 insertions(+), 1004 deletions(-) rename src/main/java/com/ning/http/client/{ConnectionsPool.java => providers/grizzly/ConnectionPool.java} (84%) rename src/main/java/com/ning/http/client/providers/grizzly/{GrizzlyConnectionsPool.java => GrizzlyConnectionPool.java} (97%) create mode 100644 src/main/java/com/ning/http/client/providers/netty/ChannelPool.java create mode 100644 src/main/java/com/ning/http/client/providers/netty/DefaultChannelPool.java delete mode 100644 src/main/java/com/ning/http/client/providers/netty/NettyConnectionsPool.java diff --git a/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java b/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java index 84aa24e898..a510949e1c 100644 --- a/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java @@ -67,7 +67,6 @@ public class AsyncHttpClientConfig { protected ProxyServerSelector proxyServerSelector; protected SSLContext sslContext; protected AsyncHttpProviderConfig providerConfig; - protected ConnectionsPool connectionsPool; protected Realm realm; protected List requestFilters; protected List responseFilters; @@ -105,7 +104,7 @@ private AsyncHttpClientConfig(int maxTotalConnections, ProxyServerSelector proxyServerSelector, SSLContext sslContext, AsyncHttpProviderConfig providerConfig, - ConnectionsPool connectionsPool, Realm realm, + Realm realm, List requestFilters, List responseFilters, List ioExceptionFilters, @@ -136,7 +135,6 @@ private AsyncHttpClientConfig(int maxTotalConnections, this.allowPoolingConnection = keepAlive; this.sslContext = sslContext; this.providerConfig = providerConfig; - this.connectionsPool = connectionsPool; this.realm = realm; this.requestFilters = requestFilters; this.responseFilters = responseFilters; @@ -244,7 +242,7 @@ public int getMaxRedirects() { } /** - * Is the {@link ConnectionsPool} support enabled. + * Is the {@link ChannelPool} support enabled. * * @return true if keep-alive is enabled */ @@ -299,15 +297,6 @@ public SSLContext getSSLContext() { return sslContext; } - /** - * Return an instance of {@link ConnectionsPool} - * - * @return an instance of {@link ConnectionsPool} - */ - public ConnectionsPool getConnectionsPool() { - return connectionsPool; - } - /** * Return the {@link com.ning.http.client.AsyncHttpProviderConfig} * @@ -514,7 +503,6 @@ public static class Builder { private ProxyServerSelector proxyServerSelector = null; private SSLContext sslContext; private AsyncHttpProviderConfig providerConfig; - private ConnectionsPool connectionsPool; private Realm realm; private final List requestFilters = new LinkedList(); private final List responseFilters = new LinkedList(); @@ -651,9 +639,9 @@ public Builder setUserAgent(String userAgent) { } /** - * Set true if connection can be pooled by a {@link ConnectionsPool}. Default is true. + * Set true if connection can be pooled by a {@link ChannelPool}. Default is true. * - * @param allowPoolingConnection true if connection can be pooled by a {@link ConnectionsPool} + * @param allowPoolingConnection true if connection can be pooled by a {@link ChannelPool} * @return a {@link Builder} */ public Builder setAllowPoolingConnection(boolean allowPoolingConnection) { @@ -718,17 +706,6 @@ public Builder setAsyncHttpClientProviderConfig(AsyncHttpProviderConfig pr return this; } - /** - * Set the {@link ConnectionsPool} - * - * @param connectionsPool the {@link ConnectionsPool} - * @return a {@link Builder} - */ - public Builder setConnectionsPool(ConnectionsPool connectionsPool) { - this.connectionsPool = connectionsPool; - return this; - } - /** * Set the {@link Realm} that will be used for all requests. * @@ -976,7 +953,6 @@ public Builder setAcceptAnyCertificate(boolean acceptAnyCertificate) { public Builder(AsyncHttpClientConfig prototype) { allowPoolingConnection = prototype.isAllowPoolingConnection(); providerConfig = prototype.getAsyncHttpProviderConfig(); - connectionsPool = prototype.getConnectionsPool(); connectionTimeOutInMs = prototype.getConnectionTimeoutInMs(); idleConnectionInPoolTimeoutInMs = prototype.getIdleConnectionInPoolTimeoutInMs(); idleConnectionTimeoutInMs = prototype.getIdleConnectionTimeoutInMs(); @@ -1060,7 +1036,6 @@ public Thread newThread(Runnable r) { proxyServerSelector, // sslContext, // providerConfig, // - connectionsPool, // realm, // requestFilters, // responseFilters, // diff --git a/src/main/java/com/ning/http/client/AsyncHttpClientConfigBean.java b/src/main/java/com/ning/http/client/AsyncHttpClientConfigBean.java index 170fbf31a1..a4fe56050a 100644 --- a/src/main/java/com/ning/http/client/AsyncHttpClientConfigBean.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClientConfigBean.java @@ -179,11 +179,6 @@ public AsyncHttpClientConfigBean setProviderConfig(AsyncHttpProviderConfig return this; } - public AsyncHttpClientConfigBean setConnectionsPool(ConnectionsPool connectionsPool) { - this.connectionsPool = connectionsPool; - return this; - } - public AsyncHttpClientConfigBean setRealm(Realm realm) { this.realm = realm; return this; diff --git a/src/main/java/com/ning/http/client/AsyncHttpProviderConfig.java b/src/main/java/com/ning/http/client/AsyncHttpProviderConfig.java index f73c909b5f..decaa2074d 100644 --- a/src/main/java/com/ning/http/client/AsyncHttpProviderConfig.java +++ b/src/main/java/com/ning/http/client/AsyncHttpProviderConfig.java @@ -29,7 +29,7 @@ public interface AsyncHttpProviderConfig { * @param value the value of the property * @return this instance of AsyncHttpProviderConfig */ - AsyncHttpProviderConfig addProperty(U name, V value); + AsyncHttpProviderConfig addProperty(U name, V value); /** * Return the value associated with the property's name diff --git a/src/main/java/com/ning/http/client/ConnectionsPool.java b/src/main/java/com/ning/http/client/providers/grizzly/ConnectionPool.java similarity index 84% rename from src/main/java/com/ning/http/client/ConnectionsPool.java rename to src/main/java/com/ning/http/client/providers/grizzly/ConnectionPool.java index 02dd4283d5..ed4765d0a1 100644 --- a/src/main/java/com/ning/http/client/ConnectionsPool.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/ConnectionPool.java @@ -14,12 +14,14 @@ * under the License. * */ -package com.ning.http.client; +package com.ning.http.client.providers.grizzly; + +import org.glassfish.grizzly.Connection; /** * An interface used by an {@link AsyncHttpProvider} for caching http connections. */ -public interface ConnectionsPool { +public interface ConnectionPool { /** * Add a connection tpo the pool @@ -28,7 +30,7 @@ public interface ConnectionsPool { * @param connection an I/O connection * @return true if added. */ - boolean offer(U uri, V connection); + boolean offer(String uri, Connection connection); /** * Remove the connection associated with the uri. @@ -36,7 +38,7 @@ public interface ConnectionsPool { * @param uri the uri used when invoking addConnection * @return the connection associated with the uri */ - V poll(U uri); + Connection poll(String uri); /** * Remove all connections from the cache. A connection might have been associated with several uri. @@ -44,11 +46,11 @@ public interface ConnectionsPool { * @param connection a connection * @return the true if the connection has been removed */ - boolean removeAll(V connection); + boolean removeAll(Connection connection); /** * Return true if a connection can be cached. A implementation can decide based on some rules to allow caching - * Calling this method is equivalent of checking the returned value of {@link ConnectionsPool#offer(Object, Object)} + * Calling this method is equivalent of checking the returned value of {@link ConnectionPool#offer(Object, Object)} * * @return true if a connection can be cached. */ 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 bd883f5260..f598af7bdd 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 @@ -88,7 +88,6 @@ import org.glassfish.grizzly.ssl.SSLFilter; 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; @@ -112,7 +111,6 @@ import com.ning.http.client.AsyncHttpProviderConfig; import com.ning.http.client.Body; import com.ning.http.client.BodyGenerator; -import com.ning.http.client.ConnectionsPool; import com.ning.http.client.FluentCaseInsensitiveStringsMap; import com.ning.http.client.HttpResponseBodyPart; import com.ning.http.client.HttpResponseHeaders; @@ -180,6 +178,7 @@ public class GrizzlyAsyncHttpProvider implements AsyncHttpProvider { private final TCPNIOTransport clientTransport; private final AsyncHttpClientConfig clientConfig; + private final GrizzlyAsyncHttpProviderConfig providerConfig; private final ConnectionManager connectionManager; DelayedExecutor.Resolver resolver; @@ -194,10 +193,14 @@ public class GrizzlyAsyncHttpProvider implements AsyncHttpProvider { public GrizzlyAsyncHttpProvider(final AsyncHttpClientConfig clientConfig) { this.clientConfig = clientConfig; + this.providerConfig = + clientConfig.getAsyncHttpProviderConfig() instanceof GrizzlyAsyncHttpProviderConfig ? + (GrizzlyAsyncHttpProviderConfig) clientConfig.getAsyncHttpProviderConfig() + : new GrizzlyAsyncHttpProviderConfig(); final TCPNIOTransportBuilder builder = TCPNIOTransportBuilder.newInstance(); clientTransport = builder.build(); initializeTransport(clientConfig); - connectionManager = new ConnectionManager(this, clientTransport); + connectionManager = new ConnectionManager(this, clientTransport, providerConfig); try { clientTransport.start(); } catch (IOException ioe) { @@ -395,10 +398,6 @@ 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, (Integer) providerConfig.getProperty(MAX_HTTP_PACKET_HEADER_SIZE)); final AsyncHttpClientFilter clientFilter = @@ -1789,7 +1788,7 @@ public boolean applyDecoding(HttpHeader httpPacket) { } // END ClientContentEncoding - private static final class NonCachingPool implements ConnectionsPool { + private static final class NonCachingPool implements ConnectionPool { // ---------------------------------------- Methods from ConnectionsPool @@ -2316,7 +2315,7 @@ static class ConnectionManager { private static final Attribute DO_NOT_CACHE = Grizzly.DEFAULT_ATTRIBUTE_BUILDER.createAttribute(ConnectionManager.class.getName()); - private final ConnectionsPool pool; + private final ConnectionPool pool; private final TCPNIOConnectorHandler connectionHandler; private final ConnectionMonitor connectionMonitor; private final GrizzlyAsyncHttpProvider provider; @@ -2324,18 +2323,18 @@ static class ConnectionManager { // -------------------------------------------------------- Constructors ConnectionManager(final GrizzlyAsyncHttpProvider provider, - final TCPNIOTransport transport) { + final TCPNIOTransport transport, + final GrizzlyAsyncHttpProviderConfig providerConfig) { - ConnectionsPool connectionPool; + ConnectionPool connectionPool; this.provider = provider; final AsyncHttpClientConfig config = provider.clientConfig; if (config.isAllowPoolingConnection()) { - ConnectionsPool pool = config.getConnectionsPool(); + ConnectionPool pool = providerConfig != null ? providerConfig.getConnectionPool() : null; if (pool != null) { - //noinspection unchecked - connectionPool = (ConnectionsPool) pool; + connectionPool = pool; } else { - connectionPool = new GrizzlyConnectionsPool((config)); + connectionPool = new GrizzlyConnectionPool((config)); } } else { connectionPool = new NonCachingPool(); 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 066e1a959d..73a9d6a7cf 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; @@ -90,7 +91,9 @@ boolean hasDefaultValue() { } // END PROPERTY private final Map attributes = new HashMap(); - + + protected ConnectionPool connectionPool; + // ------------------------------------ Methods from AsyncHttpProviderConfig /** @@ -157,4 +160,11 @@ public Set> propertiesSet() { return attributes.entrySet(); } + public ConnectionPool getConnectionPool() { + return connectionPool; + } + + public void setConnectionPool(ConnectionPool connectionPool) { + this.connectionPool = connectionPool; + } } diff --git a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyConnectionsPool.java b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyConnectionPool.java similarity index 97% rename from src/main/java/com/ning/http/client/providers/grizzly/GrizzlyConnectionsPool.java rename to src/main/java/com/ning/http/client/providers/grizzly/GrizzlyConnectionPool.java index b5e0925d52..4828b762ee 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyConnectionsPool.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyConnectionPool.java @@ -16,7 +16,6 @@ import static com.ning.http.util.DateUtils.millisTime; import com.ning.http.client.AsyncHttpClientConfig; -import com.ning.http.client.ConnectionsPool; import org.glassfish.grizzly.CloseListener; import org.glassfish.grizzly.CloseType; @@ -41,14 +40,14 @@ import java.util.concurrent.atomic.AtomicInteger; /** - * {@link ConnectionsPool} implementation. + * {@link ConnectionPool} implementation. * * @author The Grizzly Team * @since 1.7.0 */ -public class GrizzlyConnectionsPool implements ConnectionsPool { +public class GrizzlyConnectionPool implements ConnectionPool { - private final static Logger LOG = LoggerFactory.getLogger(GrizzlyConnectionsPool.class); + private final static Logger LOG = LoggerFactory.getLogger(GrizzlyConnectionPool.class); private final ConcurrentHashMap connectionsPool = new ConcurrentHashMap(); @@ -74,7 +73,7 @@ public void onClosed(Connection connection, CloseType closeType) connection.toString()); } } - GrizzlyConnectionsPool.this.removeAll(connection); + GrizzlyConnectionPool.this.removeAll(connection); } }; @@ -83,7 +82,7 @@ public void onClosed(Connection connection, CloseType closeType) @SuppressWarnings("UnusedDeclaration") - public GrizzlyConnectionsPool(final boolean cacheSSLConnections, + public GrizzlyConnectionPool(final boolean cacheSSLConnections, final int timeout, final int maxConnectionLifeTimeInMs, final int maxConnectionsPerHost, @@ -109,8 +108,7 @@ public GrizzlyConnectionsPool(final boolean cacheSSLConnections, } } - - public GrizzlyConnectionsPool(final AsyncHttpClientConfig config) { + public GrizzlyConnectionPool(final AsyncHttpClientConfig config) { cacheSSLConnections = config.isSslConnectionPoolEnabled(); timeout = config.getIdleConnectionInPoolTimeoutInMs(); @@ -299,7 +297,7 @@ public static final class DelayedExecutor { public DelayedExecutor(final ExecutorService threadPool, - final GrizzlyConnectionsPool connectionsPool) { + final GrizzlyConnectionPool connectionsPool) { this(threadPool, 1000, TimeUnit.MILLISECONDS, connectionsPool); } @@ -307,7 +305,7 @@ public DelayedExecutor(final ExecutorService threadPool, public DelayedExecutor(final ExecutorService threadPool, final long checkInterval, final TimeUnit timeunit, - final GrizzlyConnectionsPool connectionsPool) { + final GrizzlyConnectionPool connectionsPool) { this.threadPool = threadPool; this.checkIntervalMs = TimeUnit.MILLISECONDS.convert(checkInterval, timeunit); totalCachedConnections = connectionsPool.totalCachedConnections; diff --git a/src/main/java/com/ning/http/client/providers/netty/ChannelPool.java b/src/main/java/com/ning/http/client/providers/netty/ChannelPool.java new file mode 100644 index 0000000000..c8331cd3b7 --- /dev/null +++ b/src/main/java/com/ning/http/client/providers/netty/ChannelPool.java @@ -0,0 +1,63 @@ +/* + * 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.channel.Channel; + +/** + * An interface used by an {@link AsyncHttpProvider} for caching http connections. + */ +public interface ChannelPool { + + /** + * Add a connection to the pool + * + * @param uri a uri used to retrieve the cached connection + * @param connection an I/O connection + * @return true if added. + */ + boolean offer(String uri, Channel connection); + + /** + * Remove the connection associated with the uri. + * + * @param uri the uri used when invoking addConnection + * @return the connection associated with the uri + */ + Channel poll(String uri); + + /** + * Remove all connections from the cache. A connection might have been associated with several uri. + * + * @param connection a connection + * @return the true if the connection has been removed + */ + boolean removeAll(Channel connection); + + /** + * Return true if a connection can be cached. A implementation can decide based on some rules to allow caching + * Calling this method is equivalent of checking the returned value of {@link ChannelPool#offer(Object, Object)} + * + * @return true if a connection can be cached. + */ + boolean canCacheConnection(); + + /** + * Destroy all connections that has been cached by this instance. + */ + void destroy(); +} diff --git a/src/main/java/com/ning/http/client/providers/netty/DefaultChannelPool.java b/src/main/java/com/ning/http/client/providers/netty/DefaultChannelPool.java new file mode 100644 index 0000000000..812ccc3a8e --- /dev/null +++ b/src/main/java/com/ning/http/client/providers/netty/DefaultChannelPool.java @@ -0,0 +1,353 @@ +/* + * 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.providers.netty; + +import static com.ning.http.util.DateUtils.millisTime; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; + +import org.jboss.netty.channel.Channel; +import org.jboss.netty.util.Timeout; +import org.jboss.netty.util.Timer; +import org.jboss.netty.util.TimerTask; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.ning.http.client.providers.netty.NettyAsyncHttpProvider.DiscardEvent; + +/** + * A simple implementation of {@link com.ning.http.client.ChannelPool} based on a {@link java.util.concurrent.ConcurrentHashMap} + */ +public final class DefaultChannelPool implements ChannelPool { + + private static final Logger LOGGER = LoggerFactory.getLogger(DefaultChannelPool.class); + + private final ConcurrentHashMap> connectionsPool = new ConcurrentHashMap>(); + private final ConcurrentHashMap channel2Creation = new ConcurrentHashMap(); + private final AtomicInteger size = new AtomicInteger(); + private final AtomicBoolean isClosed = new AtomicBoolean(false); + private final Timer nettyTimer; + private final boolean sslConnectionPoolEnabled; + private final int maxTotalConnections; + private final boolean maxTotalConnectionsDisabled; + private final int maxConnectionPerHost; + private final boolean maxConnectionPerHostDisabled; + private final int maxConnectionTTL; + private final boolean maxConnectionTTLDisabled; + private final long maxIdleTime; + private final boolean maxIdleTimeDisabled; + private final long cleanerPeriod; + + public DefaultChannelPool(NettyAsyncHttpProvider provider, Timer hashedWheelTimer) { + this(provider.getConfig().getMaxTotalConnections(),// + provider.getConfig().getMaxConnectionPerHost(),// + provider.getConfig().getIdleConnectionInPoolTimeoutInMs(),// + provider.getConfig().getMaxConnectionLifeTimeInMs(),// + provider.getConfig().isSslConnectionPoolEnabled(),// + hashedWheelTimer); + } + + public DefaultChannelPool(// + int maxTotalConnections,// + int maxConnectionPerHost,// + long maxIdleTime,// + int maxConnectionTTL,// + boolean sslConnectionPoolEnabled,// + Timer nettyTimer) { + this.maxTotalConnections = maxTotalConnections; + maxTotalConnectionsDisabled = maxTotalConnections <= 0; + this.maxConnectionPerHost = maxConnectionPerHost; + maxConnectionPerHostDisabled = maxConnectionPerHost <= 0; + this.sslConnectionPoolEnabled = sslConnectionPoolEnabled; + this.maxIdleTime = maxIdleTime; + this.maxConnectionTTL = maxConnectionTTL; + maxConnectionTTLDisabled = maxConnectionTTL <= 0; + this.nettyTimer = nettyTimer; + maxIdleTimeDisabled = maxIdleTime <= 0; + + cleanerPeriod = Math.min(maxConnectionTTLDisabled ? Long.MAX_VALUE : maxConnectionTTL, maxIdleTimeDisabled ? Long.MAX_VALUE + : maxIdleTime); + + if (!maxConnectionTTLDisabled || !maxIdleTimeDisabled) + scheduleNewIdleChannelDetector(new IdleChannelDetector()); + } + + private void scheduleNewIdleChannelDetector(TimerTask task) { + nettyTimer.newTimeout(task, cleanerPeriod, TimeUnit.MILLISECONDS); + } + + private static final class ChannelCreation { + final long creationTime; + final String key; + + ChannelCreation(long creationTime, String key) { + this.creationTime = creationTime; + this.key = key; + } + } + + private static final class IdleChannel { + final Channel channel; + final long start; + + IdleChannel(Channel channel, long start) { + if (channel == null) + throw new NullPointerException("channel"); + this.channel = channel; + this.start = start; + } + + @Override + // only depends on channel + public boolean equals(Object o) { + return this == o || (o instanceof IdleChannel && channel.equals(IdleChannel.class.cast(o).channel)); + } + + @Override + public int hashCode() { + return channel.hashCode(); + } + } + + private boolean isTTLExpired(Channel channel, long now) { + if (maxConnectionTTLDisabled) + return false; + + ChannelCreation creation = channel2Creation.get(channel); + return creation == null || now - creation.creationTime >= maxConnectionTTL; + } + + private boolean isRemotelyClosed(Channel channel) { + return !channel.isConnected() || !channel.isOpen(); + } + + private final class IdleChannelDetector implements TimerTask { + + private boolean isIdleTimeoutExpired(IdleChannel idleChannel, long now) { + return !maxIdleTimeDisabled && now - idleChannel.start >= maxIdleTime; + } + + private List expiredChannels(ConcurrentLinkedQueue pool, long now) { + // lazy create + List idleTimeoutChannels = null; + for (IdleChannel idleChannel : pool) { + if (isTTLExpired(idleChannel.channel, now) || isIdleTimeoutExpired(idleChannel, now) + || isRemotelyClosed(idleChannel.channel)) { + LOGGER.debug("Adding Candidate expired Channel {}", idleChannel.channel); + if (idleTimeoutChannels == null) + idleTimeoutChannels = new ArrayList(); + idleTimeoutChannels.add(idleChannel); + } + } + + return idleTimeoutChannels != null ? idleTimeoutChannels : Collections. emptyList(); + } + + private boolean isChannelCloseable(Channel channel) { + boolean closeable = true; + Object attachment = channel.getPipeline().getContext(NettyAsyncHttpProvider.class).getAttachment(); + if (attachment instanceof NettyResponseFuture) { + NettyResponseFuture future = (NettyResponseFuture) attachment; + closeable = !future.isDone() || !future.isCancelled(); + if (!closeable) + LOGGER.error("Future not in appropriate state %s, not closing", future); + } + return true; + } + + private final List closeChannels(List candidates) { + + // lazy create, only if we have a non-closeable channel + List closedChannels = null; + for (int i = 0; i < candidates.size(); i++) { + IdleChannel idleChannel = candidates.get(i); + if (!isChannelCloseable(idleChannel.channel)) + if (closedChannels == null) { + // first non closeable to be skipped, copy all previously skipped closeable channels + closedChannels = new ArrayList(candidates.size()); + for (int j = 0; j < i; j++) + closedChannels.add(candidates.get(j)); + } else { + LOGGER.debug("Closing Idle Channel {}", idleChannel.channel); + close(idleChannel.channel); + if (closedChannels != null) { + closedChannels.add(idleChannel); + } + } + } + + return closedChannels != null ? closedChannels : candidates; + } + + public void run(Timeout timeout) throws Exception { + + if (isClosed.get()) + return; + + try { + if (LOGGER.isDebugEnabled()) { + for (String key : connectionsPool.keySet()) { + LOGGER.debug("Entry count for : {} : {}", key, connectionsPool.get(key).size()); + } + } + + long start = millisTime(); + int totalCount = size.get(); + int closedCount = 0; + + for (ConcurrentLinkedQueue pool : connectionsPool.values()) { + // store in intermediate unsynchronized lists to minimize the impact on the ConcurrentLinkedQueue + List candidateExpiredChannels = expiredChannels(pool, start); + List closedChannels = closeChannels(candidateExpiredChannels); + pool.removeAll(closedChannels); + int poolClosedCount = closedChannels.size(); + size.addAndGet(-poolClosedCount); + closedCount += poolClosedCount; + } + + long duration = millisTime() - start; + + LOGGER.debug("Closed {} connections out of {} in {}ms", closedCount, totalCount, duration); + + } catch (Throwable t) { + LOGGER.error("uncaught exception!", t); + } + + scheduleNewIdleChannelDetector(timeout.getTask()); + } + } + + private boolean addIdleChannel(ConcurrentLinkedQueue idleConnectionForKey, String key, Channel channel, long now) { + + // FIXME computing CLQ.size is not efficient + if (maxConnectionPerHostDisabled || idleConnectionForKey.size() < maxConnectionPerHost) { + IdleChannel idleChannel = new IdleChannel(channel, now); + return idleConnectionForKey.add(idleChannel); + } + LOGGER.debug("Maximum number of requests per key reached {} for {}", maxConnectionPerHost, key); + return false; + } + + /** + * {@inheritDoc} + */ + public boolean offer(String key, Channel channel) { + if (isClosed.get() || (!sslConnectionPoolEnabled && key.startsWith("https"))) + return false; + + long now = millisTime(); + + if (isTTLExpired(channel, now)) + return false; + + ConcurrentLinkedQueue idleConnectionForKey = connectionsPool.get(key); + if (idleConnectionForKey == null) { + ConcurrentLinkedQueue newPool = new ConcurrentLinkedQueue(); + idleConnectionForKey = connectionsPool.putIfAbsent(key, newPool); + if (idleConnectionForKey == null) + idleConnectionForKey = newPool; + } + + boolean added = addIdleChannel(idleConnectionForKey, key, channel, now); + if (added) { + size.incrementAndGet(); + channel2Creation.putIfAbsent(channel, new ChannelCreation(now, key)); + } + + return added; + } + + /** + * {@inheritDoc} + */ + public Channel poll(String key) { + if (!sslConnectionPoolEnabled && key.startsWith("https")) + return null; + + IdleChannel idleChannel = null; + ConcurrentLinkedQueue pooledConnectionForKey = connectionsPool.get(key); + if (pooledConnectionForKey != null) { + while (idleChannel == null) { + idleChannel = pooledConnectionForKey.poll(); + + if (idleChannel == null) + // pool is empty + break; + else if (isRemotelyClosed(idleChannel.channel)) { + idleChannel = null; + LOGGER.trace("Channel not connected or not opened, probably remotely closed!"); + } + } + } + if (idleChannel != null) { + size.decrementAndGet(); + return idleChannel.channel; + } else + return null; + } + + /** + * {@inheritDoc} + */ + public boolean removeAll(Channel channel) { + ChannelCreation creation = channel2Creation.remove(channel); + return !isClosed.get() && creation != null && connectionsPool.get(creation.key).remove(channel); + } + + /** + * {@inheritDoc} + */ + public boolean canCacheConnection() { + // FIXME: doesn't honor per host limit + // FIXME: doesn't account for borrowed channels + return !isClosed.get() && (maxTotalConnectionsDisabled || size.get() < maxTotalConnections); + } + + /** + * {@inheritDoc} + */ + public void destroy() { + if (isClosed.getAndSet(true)) + return; + + for (ConcurrentLinkedQueue pool : connectionsPool.values()) { + for (IdleChannel idleChannel : pool) + close(idleChannel.channel); + } + + connectionsPool.clear(); + channel2Creation.clear(); + size.set(0); + } + + private void close(Channel channel) { + try { + channel.getPipeline().getContext(NettyAsyncHttpProvider.class).setAttachment(DiscardEvent.INSTANCE); + channel2Creation.remove(channel); + channel.close(); + } catch (Throwable t) { + // noop + } + } + + public String toString() { + return String.format("NettyConnectionPool: {pool-size: %d}", size.get()); + } +} 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 7ebb12ff12..852e05b896 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,18 +15,6 @@ */ package com.ning.http.client.providers.netty; -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.AsyncHttpProviderUtils.getNonEmptyPath; import static com.ning.http.util.MiscUtils.isNonEmpty; @@ -37,7 +25,6 @@ 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.nio.channels.ClosedChannelException; @@ -48,7 +35,6 @@ 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.ExecutorService; @@ -78,9 +64,7 @@ import org.jboss.netty.channel.group.ChannelGroup; 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; import org.jboss.netty.handler.codec.http.HttpChunkTrailer; @@ -97,7 +81,6 @@ 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; -import org.jboss.netty.handler.ssl.ImmediateExecutor; import org.jboss.netty.handler.ssl.SslHandler; import org.jboss.netty.handler.stream.ChunkedFile; import org.jboss.netty.handler.stream.ChunkedWriteHandler; @@ -116,7 +99,6 @@ 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.FluentCaseInsensitiveStringsMap; import com.ning.http.client.HttpResponseBodyPart; import com.ning.http.client.HttpResponseHeaders; @@ -163,32 +145,25 @@ public class NettyAsyncHttpProvider extends SimpleChannelUpstreamHandler impleme static { REMOTELY_CLOSED_EXCEPTION.setStackTrace(new StackTraceElement[0]); } - public final static String HTTP_HANDLER = "httpHandler"; - public final static String SSL_HANDLER = "sslHandler"; - public final static String HTTP_PROCESSOR = "httpProcessor"; - public final static String WS_PROCESSOR = "wsProcessor"; + public static final String HTTP_HANDLER = "httpHandler"; + public static final String SSL_HANDLER = "sslHandler"; + public static final String HTTP_PROCESSOR = "httpProcessor"; + public static final String WS_PROCESSOR = "wsProcessor"; - private final static String HTTPS = "https"; - private final static String HTTP = "http"; + private static final String HTTPS = "https"; + private static final String HTTP = "http"; 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 static final Charset UTF8 = Charset.forName("UTF-8"); + private final ClientBootstrap plainBootstrap; private final ClientBootstrap secureBootstrap; private final ClientBootstrap webSocketBootstrap; private final ClientBootstrap secureWebSocketBootstrap; - private final static int MAX_BUFFERED_BYTES = 8192; 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; - private int httpsClientCodecMaxInitialLineLength = 4096; - private int httpsClientCodecMaxHeaderSize = 8192; - private int httpsClientCodecMaxChunkSize = 8192; private final ChannelGroup openChannels = new CleanupChannelGroup("asyncHttpClient") { @Override @@ -200,14 +175,13 @@ public boolean remove(Object o) { return removed; } }; - private final ConnectionsPool connectionsPool; + private final ChannelPool connectionsPool; + // FIXME should be the pool responsibility private Semaphore freeConnections = null; private final NettyAsyncHttpProviderConfig providerConfig; - private boolean executeConnectAsync = true; - public static final ThreadLocal IN_IO_THREAD = new ThreadLocalBoolean(); private final boolean trackConnections; private final boolean disableZeroCopy; - private final static NTLMEngine ntlmEngine = new NTLMEngine(); + private static final NTLMEngine ntlmEngine = new NTLMEngine(); private static SpnegoEngine spnegoEngine = null; private final Protocol httpProtocol = new HttpProtocol(); private final Protocol webSocketProtocol = new WebSocketProtocol(); @@ -231,30 +205,20 @@ public NettyAsyncHttpProvider(AsyncHttpClientConfig config) { LOGGER.warn("Request was enabled but Netty actually doesn't support this feature"); } - if (providerConfig.getProperty(USE_BLOCKING_IO) != null) { - socketChannelFactory = new OioClientSocketChannelFactory(config.executorService()); - allowReleaseSocketChannelFactory = true; - } else { - // check if external NioClientSocketChannelFactory is defined - Object oo = providerConfig.getProperty(SOCKET_CHANNEL_FACTORY); - if (oo instanceof NioClientSocketChannelFactory) { - socketChannelFactory = NioClientSocketChannelFactory.class.cast(oo); + // check if external NioClientSocketChannelFactory is defined + if (providerConfig.getSocketChannelFactory() != null) { + socketChannelFactory = providerConfig.getSocketChannelFactory(); + // cannot allow releasing shared channel factory + allowReleaseSocketChannelFactory = false; - // cannot allow releasing shared channel factory - allowReleaseSocketChannelFactory = false; - } else { - ExecutorService e; - Object o = providerConfig.getProperty(BOSS_EXECUTOR_SERVICE); - if (o instanceof ExecutorService) { - e = ExecutorService.class.cast(o); - } else { - e = Executors.newCachedThreadPool(); - } - int numWorkers = config.getIoThreadMultiplier() * Runtime.getRuntime().availableProcessors(); - log.trace("Number of application's worker threads is {}", numWorkers); - socketChannelFactory = new NioClientSocketChannelFactory(e, config.executorService(), numWorkers); - allowReleaseSocketChannelFactory = true; - } + } else { + ExecutorService e = providerConfig.getBossExecutorService(); + if (e == null) + e = Executors.newCachedThreadPool(); + int numWorkers = config.getIoThreadMultiplier() * Runtime.getRuntime().availableProcessors(); + LOGGER.trace("Number of application's worker threads is {}", numWorkers); + socketChannelFactory = new NioClientSocketChannelFactory(e, config.executorService(), numWorkers); + allowReleaseSocketChannelFactory = true; } allowStopNettyTimer = providerConfig.getNettyTimer() == null; @@ -266,16 +230,18 @@ public NettyAsyncHttpProvider(AsyncHttpClientConfig config) { secureBootstrap = new ClientBootstrap(socketChannelFactory); webSocketBootstrap = new ClientBootstrap(socketChannelFactory); secureWebSocketBootstrap = new ClientBootstrap(socketChannelFactory); + disableZeroCopy = providerConfig.isDisableZeroCopy(); + this.config = config; configureNetty(); // This is dangerous as we can't catch a wrong typed ConnectionsPool - ConnectionsPool cp = (ConnectionsPool) config.getConnectionsPool(); + ChannelPool cp = providerConfig.getChannelPool(); if (cp == null && config.isAllowPoolingConnection()) { - cp = new NettyConnectionsPool(this, nettyTimer); + cp = new DefaultChannelPool(this, nettyTimer); } else if (cp == null) { - cp = new NonConnectionsPool(); + cp = new NonChannelPool(); } this.connectionsPool = cp; @@ -285,8 +251,6 @@ public NettyAsyncHttpProvider(AsyncHttpClientConfig config) { } else { trackConnections = false; } - - disableZeroCopy = providerConfig.isDisableZeroCopy(); } private Timer newNettyTimer() { @@ -305,14 +269,14 @@ public String toString() { } void configureNetty() { - if (providerConfig != null) { - for (Entry entry : providerConfig.propertiesSet()) { - plainBootstrap.setOption(entry.getKey(), entry.getValue()); - } - configureHttpClientCodec(); - configureHttpsClientCodec(); + + // FIXME why not do that for other bootstraps + for (Entry entry : providerConfig.propertiesSet()) { + plainBootstrap.setOption(entry.getKey(), entry.getValue()); } + DefaultChannelFuture.setUseDeadLockChecker(providerConfig.isUseDeadLockChecker()); + plainBootstrap.setPipelineFactory(new ChannelPipelineFactory() { public ChannelPipeline getPipeline() throws Exception { @@ -328,16 +292,6 @@ public ChannelPipeline getPipeline() throws Exception { return pipeline; } }); - DefaultChannelFuture.setUseDeadLockChecker(false); - - if (providerConfig != null) { - Object value = providerConfig.getProperty(EXECUTE_ASYNC_CONNECT); - if (value instanceof Boolean) { - executeConnectAsync = Boolean.class.cast(value); - } else if (providerConfig.getProperty(DISABLE_NESTED_REQUEST) != null) { - DefaultChannelFuture.setUseDeadLockChecker(true); - } - } webSocketBootstrap.setPipelineFactory(new ChannelPipelineFactory() { @@ -351,22 +305,9 @@ public ChannelPipeline getPipeline() throws Exception { }); } - protected void configureHttpClientCodec() { - httpClientCodecMaxInitialLineLength = providerConfig.getProperty(HTTP_CLIENT_CODEC_MAX_INITIAL_LINE_LENGTH, Integer.class, httpClientCodecMaxInitialLineLength); - httpClientCodecMaxHeaderSize = providerConfig.getProperty(HTTP_CLIENT_CODEC_MAX_HEADER_SIZE, Integer.class, httpClientCodecMaxHeaderSize); - httpClientCodecMaxChunkSize = providerConfig.getProperty(HTTP_CLIENT_CODEC_MAX_CHUNK_SIZE, Integer.class, httpClientCodecMaxChunkSize); - } - - protected void configureHttpsClientCodec() { - httpsClientCodecMaxInitialLineLength = providerConfig.getProperty(HTTPS_CLIENT_CODEC_MAX_INITIAL_LINE_LENGTH, Integer.class, httpsClientCodecMaxInitialLineLength); - httpsClientCodecMaxHeaderSize = providerConfig.getProperty(HTTPS_CLIENT_CODEC_MAX_HEADER_SIZE, Integer.class, httpsClientCodecMaxHeaderSize); - httpsClientCodecMaxChunkSize = providerConfig.getProperty(HTTPS_CLIENT_CODEC_MAX_CHUNK_SIZE, Integer.class, httpsClientCodecMaxChunkSize); - } - SslHandler createSslHandler(String peerHost, int peerPort) throws GeneralSecurityException, IOException { SSLEngine sslEngine = SslUtils.getInstance().createClientSSLEngine(config, peerHost, peerPort); - return handshakeTimeoutInMillis > 0 ? new SslHandler(sslEngine, getDefaultBufferPool(), false, ImmediateExecutor.INSTANCE, nettyTimer, - handshakeTimeoutInMillis) : new SslHandler(sslEngine); + return handshakeTimeoutInMillis > 0 ? new SslHandler(sslEngine, getDefaultBufferPool(), false, nettyTimer, handshakeTimeoutInMillis) : new SslHandler(sslEngine); } void constructSSLPipeline(final NettyConnectListener cl) { @@ -413,7 +354,7 @@ private Channel lookupInCache(UriComponents uri, ProxyServer proxy, ConnectionPo final Channel channel = connectionsPool.poll(getPoolKey(uri, proxy, strategy)); if (channel != null) { - log.debug("Using cached Channel {}\n for uri {}\n", channel, uri); + LOGGER.debug("Using cached Channel {}\n for uri {}\n", channel, uri); try { // Always make sure the channel who got cached support the proper protocol. It could @@ -421,18 +362,22 @@ private Channel lookupInCache(UriComponents uri, ProxyServer proxy, ConnectionPo // https. return verifyChannelPipeline(channel, uri.getScheme()); } catch (Exception ex) { - log.debug(ex.getMessage(), ex); + LOGGER.debug(ex.getMessage(), ex); } } return null; } private HttpClientCodec createHttpClientCodec() { - return new HttpClientCodec(httpClientCodecMaxInitialLineLength, httpClientCodecMaxHeaderSize, httpClientCodecMaxChunkSize); + return new HttpClientCodec(providerConfig.getHttpClientCodecMaxInitialLineLength(),// + providerConfig.getHttpClientCodecMaxHeaderSize(),// + providerConfig.getHttpClientCodecMaxChunkSize()); } private HttpClientCodec createHttpsClientCodec() { - return new HttpClientCodec(httpsClientCodecMaxInitialLineLength, httpsClientCodecMaxHeaderSize, httpsClientCodecMaxChunkSize); + return new HttpClientCodec(providerConfig.getHttpClientCodecMaxInitialLineLength(),// + providerConfig.getHttpClientCodecMaxHeaderSize(),// + providerConfig.getHttpClientCodecMaxChunkSize()); } private Channel verifyChannelPipeline(Channel channel, String scheme) throws IOException, GeneralSecurityException { @@ -450,6 +395,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(); + HttpHeaders nettyRequestHeaders = nettyRequest.headers(); boolean ssl = channel.getPipeline().get(SslHandler.class) != null; try { @@ -481,20 +427,20 @@ protected final void writeRequest(final Channel channel, final AsyncHttpClie } long length = body.getContentLength(); if (length >= 0) { - nettyRequest.setHeader(HttpHeaders.Names.CONTENT_LENGTH, length); + nettyRequestHeaders.set(HttpHeaders.Names.CONTENT_LENGTH, length); } else { - nettyRequest.setHeader(HttpHeaders.Names.TRANSFER_ENCODING, HttpHeaders.Values.CHUNKED); + nettyRequestHeaders.set(HttpHeaders.Names.TRANSFER_ENCODING, HttpHeaders.Values.CHUNKED); } } else if (isNonEmpty(future.getRequest().getParts())) { - String contentType = nettyRequest.getHeader(HttpHeaders.Names.CONTENT_TYPE); - String contentLength = nettyRequest.getHeader(HttpHeaders.Names.CONTENT_LENGTH); + String contentType = nettyRequestHeaders.get(HttpHeaders.Names.CONTENT_TYPE); + String contentLength = nettyRequestHeaders.get(HttpHeaders.Names.CONTENT_LENGTH); long length = -1; if (contentLength != null) { length = Long.parseLong(contentLength); } else { - nettyRequest.addHeader(HttpHeaders.Names.TRANSFER_ENCODING, HttpHeaders.Values.CHUNKED); + nettyRequestHeaders.add(HttpHeaders.Names.TRANSFER_ENCODING, HttpHeaders.Values.CHUNKED); } body = new MultipartBody(future.getRequest().getParts(), contentType, length); @@ -504,8 +450,8 @@ protected final void writeRequest(final Channel channel, final AsyncHttpClie if (future.getAsyncHandler() instanceof TransferCompletionHandler) { FluentCaseInsensitiveStringsMap h = new FluentCaseInsensitiveStringsMap(); - for (String s : nettyRequest.getHeaderNames()) { - for (String header : nettyRequest.getHeaders(s)) { + for (String s : nettyRequestHeaders.names()) { + for (String header : nettyRequestHeaders.getAll(s)) { h.add(s, header); } } @@ -522,11 +468,11 @@ protected final void writeRequest(final Channel channel, final AsyncHttpClie channel.write(nettyRequest).addListener(new ProgressListener(true, future.getAsyncHandler(), future)); } catch (Throwable cause) { - log.debug(cause.getMessage(), cause); + LOGGER.debug(cause.getMessage(), cause); try { channel.close(); } catch (RuntimeException ex) { - log.debug(ex.getMessage(), ex); + LOGGER.debug(ex.getMessage(), ex); } return; } @@ -542,7 +488,7 @@ protected final void writeRequest(final Channel channel, final AsyncHttpClie try { ChannelFuture writeFuture; if (disableZeroCopy || ssl) { - writeFuture = channel.write(new ChunkedFile(raf, 0, raf.length(), MAX_BUFFERED_BYTES)); + writeFuture = channel.write(new ChunkedFile(raf, 0, raf.length(), providerConfig.getChunkedFileChunkSize())); } else { final FileRegion region = new OptimizedFileRegion(raf, 0, raf.length()); writeFuture = channel.write(region); @@ -552,7 +498,7 @@ public void operationComplete(ChannelFuture cf) { try { raf.close(); } catch (IOException e) { - log.warn("Failed to close request body: {}", e.getMessage(), e); + LOGGER.warn("Failed to close request body: {}", e.getMessage(), e); } super.operationComplete(cf); } @@ -582,7 +528,7 @@ public void operationComplete(ChannelFuture cf) { try { b.close(); } catch (IOException e) { - log.warn("Failed to close request body: {}", e.getMessage(), e); + LOGGER.warn("Failed to close request body: {}", e.getMessage(), e); } super.operationComplete(cf); } @@ -594,7 +540,7 @@ public void operationComplete(ChannelFuture cf) { try { channel.close(); } catch (RuntimeException ex) { - log.debug(ex.getMessage(), ex); + LOGGER.debug(ex.getMessage(), ex); } } @@ -621,7 +567,7 @@ public void operationComplete(ChannelFuture cf) { } } - protected final static HttpRequest buildRequest(AsyncHttpClientConfig config, Request request, UriComponents uri, boolean allowConnect, ChannelBuffer buffer, ProxyServer proxyServer) + protected static final HttpRequest buildRequest(AsyncHttpClientConfig config, Request request, UriComponents uri, boolean allowConnect, ChannelBuffer buffer, ProxyServer proxyServer) throws IOException { String method = request.getMethod(); @@ -650,28 +596,32 @@ private static HttpRequest construct(AsyncHttpClientConfig config, Request reque HttpRequest nettyRequest; + if (m.equals(HttpMethod.CONNECT)) { nettyRequest = new DefaultHttpRequest(HttpVersion.HTTP_1_0, m, AsyncHttpProviderUtils.getAuthority(uri)); } else { String path = computeNonConnectRequestPath(config, uri, proxyServer); nettyRequest = new DefaultHttpRequest(HttpVersion.HTTP_1_1, m, path); } + + HttpHeaders nettyRequestHeaders = nettyRequest.headers(); + boolean webSocket = isWebSocket(uri.getScheme()); if (webSocket && !m.equals(HttpMethod.CONNECT)) { - 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(HttpHeaders.Names.SEC_WEBSOCKET_KEY, WebSocketUtil.getKey()); - nettyRequest.addHeader(HttpHeaders.Names.SEC_WEBSOCKET_VERSION, "13"); + nettyRequestHeaders.add(HttpHeaders.Names.UPGRADE, HttpHeaders.Values.WEBSOCKET); + nettyRequestHeaders.add(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.UPGRADE); + nettyRequestHeaders.add(HttpHeaders.Names.ORIGIN, "http://" + uri.getHost() + ":" + uri.getPort()); + nettyRequestHeaders.add(HttpHeaders.Names.SEC_WEBSOCKET_KEY, WebSocketUtil.getKey()); + nettyRequestHeaders.add(HttpHeaders.Names.SEC_WEBSOCKET_VERSION, "13"); } String host = request.getVirtualHost() != null ? request.getVirtualHost() : uri.getHost(); if (host != null) { // FIXME why write port when regular host? if (request.getVirtualHost() != null || uri.getPort() == -1) { - nettyRequest.setHeader(HttpHeaders.Names.HOST, host); + nettyRequestHeaders.set(HttpHeaders.Names.HOST, host); } else { - nettyRequest.setHeader(HttpHeaders.Names.HOST, host + ":" + uri.getPort()); + nettyRequestHeaders.set(HttpHeaders.Names.HOST, host + ":" + uri.getPort()); } } else { host = "127.0.0.1"; @@ -682,18 +632,18 @@ private static HttpRequest construct(AsyncHttpClientConfig config, Request reque String name = header.getKey(); if (!HttpHeaders.Names.HOST.equalsIgnoreCase(name)) { for (String value : header.getValue()) { - nettyRequest.addHeader(name, value); + nettyRequestHeaders.add(name, value); } } } if (config.isCompressionEnabled()) { - nettyRequest.setHeader(HttpHeaders.Names.ACCEPT_ENCODING, GZIP_DEFLATE); + nettyRequestHeaders.set(HttpHeaders.Names.ACCEPT_ENCODING, GZIP_DEFLATE); } } else { List auth = request.getHeaders().get(HttpHeaders.Names.PROXY_AUTHORIZATION); if (isNTLM(auth)) { - nettyRequest.addHeader(HttpHeaders.Names.PROXY_AUTHORIZATION, auth.get(0)); + nettyRequestHeaders.add(HttpHeaders.Names.PROXY_AUTHORIZATION, auth.get(0)); } } Realm realm = request.getRealm() != null ? request.getRealm() : config.getRealm(); @@ -712,12 +662,12 @@ private static HttpRequest construct(AsyncHttpClientConfig config, Request reque switch (realm.getAuthScheme()) { case BASIC: - nettyRequest.addHeader(HttpHeaders.Names.AUTHORIZATION, AuthenticatorUtils.computeBasicAuthentication(realm)); + nettyRequestHeaders.add(HttpHeaders.Names.AUTHORIZATION, AuthenticatorUtils.computeBasicAuthentication(realm)); break; case DIGEST: if (isNonEmpty(realm.getNonce())) { try { - nettyRequest.addHeader(HttpHeaders.Names.AUTHORIZATION, AuthenticatorUtils.computeDigestAuthentication(realm)); + nettyRequestHeaders.add(HttpHeaders.Names.AUTHORIZATION, AuthenticatorUtils.computeDigestAuthentication(realm)); } catch (NoSuchAlgorithmException e) { throw new SecurityException(e); } @@ -725,7 +675,7 @@ private static HttpRequest construct(AsyncHttpClientConfig config, Request reque break; case NTLM: try { - nettyRequest.addHeader(HttpHeaders.Names.AUTHORIZATION, ntlmEngine.generateType1Msg("NTLM " + domain, authHost)); + nettyRequestHeaders.add(HttpHeaders.Names.AUTHORIZATION, ntlmEngine.generateType1Msg("NTLM " + domain, authHost)); } catch (NTLMEngineException e) { IOException ie = new IOException(); ie.initCause(e); @@ -743,7 +693,7 @@ private static HttpRequest construct(AsyncHttpClientConfig config, Request reque ie.initCause(e); throw ie; } - nettyRequest.addHeader(HttpHeaders.Names.AUTHORIZATION, "Negotiate " + challengeHeader); + nettyRequestHeaders.add(HttpHeaders.Names.AUTHORIZATION, "Negotiate " + challengeHeader); break; case NONE: break; @@ -753,12 +703,12 @@ private static HttpRequest construct(AsyncHttpClientConfig config, Request reque } if (!webSocket && !request.getHeaders().containsKey(HttpHeaders.Names.CONNECTION)) { - nettyRequest.setHeader(HttpHeaders.Names.CONNECTION, AsyncHttpProviderUtils.keepAliveHeaderValue(config)); + nettyRequestHeaders.set(HttpHeaders.Names.CONNECTION, AsyncHttpProviderUtils.keepAliveHeaderValue(config)); } if (proxyServer != null) { if (!request.getHeaders().containsKey("Proxy-Connection")) { - nettyRequest.setHeader("Proxy-Connection", AsyncHttpProviderUtils.keepAliveHeaderValue(config)); + nettyRequestHeaders.set("Proxy-Connection", AsyncHttpProviderUtils.keepAliveHeaderValue(config)); } if (proxyServer.getPrincipal() != null) { @@ -768,7 +718,7 @@ private static HttpRequest construct(AsyncHttpClientConfig config, Request reque if (!isNTLM(auth)) { try { String msg = ntlmEngine.generateType1Msg(proxyServer.getNtlmDomain(), proxyServer.getHost()); - nettyRequest.setHeader(HttpHeaders.Names.PROXY_AUTHORIZATION, "NTLM " + msg); + nettyRequestHeaders.set(HttpHeaders.Names.PROXY_AUTHORIZATION, "NTLM " + msg); } catch (NTLMEngineException e) { IOException ie = new IOException(); ie.initCause(e); @@ -776,62 +726,62 @@ private static HttpRequest construct(AsyncHttpClientConfig config, Request reque } } } else { - nettyRequest.setHeader(HttpHeaders.Names.PROXY_AUTHORIZATION, AuthenticatorUtils.computeBasicAuthentication(proxyServer)); + nettyRequestHeaders.set(HttpHeaders.Names.PROXY_AUTHORIZATION, AuthenticatorUtils.computeBasicAuthentication(proxyServer)); } } } // Add default accept headers. if (!request.getHeaders().containsKey(HttpHeaders.Names.ACCEPT)) { - nettyRequest.setHeader(HttpHeaders.Names.ACCEPT, "*/*"); + nettyRequestHeaders.set(HttpHeaders.Names.ACCEPT, "*/*"); } String userAgentHeader = request.getHeaders().getFirstValue(HttpHeaders.Names.USER_AGENT); if (userAgentHeader != null) { - nettyRequest.setHeader(HttpHeaders.Names.USER_AGENT, userAgentHeader); + nettyRequestHeaders.set(HttpHeaders.Names.USER_AGENT, userAgentHeader); } else if (config.getUserAgent() != null) { - nettyRequest.setHeader(HttpHeaders.Names.USER_AGENT, config.getUserAgent()); + nettyRequestHeaders.set(HttpHeaders.Names.USER_AGENT, config.getUserAgent()); } else { - nettyRequest.setHeader(HttpHeaders.Names.USER_AGENT, AsyncHttpProviderUtils.constructUserAgent(NettyAsyncHttpProvider.class)); + nettyRequestHeaders.set(HttpHeaders.Names.USER_AGENT, AsyncHttpProviderUtils.constructUserAgent(NettyAsyncHttpProvider.class)); } if (!m.equals(HttpMethod.CONNECT)) { if (isNonEmpty(request.getCookies())) { - nettyRequest.setHeader(HttpHeaders.Names.COOKIE, CookieEncoder.encode(request.getCookies())); + nettyRequestHeaders.set(HttpHeaders.Names.COOKIE, CookieEncoder.encode(request.getCookies())); } String bodyCharset = request.getBodyEncoding() == null ? DEFAULT_CHARSET : request.getBodyEncoding(); // We already have processed the body. if (buffer != null && buffer.writerIndex() != 0) { - nettyRequest.setHeader(HttpHeaders.Names.CONTENT_LENGTH, buffer.writerIndex()); + nettyRequestHeaders.set(HttpHeaders.Names.CONTENT_LENGTH, buffer.writerIndex()); nettyRequest.setContent(buffer); } else if (request.getByteData() != null) { - nettyRequest.setHeader(HttpHeaders.Names.CONTENT_LENGTH, String.valueOf(request.getByteData().length)); + nettyRequestHeaders.set(HttpHeaders.Names.CONTENT_LENGTH, String.valueOf(request.getByteData().length)); nettyRequest.setContent(ChannelBuffers.wrappedBuffer(request.getByteData())); } else if (request.getStringData() != null) { byte[] bytes = request.getStringData().getBytes(bodyCharset); - nettyRequest.setHeader(HttpHeaders.Names.CONTENT_LENGTH, String.valueOf(bytes.length)); + nettyRequestHeaders.set(HttpHeaders.Names.CONTENT_LENGTH, String.valueOf(bytes.length)); nettyRequest.setContent(ChannelBuffers.wrappedBuffer(bytes)); } else if (isNonEmpty(request.getFormParams())) { String formBody = AsyncHttpProviderUtils.formParams2UTF8String(request.getFormParams()); - nettyRequest.setHeader(HttpHeaders.Names.CONTENT_LENGTH, String.valueOf(formBody.length())); + nettyRequestHeaders.set(HttpHeaders.Names.CONTENT_LENGTH, String.valueOf(formBody.length())); nettyRequest.setContent(ChannelBuffers.wrappedBuffer(formBody.getBytes(bodyCharset))); if (!request.getHeaders().containsKey(HttpHeaders.Names.CONTENT_TYPE)) { - nettyRequest.setHeader(HttpHeaders.Names.CONTENT_TYPE, HttpHeaders.Values.APPLICATION_X_WWW_FORM_URLENCODED); + nettyRequestHeaders.set(HttpHeaders.Names.CONTENT_TYPE, HttpHeaders.Values.APPLICATION_X_WWW_FORM_URLENCODED); } } else if (isNonEmpty(request.getParts())) { MultipartRequestEntity mre = AsyncHttpProviderUtils.createMultipartRequestEntity(request.getParts(), request.getHeaders()); - nettyRequest.setHeader(HttpHeaders.Names.CONTENT_TYPE, mre.getContentType()); + nettyRequestHeaders.set(HttpHeaders.Names.CONTENT_TYPE, mre.getContentType()); long contentLength = mre.getContentLength(); if (contentLength >= 0) { - nettyRequest.setHeader(HttpHeaders.Names.CONTENT_LENGTH, String.valueOf(contentLength)); + nettyRequestHeaders.set(HttpHeaders.Names.CONTENT_LENGTH, String.valueOf(contentLength)); } } else if (request.getFile() != null) { @@ -839,7 +789,7 @@ private static HttpRequest construct(AsyncHttpClientConfig config, Request reque if (!file.isFile()) { throw new IOException(String.format("File %s is not a file or doesn't exist", file.getAbsolutePath())); } - nettyRequest.setHeader(HttpHeaders.Names.CONTENT_LENGTH, file.length()); + nettyRequestHeaders.set(HttpHeaders.Names.CONTENT_LENGTH, file.length()); } } return nettyRequest; @@ -872,7 +822,7 @@ public void close() { nettyTimer.stop(); } catch (Throwable t) { - log.warn("Unexpected error on close", t); + LOGGER.warn("Unexpected error on close", t); } } } @@ -886,11 +836,11 @@ public Response prepareResponse(final HttpResponseStatus status, final HttpRespo /* @Override */ public ListenableFuture execute(Request request, final AsyncHandler asyncHandler) throws IOException { - return doConnect(request, asyncHandler, null, true, executeConnectAsync, false); + return doConnect(request, asyncHandler, null, true, 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); + private void execute(final Request request, final NettyResponseFuture f, boolean useCache, boolean reclaimCache) throws IOException { + doConnect(request, f.getAsyncHandler(), f, useCache, reclaimCache); } private NettyResponseFuture buildNettyResponseFutureWithCachedChannel(Request request, AsyncHandler asyncHandler, NettyResponseFuture f, ProxyServer proxyServer, @@ -934,7 +884,7 @@ private NettyResponseFuture buildNettyResponseFutureWithCachedChannel(Req return null; } - private ListenableFuture doConnect(final Request request, final AsyncHandler asyncHandler, NettyResponseFuture f, boolean useCache, boolean asyncConnect, + private ListenableFuture doConnect(final Request request, final AsyncHandler asyncHandler, NettyResponseFuture f, boolean useCache, boolean reclaimCache) throws IOException { if (isClose()) { @@ -964,20 +914,20 @@ private ListenableFuture doConnect(final Request request, final AsyncHand NettyResponseFuture connectedFuture = buildNettyResponseFutureWithCachedChannel(request, asyncHandler, f, proxyServer, uri, bufferedBytes, 3); if (connectedFuture != null) { - log.debug("\nUsing cached Channel {}\n for request \n{}\n", connectedFuture.channel(), connectedFuture.getNettyRequest()); + LOGGER.debug("\nUsing cached Channel {}\n for request \n{}\n", connectedFuture.channel(), connectedFuture.getNettyRequest()); try { writeRequest(connectedFuture.channel(), config, connectedFuture); } catch (Exception ex) { - log.debug("writeRequest failure", ex); + LOGGER.debug("writeRequest failure", ex); if (useSSl && ex.getMessage() != null && ex.getMessage().contains("SSLEngine")) { - log.debug("SSLEngine failure", ex); + LOGGER.debug("SSLEngine failure", ex); connectedFuture = null; } else { try { asyncHandler.onThrowable(ex); } catch (Throwable t) { - log.warn("doConnect.writeRequest()", t); + LOGGER.warn("doConnect.writeRequest()", t); } IOException ioe = new IOException(ex.getMessage()); ioe.initCause(ex); @@ -988,27 +938,27 @@ private ListenableFuture doConnect(final Request request, final AsyncHand } } - // Do not throw an exception when we need an extra connection for a redirect. - if (!reclaimCache && !connectionsPool.canCacheConnection()) { - IOException ex = new IOException(String.format("Too many connections %s", config.getMaxTotalConnections())); - try { - asyncHandler.onThrowable(ex); - } catch (Throwable t) { - log.warn("!connectionsPool.canCacheConnection()", t); - } - throw ex; - } - boolean acquiredConnection = false; - if (trackConnections) { - if (!reclaimCache) { + // Do not throw an exception when we need an extra connection for a redirect. + if (!reclaimCache) { + if (!connectionsPool.canCacheConnection()) { + IOException ex = new IOException(String.format("Too many connections %s", config.getMaxTotalConnections())); + try { + asyncHandler.onThrowable(ex); + } catch (Throwable t) { + LOGGER.warn("!connectionsPool.canCacheConnection()", t); + } + throw ex; + } + + if (trackConnections) { if (!freeConnections.tryAcquire()) { IOException ex = new IOException(String.format("Too many connections %s", config.getMaxTotalConnections())); try { asyncHandler.onThrowable(ex); } catch (Throwable t) { - log.warn("!connectionsPool.canCacheConnection()", t); + LOGGER.warn("!connectionsPool.canCacheConnection()", t); } throw ex; } else { @@ -1017,22 +967,16 @@ private ListenableFuture doConnect(final Request request, final AsyncHand } } - NettyConnectListener c = new NettyConnectListener.Builder(config, request, asyncHandler, f, this, bufferedBytes).build(uri); + NettyConnectListener connectListener = new NettyConnectListener.Builder(config, request, asyncHandler, f, this, bufferedBytes).build(uri); - if (useSSl) { - constructSSLPipeline(c); - } + if (useSSl) + constructSSLPipeline(connectListener); ChannelFuture channelFuture; ClientBootstrap bootstrap = (request.getURI().getScheme().startsWith(WEBSOCKET) && !useProxy) ? (useSSl ? secureWebSocketBootstrap : webSocketBootstrap) : (useSSl ? secureBootstrap : plainBootstrap); bootstrap.setOption("connectTimeoutMillis", config.getConnectionTimeoutInMs()); - // Do no enable this with win. - if (!System.getProperty("os.name").toLowerCase(Locale.ENGLISH).contains("win")) { - bootstrap.setOption("reuseAddress", providerConfig.getProperty(REUSE_ADDRESS)); - } - try { InetSocketAddress remoteAddress; if (request.getInetAddress() != null) { @@ -1053,52 +997,23 @@ private ListenableFuture doConnect(final Request request, final AsyncHand if (acquiredConnection) { freeConnections.release(); } - abort(c.future(), t.getCause() == null ? t : t.getCause()); - return c.future(); + abort(connectListener.future(), t.getCause() == null ? t : t.getCause()); + return connectListener.future(); } - boolean directInvokation = !(IN_IO_THREAD.get() && DefaultChannelFuture.isUseDeadLockChecker()); + channelFuture.addListener(connectListener); - if (directInvokation && !asyncConnect && request.getFile() == null) { - int timeOut = config.getConnectionTimeoutInMs() > 0 ? config.getConnectionTimeoutInMs() : Integer.MAX_VALUE; - if (!channelFuture.awaitUninterruptibly(timeOut, TimeUnit.MILLISECONDS)) { - if (acquiredConnection) { - freeConnections.release(); - } - channelFuture.cancel(); - abort(c.future(), new ConnectException(String.format("Connect operation to %s timeout %s", uri, timeOut))); - } + LOGGER.debug("\nNon cached request \n{}\n\nusing Channel \n{}\n", connectListener.future().getNettyRequest(), channelFuture.getChannel()); - try { - c.operationComplete(channelFuture); - } catch (Exception e) { - if (acquiredConnection) { - freeConnections.release(); - } - IOException ioe = new IOException(e.getMessage()); - ioe.initCause(e); - try { - asyncHandler.onThrowable(ioe); - } catch (Throwable t) { - log.warn("c.operationComplete()", t); - } - throw ioe; - } - } else { - channelFuture.addListener(c); - } - - log.debug("\nNon cached request \n{}\n\nusing Channel \n{}\n", c.future().getNettyRequest(), channelFuture.getChannel()); - - if (!c.future().isCancelled() || !c.future().isDone()) { + if (!connectListener.future().isCancelled() || !connectListener.future().isDone()) { openChannels.add(channelFuture.getChannel()); - c.future().attachChannel(channelFuture.getChannel(), false); + connectListener.future().attachChannel(channelFuture.getChannel(), false); } else { if (acquiredConnection) { freeConnections.release(); } } - return c.future(); + return connectListener.future(); } private void closeChannel(final ChannelHandlerContext ctx) { @@ -1107,19 +1022,19 @@ private void closeChannel(final ChannelHandlerContext ctx) { } private void finishChannel(final ChannelHandlerContext ctx) { - ctx.setAttachment(new DiscardEvent()); + ctx.setAttachment(DiscardEvent.INSTANCE); // The channel may have already been removed if a timeout occurred, and this method may be called just after. if (ctx.getChannel() == null) { return; } - log.debug("Closing Channel {} ", ctx.getChannel()); + LOGGER.debug("Closing Channel {} ", ctx.getChannel()); try { ctx.getChannel().close(); } catch (Throwable t) { - log.debug("Error closing a connection", t); + LOGGER.debug("Error closing a connection", t); } if (ctx.getChannel() != null) { @@ -1130,41 +1045,43 @@ private void finishChannel(final ChannelHandlerContext ctx) { @Override public void messageReceived(final ChannelHandlerContext ctx, MessageEvent e) throws Exception { + // call super to reset the read timeout super.messageReceived(ctx, e); - IN_IO_THREAD.set(Boolean.TRUE); - if (ctx.getAttachment() == null) { - log.debug("ChannelHandlerContext wasn't having any attachment"); - } - if (ctx.getAttachment() instanceof DiscardEvent) { - return; - } else if (ctx.getAttachment() instanceof AsyncCallable) { - if (e.getMessage() instanceof HttpChunk) { - HttpChunk chunk = (HttpChunk) e.getMessage(); - if (chunk.isLast()) { - AsyncCallable ac = (AsyncCallable) ctx.getAttachment(); + Object attachment = ctx.getAttachment(); + + if (attachment == null) + LOGGER.debug("ChannelHandlerContext doesn't have any attachment"); + + if (attachment == DiscardEvent.INSTANCE) { + // discard + + } else if (attachment instanceof AsyncCallable) { + Object message = e.getMessage(); + AsyncCallable ac = (AsyncCallable) attachment; + if (message instanceof HttpChunk) { + // the AsyncCallable is to be processed on the last chunk + if (HttpChunk.class.cast(message).isLast()) + // process the AsyncCallable before passing the message to the protocol ac.call(); - } else { - return; - } } else { - AsyncCallable ac = (AsyncCallable) ctx.getAttachment(); ac.call(); + ctx.setAttachment(DiscardEvent.INSTANCE); } - ctx.setAttachment(new DiscardEvent()); - return; - } else if (!(ctx.getAttachment() instanceof NettyResponseFuture)) { + + } else if (attachment instanceof NettyResponseFuture) { + Protocol p = (ctx.getPipeline().get(HTTP_PROCESSOR) != null ? httpProtocol : webSocketProtocol); + p.handle(ctx, e, NettyResponseFuture.class.cast(attachment)); + + } else { + // unhandled message try { ctx.getChannel().close(); } catch (Throwable t) { - log.trace("Closing an orphan channel {}", ctx.getChannel()); + LOGGER.trace("Closing an orphan channel {}", ctx.getChannel()); } - return; } - - Protocol p = (ctx.getPipeline().get(HTTP_PROCESSOR) != null ? httpProtocol : webSocketProtocol); - p.handle(ctx, e); } private Realm kerberosChallenge(List proxyAuth, Request request, ProxyServer proxyServer, FluentCaseInsensitiveStringsMap headers, Realm realm, @@ -1266,25 +1183,10 @@ private String getPoolKey(UriComponents uri, ProxyServer proxy, ConnectionPoolKe } 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; - } - - finishChannel(ctx); - return null; - } - - @Override - public String toString() { - return String.format("Draining task for channel %s", ctx.getChannel()); - } - }); + ctx.setAttachment(newDrainCallable(future, ctx, future.getKeepAlive(), getPoolKey(future))); } - private FilterContext handleIoException(FilterContext fc, NettyResponseFuture future) { + private FilterContext handleIoException(FilterContext fc, NettyResponseFuture future) { for (IOExceptionFilter asyncFilter : config.getIOExceptionFilters()) { try { fc = asyncFilter.filter(fc); @@ -1298,7 +1200,7 @@ private FilterContext handleIoException(FilterContext fc, NettyResponseFuture return fc; } - private void replayRequest(final NettyResponseFuture future, FilterContext fc, HttpResponse response, ChannelHandlerContext ctx) throws IOException { + private void replayRequest(final NettyResponseFuture future, FilterContext fc, ChannelHandlerContext ctx) throws IOException { if (future.getAsyncHandler() instanceof AsyncHandlerExtensions) { AsyncHandlerExtensions.class.cast(future.getAsyncHandler()).onRetry(); } @@ -1307,16 +1209,16 @@ private void replayRequest(final NettyResponseFuture future, FilterContext fc future.setState(NettyResponseFuture.STATE.NEW); future.touch(); - log.debug("\n\nReplaying Request {}\n for Future {}\n", newRequest, future); + LOGGER.debug("\n\nReplaying Request {}\n for Future {}\n", newRequest, future); drainChannel(ctx, future); nextRequest(newRequest, future); return; } - private List getAuthorizationToken(List> list, String headerAuth) { + private List getNettyHeaderValuesByCaseInsensitiveName(HttpHeaders headers, String name) { ArrayList l = new ArrayList(); - for (Entry e : list) { - if (e.getKey().equalsIgnoreCase(headerAuth)) { + for (Entry e : headers) { + if (e.getKey().equalsIgnoreCase(name)) { l.add(e.getValue().trim()); } } @@ -1328,7 +1230,7 @@ private void nextRequest(final Request request, final NettyResponseFuture fut } private void nextRequest(final Request request, final NettyResponseFuture future, final boolean useCache) throws IOException { - execute(request, future, useCache, true, true); + execute(request, future, useCache, true); } public void abort(NettyResponseFuture future, Throwable t) { @@ -1339,8 +1241,8 @@ public void abort(NettyResponseFuture future, Throwable t) { } if (!future.isCancelled() && !future.isDone()) { - log.debug("Aborting Future {}\n", future); - log.debug(t.getMessage(), t); + LOGGER.debug("Aborting Future {}\n", future); + LOGGER.debug(t.getMessage(), t); } future.abort(t); @@ -1378,10 +1280,10 @@ public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws try { super.channelClosed(ctx, e); } catch (Exception ex) { - log.trace("super.channelClosed", ex); + LOGGER.trace("super.channelClosed", ex); } - log.debug("Channel Closed: {} with attachment {}", e.getChannel(), ctx.getAttachment()); + LOGGER.debug("Channel Closed: {} with attachment {}", e.getChannel(), ctx.getAttachment()); if (ctx.getAttachment() instanceof AsyncCallable) { AsyncCallable ac = (AsyncCallable) ctx.getAttachment(); @@ -1400,7 +1302,7 @@ public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws fc = handleIoException(fc, future); if (fc.replayRequest() && !future.cannotBeReplay()) { - replayRequest(future, fc, null, ctx); + replayRequest(future, fc, ctx); return; } } @@ -1433,13 +1335,13 @@ protected boolean remotelyClosed(Channel channel, NettyResponseFuture future) } if (future == null || future.cannotBeReplay()) { - log.debug("Unable to recover future {}\n", future); + LOGGER.debug("Unable to recover future {}\n", future); return true; } future.setState(NettyResponseFuture.STATE.RECONNECTED); - log.debug("Trying to recover request {}\n", future.getNettyRequest()); + LOGGER.debug("Trying to recover request {}\n", future.getNettyRequest()); if (future.getAsyncHandler() instanceof AsyncHandlerExtensions) { AsyncHandlerExtensions.class.cast(future.getAsyncHandler()).onRetry(); } @@ -1450,7 +1352,7 @@ protected boolean remotelyClosed(Channel channel, NettyResponseFuture future) } catch (IOException iox) { future.setState(NettyResponseFuture.STATE.CLOSED); future.abort(iox); - log.error("Remotely Closed, unable to recover", iox); + LOGGER.error("Remotely Closed, unable to recover", iox); return true; } } @@ -1461,7 +1363,7 @@ private void markAsDone(final NettyResponseFuture future, final ChannelHandle future.done(); } catch (Throwable t) { // Never propagate exception once we know we are done. - log.debug(t.getMessage(), t); + LOGGER.debug(t.getMessage(), t); } if (!future.getKeepAlive() || !ctx.getChannel().isReadable()) { @@ -1469,41 +1371,34 @@ 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()) { + private void finishUpdate(final NettyResponseFuture future, final ChannelHandlerContext ctx, boolean expectOtherChunks) throws IOException { + boolean keepAlive = future.getKeepAlive(); + if (expectOtherChunks && keepAlive) drainChannel(ctx, future); - } else { - if (future.getKeepAlive() && ctx.getChannel().isReadable() && connectionsPool.offer(getPoolKey(future), ctx.getChannel())) { - markAsDone(future, ctx); - return; - } - finishChannel(ctx); - } + else + tryToOfferChannelToPool(ctx, keepAlive, getPoolKey(future)); markAsDone(future, ctx); } - @SuppressWarnings("unchecked") - private final boolean updateStatusAndInterrupt(AsyncHandler handler, HttpResponseStatus c) throws Exception { + private final boolean updateStatusAndInterrupt(AsyncHandler handler, HttpResponseStatus c) throws Exception { return handler.onStatusReceived(c) != STATE.CONTINUE; } - @SuppressWarnings("unchecked") - private final boolean updateHeadersAndInterrupt(AsyncHandler handler, HttpResponseHeaders c) throws Exception { + private final boolean updateHeadersAndInterrupt(AsyncHandler handler, HttpResponseHeaders c) throws Exception { return handler.onHeadersReceived(c) != STATE.CONTINUE; } - @SuppressWarnings("unchecked") - private final boolean updateBodyAndInterrupt(final NettyResponseFuture future, AsyncHandler handler, HttpResponseBodyPart c) throws Exception { + private final boolean updateBodyAndInterrupt(final NettyResponseFuture future, AsyncHandler handler, HttpResponseBodyPart c) throws Exception { boolean state = handler.onBodyPartReceived(c) != STATE.CONTINUE; - if (c.closeUnderlyingConnection()) { + if (c.closeUnderlyingConnection()) future.setKeepAlive(false); - } return state; } // Simple marker for stopping publishing bytes. - final static class DiscardEvent { + enum DiscardEvent { + INSTANCE } @Override @@ -1516,8 +1411,8 @@ public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws return; } - if (log.isDebugEnabled()) { - log.debug("Unexpected I/O exception on channel {}", channel, cause); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Unexpected I/O exception on channel {}", channel, cause); } try { @@ -1539,7 +1434,7 @@ public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws fc = handleIoException(fc, future); if (fc.replayRequest()) { - replayRequest(future, fc, null, ctx); + replayRequest(future, fc, ctx); return; } } else { @@ -1554,7 +1449,7 @@ public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws } if (abortOnReadCloseException(cause) || abortOnWriteCloseException(cause)) { - log.debug("Trying to recover from dead Channel: {}", channel); + LOGGER.debug("Trying to recover from dead Channel: {}", channel); return; } } else if (ctx.getAttachment() instanceof AsyncCallable) { @@ -1566,10 +1461,10 @@ public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws if (future != null) { try { - log.debug("Was unable to recover Future: {}", future); + LOGGER.debug("Was unable to recover Future: {}", future); abort(future, cause); } catch (Throwable t) { - log.error(t.getMessage(), t); + LOGGER.error(t.getMessage(), t); } } @@ -1667,10 +1562,10 @@ public static NettyResponseFuture newFuture(UriComponents uri, Request re private class ProgressListener implements ChannelFutureProgressListener { private final boolean notifyHeaders; - private final AsyncHandler asyncHandler; + private final AsyncHandler asyncHandler; private final NettyResponseFuture future; - public ProgressListener(boolean notifyHeaders, AsyncHandler asyncHandler, NettyResponseFuture future) { + public ProgressListener(boolean notifyHeaders, AsyncHandler asyncHandler, NettyResponseFuture future) { this.notifyHeaders = notifyHeaders; this.asyncHandler = asyncHandler; this.future = future; @@ -1683,25 +1578,25 @@ public void operationComplete(ChannelFuture cf) { if (cause != null && future.getState() != NettyResponseFuture.STATE.NEW) { if (cause instanceof IllegalStateException) { - log.debug(cause.getMessage(), cause); + LOGGER.debug(cause.getMessage(), cause); try { cf.getChannel().close(); } catch (RuntimeException ex) { - log.debug(ex.getMessage(), ex); + LOGGER.debug(ex.getMessage(), ex); } return; } if (cause instanceof ClosedChannelException || abortOnReadCloseException(cause) || abortOnWriteCloseException(cause)) { - if (log.isDebugEnabled()) { - log.debug(cf.getCause() == null ? "" : cf.getCause().getMessage(), cf.getCause()); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug(cf.getCause() == null ? "" : cf.getCause().getMessage(), cf.getCause()); } try { cf.getChannel().close(); } catch (RuntimeException ex) { - log.debug(ex.getMessage(), ex); + LOGGER.debug(ex.getMessage(), ex); } return; } else { @@ -1812,13 +1707,13 @@ public void releaseExternalResources() { try { file.close(); } catch (IOException e) { - log.warn("Failed to close a file.", e); + LOGGER.warn("Failed to close a file.", e); } try { raf.close(); } catch (IOException e) { - log.warn("Failed to close a file.", e); + LOGGER.warn("Failed to close a file.", e); } } } @@ -1848,7 +1743,7 @@ public void getBytes(byte[] bytes) { try { byteRead += file.read(bytes); } catch (IOException e) { - log.error(e.getMessage(), e); + LOGGER.error(e.getMessage(), e); } } } @@ -1858,7 +1753,7 @@ protected AsyncHttpClientConfig getConfig() { return config; } - private static class NonConnectionsPool implements ConnectionsPool { + private static class NonChannelPool implements ChannelPool { public boolean offer(String uri, Channel connection) { return false; @@ -1887,16 +1782,17 @@ 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 exitAfterHandlingRedirect(ChannelHandlerContext ctx, NettyResponseFuture future, Request request, HttpResponse response, int statusCode) throws Exception { - int statusCode = response.getStatus().getCode(); if (AsyncHttpProviderUtils.followRedirect(config, request) && (statusCode == 302 || statusCode == 301 || statusCode == 303 || statusCode == 307)) { if (future.incrementAndGetCurrentRedirectCount() < config.getMaxRedirects()) { - // We must allow 401 handling again. + // allow 401 handling again future.getAndSetAuth(false); - String location = response.getHeader(HttpHeaders.Names.LOCATION); + HttpHeaders responseHeaders = response.headers(); + + String location = responseHeaders.get(HttpHeaders.Names.LOCATION); UriComponents uri = UriComponents.create(future.getURI(), location); if (!uri.equals(future.getURI())) { final RequestBuilder nBuilder = new RequestBuilder(future.getRequest()); @@ -1920,25 +1816,17 @@ private boolean redirect(Request request, NettyResponseFuture future, HttpRes newURI = newURI.withNewScheme(WEBSOCKET_SSL); } - log.debug("Redirecting to {}", newURI); - List setCookieHeaders = future.getHttpResponse().getHeaders(HttpHeaders.Names.SET_COOKIE2); + LOGGER.debug("Redirecting to {}", newURI); + List setCookieHeaders = responseHeaders.getAll(HttpHeaders.Names.SET_COOKIE2); if (!isNonEmpty(setCookieHeaders)) { - setCookieHeaders = future.getHttpResponse().getHeaders(HttpHeaders.Names.SET_COOKIE); + setCookieHeaders = responseHeaders.getAll(HttpHeaders.Names.SET_COOKIE); } for (String cookieStr : setCookieHeaders) { nBuilder.addOrReplaceCookie(CookieDecoder.decode(cookieStr)); } - AsyncCallable ac = new AsyncCallable(future) { - public Object call() throws Exception { - if (initialConnectionKeepAlive && ctx.getChannel().isReadable() && connectionsPool.offer(initialPoolKey, ctx.getChannel())) { - return null; - } - finishChannel(ctx); - return null; - } - }; + AsyncCallable ac = newDrainCallable(future, ctx, initialConnectionKeepAlive, initialPoolKey); if (response.isChunked()) { // We must make sure there is no bytes left before executing the next request. @@ -1956,225 +1844,335 @@ public Object call() throws Exception { return false; } - private final class HttpProtocol implements Protocol { - // @Override - public void handle(final ChannelHandlerContext ctx, final MessageEvent e) throws Exception { - final NettyResponseFuture future = (NettyResponseFuture) ctx.getAttachment(); - future.touch(); + private final boolean tryToOfferChannelToPool(ChannelHandlerContext ctx, boolean keepAlive, String poolKey) { + Channel channel = ctx.getChannel(); + if (keepAlive && channel.isReadable() && connectionsPool.offer(poolKey, channel)) { + LOGGER.debug("Adding key: {} for channel {}", poolKey, channel); + ctx.setAttachment(DiscardEvent.INSTANCE); + return true; + } else { + // not offered + finishChannel(ctx); + return false; + } + } + + private final AsyncCallable newDrainCallable(final NettyResponseFuture future, final ChannelHandlerContext ctx, final boolean keepAlive, final String poolKey) { + + return new AsyncCallable(future) { + public Object call() throws Exception { + tryToOfferChannelToPool(ctx, keepAlive, poolKey); + return null; + } + }; + } - // The connect timeout occured. - if (future.isCancelled() || future.isDone()) { - finishChannel(ctx); - return; + private final void configureKeepAlive(NettyResponseFuture future, HttpResponse response) { + String connectionHeader = response.headers().get(HttpHeaders.Names.CONNECTION); + future.setKeepAlive(connectionHeader == null || connectionHeader.equalsIgnoreCase(HttpHeaders.Values.KEEP_ALIVE)); + } + + private final boolean exitAfterProcessingFilters(ChannelHandlerContext ctx, NettyResponseFuture future, HttpResponse response, AsyncHandler handler, Request request, HttpResponseStatus status, HttpResponseHeaders responseHeaders) throws IOException { + if (!config.getResponseFilters().isEmpty()) { + FilterContext fc = new FilterContext.FilterContextBuilder().asyncHandler(handler).request(request).responseStatus(status) + .responseHeaders(responseHeaders).build(); + + for (ResponseFilter asyncFilter : config.getResponseFilters()) { + try { + fc = asyncFilter.filter(fc); + if (fc == null) { + throw new NullPointerException("FilterContext is null"); + } + } catch (FilterException efe) { + abort(future, efe); + } } - 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) { - response = (HttpResponse) e.getMessage(); + // The handler may have been wrapped. + future.setAsyncHandler(fc.getAsyncHandler()); + + // The request has changed + if (fc.replayRequest()) { + replayRequest(future, fc, ctx); + return true; + } + } + return false; + } - log.debug("\n\nRequest {}\n\nResponse {}\n", nettyRequest, response); + private final boolean exitAfterHandling401(// + final ChannelHandlerContext ctx,// + final NettyResponseFuture future,// + HttpResponse response,// + Request request,// + int statusCode,// + Realm realm,// + ProxyServer proxyServer,// + final RequestBuilder requestBuilder) throws Exception { - // Required if there is some trailing headers. - future.setHttpResponse(response); + if (statusCode == 401 && realm != null && !future.getAndSetAuth(true)) { - int statusCode = response.getStatus().getCode(); + List wwwAuthHeaders = getNettyHeaderValuesByCaseInsensitiveName(response.headers(), HttpHeaders.Names.WWW_AUTHENTICATE); - String ka = response.getHeader(HttpHeaders.Names.CONNECTION); - future.setKeepAlive(ka == null || ka.equalsIgnoreCase(HttpHeaders.Values.KEEP_ALIVE)); + if (!wwwAuthHeaders.isEmpty()) { + future.setState(NettyResponseFuture.STATE.NEW); + Realm newRealm = null; - List wwwAuth = getAuthorizationToken(response.getHeaders(), HttpHeaders.Names.WWW_AUTHENTICATE); - Realm realm = request.getRealm() != null ? request.getRealm() : config.getRealm(); + FluentCaseInsensitiveStringsMap requestHeaders = request.getHeaders(); - 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) + if (!wwwAuthHeaders.contains("Kerberos") && (isNTLM(wwwAuthHeaders) || (wwwAuthHeaders.contains("Negotiate")))) { + // NTLM + newRealm = ntlmChallenge(wwwAuthHeaders, request, proxyServer, requestHeaders, realm, future, false); + } else if (wwwAuthHeaders.contains("Negotiate")) { + // SPNEGO KERBEROS + newRealm = kerberosChallenge(wwwAuthHeaders, request, proxyServer, requestHeaders, realm, future, false); + if (newRealm == null) + return true; + } else { + newRealm = new Realm.RealmBuilder().clone(realm) // + .setScheme(realm.getAuthScheme()) // + .setUri(request.getURI()) // + .setMethodName(request.getMethod()) // + .setUsePreemptiveAuth(true) // + .parseWWWAuthenticateHeader(wwwAuthHeaders.get(0))// .build(); + } - for (ResponseFilter asyncFilter : config.getResponseFilters()) { - try { - fc = asyncFilter.filter(fc); - if (fc == null) { - throw new NullPointerException("FilterContext is null"); - } - } catch (FilterException efe) { - abort(future, efe); - } + final Realm nr = newRealm; + + LOGGER.debug("Sending authentication to {}", request.getURI()); + final Request nextRequest = requestBuilder.setHeaders(requestHeaders).setRealm(nr).build(); + AsyncCallable ac = new AsyncCallable(future) { + public Object call() throws Exception { + // not waiting for the channel to be drained, so we might ended up pooling the initial channel and creating a new one + drainChannel(ctx, future); + nextRequest(nextRequest, future); + return null; } + }; - // The handler may have been wrapped. - handler = fc.getAsyncHandler(); - future.setAsyncHandler(handler); + if (future.getKeepAlive() && response.isChunked()) + // we must make sure there is no chunk left before executing the next request + ctx.setAttachment(ac); + else + // FIXME couldn't we reuse the channel right now? + ac.call(); + return true; + } + } + return false; + } + + private final boolean exitAfterHandling407(// + NettyResponseFuture future,// + HttpResponse response,// + Request request,// + int statusCode,// + Realm realm,// + ProxyServer proxyServer,// + final RequestBuilder requestBuilder) throws Exception { + + if (statusCode == 407 && realm != null && !future.getAndSetAuth(true)) { + List proxyAuth = getNettyHeaderValuesByCaseInsensitiveName(response.headers(), HttpHeaders.Names.PROXY_AUTHENTICATE); + if (!proxyAuth.isEmpty()) { + LOGGER.debug("Sending proxy authentication to {}", request.getURI()); + + future.setState(NettyResponseFuture.STATE.NEW); + Realm newRealm = null; + FluentCaseInsensitiveStringsMap requestHeaders = request.getHeaders(); + + if (!proxyAuth.contains("Kerberos") && (isNTLM(proxyAuth) || (proxyAuth.contains("Negotiate")))) { + newRealm = ntlmProxyChallenge(proxyAuth, request, proxyServer, requestHeaders, realm, future); + // SPNEGO KERBEROS + } else if (proxyAuth.contains("Negotiate")) { + newRealm = kerberosChallenge(proxyAuth, request, proxyServer, requestHeaders, realm, future, true); + if (newRealm == null) + return true; + } else { + newRealm = new Realm.RealmBuilder().clone(realm)// + .setScheme(realm.getAuthScheme())// + .setUri(request.getURI())// + .setMethodName("CONNECT")// + .setTargetProxy(true)// + .setUsePreemptiveAuth(true)// + .parseProxyAuthenticateHeader(proxyAuth.get(0))// + .build(); + } - // The request has changed - if (fc.replayRequest()) { - replayRequest(future, fc, response, ctx); - return; - } + Request req = requestBuilder.setHeaders(requestHeaders).setRealm(newRealm).build(); + future.setReuseChannel(true); + future.setConnectAllowed(true); + nextRequest(req, future); + return true; + } + } + return false; + } - final FluentCaseInsensitiveStringsMap headers = request.getHeaders(); - final RequestBuilder builder = new RequestBuilder(future.getRequest()); + + private boolean exitAfterHandling100(ChannelHandlerContext ctx, NettyResponseFuture future, int statusCode) { + if (statusCode == 100) { + future.getAndSetWriteHeaders(false); + future.getAndSetWriteBody(true); + writeRequest(ctx.getChannel(), config, future); + return true; + } + return false; + } - // if (realm != null && !future.getURI().getPath().equalsIgnoreCase(realm.getUri())) { - // builder.setUrl(future.getURI().toString()); - // } + private boolean exitAfterHandlingConnect(ChannelHandlerContext ctx,// + NettyResponseFuture future,// + Request request,// + ProxyServer proxyServer,// + int statusCode,// + RequestBuilder requestBuilder,// + HttpRequest nettyRequest) throws IOException { - if (statusCode == 401 && realm != null && !wwwAuth.isEmpty() && !future.getAndSetAuth(true)) { + if (nettyRequest.getMethod().equals(HttpMethod.CONNECT) && statusCode == 200) { - future.setState(NettyResponseFuture.STATE.NEW); - Realm newRealm = null; + LOGGER.debug("Connected to {}:{}", proxyServer.getHost(), proxyServer.getPort()); - if (!wwwAuth.contains("Kerberos") && (isNTLM(wwwAuth) || (wwwAuth.contains("Negotiate")))) { - // NTLM - newRealm = ntlmChallenge(wwwAuth, request, proxyServer, headers, realm, future, false); - } else if (wwwAuth.contains("Negotiate")) { - // SPNEGO KERBEROS - newRealm = kerberosChallenge(wwwAuth, request, proxyServer, headers, realm, future, false); - if (newRealm == null) - return; - } else { - newRealm = new Realm.RealmBuilder().clone(realm) // - .setScheme(realm.getAuthScheme()) // - .setUri(request.getURI()) // - .setMethodName(request.getMethod()) // - .setUsePreemptiveAuth(true) // - .parseWWWAuthenticateHeader(wwwAuth.get(0))// - .build(); - } - - final Realm nr = newRealm; - - log.debug("Sending authentication to {}", request.getURI()); - AsyncCallable ac = new AsyncCallable(future) { - public Object call() throws Exception { - drainChannel(ctx, future); - nextRequest(builder.setHeaders(headers).setRealm(nr).build(), future); - return null; - } - }; + if (future.getKeepAlive()) { + future.attachChannel(ctx.getChannel(), true); + } - if (future.getKeepAlive() && response.isChunked()) { - // We must make sure there is no bytes left before executing the next request. - ctx.setAttachment(ac); - } else { - ac.call(); - } - return; - } + try { + UriComponents requestURI = request.getURI(); + String scheme = requestURI.getScheme(); + String host = requestURI.getHost(); + int port = AsyncHttpProviderUtils.getDefaultPort(requestURI); - if (statusCode == 100) { - future.getAndSetWriteHeaders(false); - future.getAndSetWriteBody(true); - writeRequest(ctx.getChannel(), config, future); - return; - } + LOGGER.debug("Connecting to proxy {} for scheme {}", proxyServer, scheme); + upgradeProtocol(ctx.getChannel().getPipeline(), scheme, host, port); - List proxyAuth = getAuthorizationToken(response.getHeaders(), HttpHeaders.Names.PROXY_AUTHENTICATE); - if (statusCode == 407 && realm != null && !proxyAuth.isEmpty() && !future.getAndSetAuth(true)) { + } catch (Throwable ex) { + abort(future, ex); + } + Request req = requestBuilder.build(); + future.setReuseChannel(true); + future.setConnectAllowed(false); + nextRequest(req, future); + return true; + } + return false; + } + + private final boolean exitAfterHandlingStatus(ChannelHandlerContext ctx, NettyResponseFuture future, HttpResponse response, AsyncHandler handler, HttpResponseStatus status) throws IOException, Exception { + if (!future.getAndSetStatusReceived(true) && updateStatusAndInterrupt(handler, status)) { + finishUpdate(future, ctx, response.isChunked()); + return true; + } + return false; + } + + private final boolean exitAfterHandlingHeaders(ChannelHandlerContext ctx, NettyResponseFuture future, HttpResponse response, AsyncHandler handler, HttpResponseHeaders responseHeaders) throws IOException, Exception { + if (!response.headers().isEmpty() && updateHeadersAndInterrupt(handler, responseHeaders)) { + finishUpdate(future, ctx, response.isChunked()); + return true; + } + return false; + } + + private final boolean exitAfterHandlingBody(ChannelHandlerContext ctx, NettyResponseFuture future, HttpResponse response, AsyncHandler handler) throws Exception { + if (!response.isChunked()) { + updateBodyAndInterrupt(future, handler, new ResponseBodyPart(future.getURI(), response, NettyAsyncHttpProvider.this, true)); + finishUpdate(future, ctx, false); + return true; + } + return false; + } + + private final boolean exitAfterHandlingHead(ChannelHandlerContext ctx, NettyResponseFuture future, HttpResponse response, AsyncHandler handler, HttpRequest nettyRequest) 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); + } + return false; + } + + private final void handleHttpResponse(final HttpResponse response, final ChannelHandlerContext ctx, final NettyResponseFuture future, AsyncHandler handler) throws Exception { - log.debug("Sending proxy authentication to {}", request.getURI()); + HttpRequest nettyRequest = future.getNettyRequest(); + Request request = future.getRequest(); + ProxyServer proxyServer = future.getProxyServer(); + LOGGER.debug("\n\nRequest {}\n\nResponse {}\n", nettyRequest, response); + + // Required if there is some trailing headers. + future.setHttpResponse(response); - future.setState(NettyResponseFuture.STATE.NEW); - Realm newRealm = null; + configureKeepAlive(future, response); - if (!proxyAuth.contains("Kerberos") && (isNTLM(proxyAuth) || (proxyAuth.contains("Negotiate")))) { - newRealm = ntlmProxyChallenge(proxyAuth, request, proxyServer, headers, realm, future); - // SPNEGO KERBEROS - } else if (proxyAuth.contains("Negotiate")) { - newRealm = kerberosChallenge(proxyAuth, request, proxyServer, headers, realm, future, true); - if (newRealm == null) - return; - } else { - newRealm = new Realm.RealmBuilder().clone(realm)// - .setScheme(realm.getAuthScheme())// - .setUri(request.getURI())// - .setMethodName("CONNECT")// - .setTargetProxy(true)// - .setUsePreemptiveAuth(true)// - .parseProxyAuthenticateHeader(proxyAuth.get(0))// - .build(); - } + HttpResponseStatus status = new ResponseStatus(future.getURI(), response, NettyAsyncHttpProvider.this); + HttpResponseHeaders responseHeaders = new ResponseHeaders(future.getURI(), response, NettyAsyncHttpProvider.this); + + if (exitAfterProcessingFilters(ctx, future, response, handler, request, status, responseHeaders)) + return; - Request req = builder.setHeaders(headers).setRealm(newRealm).build(); - future.setReuseChannel(true); - future.setConnectAllowed(true); - nextRequest(req, future); - return; - } + final RequestBuilder requestBuilder = new RequestBuilder(future.getRequest()); - if (future.getNettyRequest().getMethod().equals(HttpMethod.CONNECT) && statusCode == 200) { + Realm realm = request.getRealm() != null ? request.getRealm() : config.getRealm(); - log.debug("Connected to {}:{}", proxyServer.getHost(), proxyServer.getPort()); + int statusCode = response.getStatus().getCode(); - if (future.getKeepAlive()) { - future.attachChannel(ctx.getChannel(), true); - } + // FIXME + if (exitAfterHandling401(ctx, future, response, request, statusCode, realm, proxyServer, requestBuilder) || // + exitAfterHandling407(future, response, request, statusCode, realm, proxyServer, requestBuilder) || // + exitAfterHandling100(ctx, future, statusCode) || // + exitAfterHandlingRedirect(ctx, future, request, response, statusCode) || // + exitAfterHandlingConnect(ctx, future, request, proxyServer, statusCode, requestBuilder, nettyRequest) || // + exitAfterHandlingStatus(ctx, future, response, handler, status) || // + exitAfterHandlingHeaders(ctx, future, response, handler, responseHeaders) || // + exitAfterHandlingBody(ctx, future, response, handler) || // + exitAfterHandlingHead(ctx, future, response, handler, nettyRequest)) { + return; + } + } - try { - UriComponents requestURI = request.getURI(); - String scheme = requestURI.getScheme(); - String host = requestURI.getHost(); - int port = AsyncHttpProviderUtils.getDefaultPort(requestURI); - - log.debug("Connecting to proxy {} for scheme {}", proxyServer, scheme); - upgradeProtocol(ctx.getChannel().getPipeline(), scheme, host, port); - } catch (Throwable ex) { - abort(future, ex); - } - Request req = builder.build(); - future.setReuseChannel(true); - future.setConnectAllowed(false); - nextRequest(req, future); - return; - } + private final void handleChunk(final HttpChunk chunk, final ChannelHandlerContext ctx, final NettyResponseFuture future, final AsyncHandler handler) throws Exception { + boolean last = chunk.isLast(); + // we don't notify updateBodyAndInterrupt with the last chunk as it's empty + if (last || updateBodyAndInterrupt(future, handler, new ResponseBodyPart(future.getURI(), null, this, chunk, last))) { - if (redirect(request, future, response, ctx)) - return; + if (chunk instanceof HttpChunkTrailer) { + HttpChunkTrailer chunkTrailer = (HttpChunkTrailer) chunk; + if (!chunkTrailer.trailingHeaders().isEmpty()) { + ResponseHeaders responseHeaders = new ResponseHeaders(future.getURI(), future.getHttpResponse(), this, chunkTrailer); + updateHeadersAndInterrupt(handler, responseHeaders); + } + } + finishUpdate(future, ctx, !chunk.isLast()); + } + } + private final class HttpProtocol implements Protocol { - if (!future.getAndSetStatusReceived(true) && updateStatusAndInterrupt(handler, status)) { - finishUpdate(future, ctx, response.isChunked()); - return; - } else if (!response.getHeaders().isEmpty() && updateHeadersAndInterrupt(handler, responseHeaders)) { - finishUpdate(future, ctx, response.isChunked()); - return; - } else if (!response.isChunked()) { - updateBodyAndInterrupt(future, handler, new ResponseBodyPart(future.getURI(), response, NettyAsyncHttpProvider.this, true)); - finishUpdate(future, ctx, false); - return; - } + public void handle(final ChannelHandlerContext ctx, final MessageEvent e, final NettyResponseFuture future) 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); - } + // The connect timeout occurred. + if (future.isCancelled() || future.isDone()) { + finishChannel(ctx); + return; + } - } else if (e.getMessage() instanceof HttpChunk) { - HttpChunk chunk = (HttpChunk) e.getMessage(); + future.touch(); + + AsyncHandler handler = future.getAsyncHandler(); + Object message = e.getMessage(); + try { + if (message instanceof HttpResponse) + handleHttpResponse((HttpResponse) message, ctx, future, handler); + + else if (message instanceof HttpChunk) + handleChunk((HttpChunk) message, ctx, future, handler); - if (handler != null) { - 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)); - } - finishUpdate(future, ctx, !chunk.isLast()); - } - } - } } catch (Exception t) { if (t instanceof IOException && !config.getIOExceptionFilters().isEmpty()) { - FilterContext fc = new FilterContext.FilterContextBuilder().asyncHandler(future.getAsyncHandler()).request(future.getRequest()) + FilterContext fc = new FilterContext.FilterContextBuilder().asyncHandler(handler).request(future.getRequest()) .ioException(IOException.class.cast(t)).build(); fc = handleIoException(fc, future); if (fc.replayRequest()) { - replayRequest(future, fc, response, ctx); + replayRequest(future, fc, ctx); return; } } @@ -2188,11 +2186,9 @@ public Object call() throws Exception { } } - // @Override public void onError(ChannelHandlerContext ctx, ExceptionEvent e) { } - // @Override public void onClose(ChannelHandlerContext ctx, ChannelStateEvent e) { } } @@ -2209,23 +2205,24 @@ private void invokeOnSucces(ChannelHandlerContext ctx, WebSocketUpgradeHandler h try { h.onSuccess(new NettyWebSocket(ctx.getChannel())); } catch (Exception ex) { - NettyAsyncHttpProvider.this.log.warn("onSuccess unexexpected exception", ex); + NettyAsyncHttpProvider.this.LOGGER.warn("onSuccess unexexpected exception", ex); } } } // @Override - public void handle(ChannelHandlerContext ctx, MessageEvent e) throws Exception { - NettyResponseFuture future = NettyResponseFuture.class.cast(ctx.getAttachment()); - WebSocketUpgradeHandler h = WebSocketUpgradeHandler.class.cast(future.getAsyncHandler()); + public void handle(ChannelHandlerContext ctx, MessageEvent e, final NettyResponseFuture future) throws Exception { + + WebSocketUpgradeHandler wsUpgradeHandler = (WebSocketUpgradeHandler) future.getAsyncHandler(); Request request = future.getRequest(); if (e.getMessage() instanceof HttpResponse) { HttpResponse response = (HttpResponse) e.getMessage(); + HttpHeaders nettyResponseHeaders = response.headers(); 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(wsUpgradeHandler).request(request).responseStatus(s).responseHeaders(responseHeaders).build(); for (ResponseFilter asyncFilter : config.getResponseFilters()) { try { fc = asyncFilter.filter(fc); @@ -2243,45 +2240,45 @@ public void handle(ChannelHandlerContext ctx, MessageEvent e) throws Exception { // The request has changed if (fc.replayRequest()) { - replayRequest(future, fc, response, ctx); + replayRequest(future, fc, ctx); return; } future.setHttpResponse(response); - if (redirect(request, future, response, ctx)) + if (exitAfterHandlingRedirect(ctx, future, request, response, response.getStatus().getCode())) return; 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; - String c = response.getHeader(HttpHeaders.Names.CONNECTION); + final boolean validUpgrade = nettyResponseHeaders.contains(HttpHeaders.Names.UPGRADE); + String c = nettyResponseHeaders.get(HttpHeaders.Names.CONNECTION); if (c == null) { - c = response.getHeader("connection"); + c = nettyResponseHeaders.get("connection"); } final boolean validConnection = c == null ? false : c.equalsIgnoreCase(HttpHeaders.Values.UPGRADE); s = new ResponseStatus(future.getURI(), response, NettyAsyncHttpProvider.this); - final boolean statusReceived = h.onStatusReceived(s) == STATE.UPGRADE; + final boolean statusReceived = wsUpgradeHandler.onStatusReceived(s) == STATE.UPGRADE; if (!statusReceived) { try { - h.onCompleted(); + wsUpgradeHandler.onCompleted(); } finally { future.done(); } return; } - final boolean headerOK = h.onHeadersReceived(responseHeaders) == STATE.CONTINUE; + final boolean headerOK = wsUpgradeHandler.onHeadersReceived(responseHeaders) == STATE.CONTINUE; if (!headerOK || !validStatus || !validUpgrade || !validConnection) { abort(future, new IOException("Invalid handshake response")); return; } - String accept = response.getHeader(HttpHeaders.Names.SEC_WEBSOCKET_ACCEPT); - String key = WebSocketUtil.getAcceptKey(future.getNettyRequest().getHeader(HttpHeaders.Names.SEC_WEBSOCKET_KEY)); + String accept = nettyResponseHeaders.get(HttpHeaders.Names.SEC_WEBSOCKET_ACCEPT); + String key = WebSocketUtil.getAcceptKey(future.getNettyRequest().headers().get(HttpHeaders.Names.SEC_WEBSOCKET_KEY)); if (accept == null || !accept.equals(key)) { abort(future, new IOException(String.format("Invalid challenge. Actual: %s. Expected: %s", accept, key))); return; @@ -2290,11 +2287,11 @@ public void handle(ChannelHandlerContext ctx, MessageEvent e) throws Exception { ctx.getPipeline().replace(HTTP_HANDLER, "ws-encoder", new WebSocket08FrameEncoder(true)); ctx.getPipeline().addBefore(WS_PROCESSOR, "ws-decoder", new WebSocket08FrameDecoder(false, false)); - invokeOnSucces(ctx, h); + invokeOnSucces(ctx, wsUpgradeHandler); future.done(); } else if (e.getMessage() instanceof WebSocketFrame) { - invokeOnSucces(ctx, h); + invokeOnSucces(ctx, wsUpgradeHandler); final WebSocketFrame frame = (WebSocketFrame) e.getMessage(); @@ -2327,9 +2324,9 @@ public void setContent(ChannelBuffer content) { if (frame.getBinaryData() != null) { webSocketChunk.setContent(ChannelBuffers.wrappedBuffer(frame.getBinaryData())); ResponseBodyPart rp = new ResponseBodyPart(future.getURI(), null, NettyAsyncHttpProvider.this, webSocketChunk, true); - h.onBodyPartReceived(rp); + wsUpgradeHandler.onBodyPartReceived(rp); - NettyWebSocket webSocket = NettyWebSocket.class.cast(h.onCompleted()); + NettyWebSocket webSocket = NettyWebSocket.class.cast(wsUpgradeHandler.onCompleted()); if (webSocket != null) { if (pendingOpcode == OPCODE_BINARY) { @@ -2340,28 +2337,25 @@ public void setContent(ChannelBuffer content) { if (frame instanceof CloseWebSocketFrame) { try { - ctx.setAttachment(DiscardEvent.class); + ctx.setAttachment(DiscardEvent.INSTANCE); 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); } finally { - h.resetSuccess(); + wsUpgradeHandler.resetSuccess(); } } } else { - log.debug("UpgradeHandler returned a null NettyWebSocket "); + LOGGER.debug("UpgradeHandler returned a null NettyWebSocket "); } } } else { - log.error("Invalid attachment {}", ctx.getAttachment()); + LOGGER.error("Invalid attachment {}", ctx.getAttachment()); } } // @Override public void onError(ChannelHandlerContext ctx, ExceptionEvent e) { try { - log.warn("onError {}", e); + LOGGER.warn("onError {}", e); if (!(ctx.getAttachment() instanceof NettyResponseFuture)) { return; } @@ -2375,13 +2369,13 @@ public void onError(ChannelHandlerContext ctx, ExceptionEvent e) { webSocket.close(); } } catch (Throwable t) { - log.error("onError", t); + LOGGER.error("onError", t); } } // @Override public void onClose(ChannelHandlerContext ctx, ChannelStateEvent e) { - log.trace("onClose {}", e); + LOGGER.trace("onClose {}", e); if (!(ctx.getAttachment() instanceof NettyResponseFuture)) { return; } @@ -2392,11 +2386,11 @@ public void onClose(ChannelHandlerContext ctx, ChannelStateEvent e) { NettyWebSocket webSocket = NettyWebSocket.class.cast(h.onCompleted()); h.resetSuccess(); - log.trace("Connection was closed abnormally (that is, with no close frame being sent)."); - if (!(ctx.getAttachment() instanceof DiscardEvent) && webSocket != null) + LOGGER.trace("Connection was closed abnormally (that is, with no close frame being sent)."); + if (ctx.getAttachment() != DiscardEvent.INSTANCE && webSocket != null) webSocket.close(1006, "Connection was closed abnormally (that is, with no close frame being sent)."); } catch (Throwable t) { - log.error("onError", t); + LOGGER.error("onError", 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 3fbc497953..2ee914353e 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 @@ -16,82 +16,22 @@ */ package com.ning.http.client.providers.netty; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; - +import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory; import org.jboss.netty.util.Timer; import com.ning.http.client.AsyncHttpProviderConfig; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutorService; + /** * This class can be used to pass Netty's internal configuration options. See Netty documentation for more information. */ public class NettyAsyncHttpProviderConfig implements AsyncHttpProviderConfig { - - /** - * Use Netty's blocking IO stategy. - */ - public final static String USE_BLOCKING_IO = "useBlockingIO"; - - /** - * Use direct {@link java.nio.ByteBuffer} - */ - public final static String USE_DIRECT_BYTEBUFFER = "bufferFactory"; - - /** - * Execute the connect operation asynchronously. - */ - public final static String EXECUTE_ASYNC_CONNECT = "asyncConnect"; - - /** - * Allow nested request from any {@link com.ning.http.client.AsyncHandler} - */ - public final static String DISABLE_NESTED_REQUEST = "disableNestedRequest"; - - /** - * Allow configuring the Netty's boss executor service. - */ - public final static String BOSS_EXECUTOR_SERVICE = "bossExecutorService"; - - /** - * See {@link java.net.Socket#setReuseAddress(boolean)} - */ - public final static String REUSE_ADDRESS = "reuseAddress"; - - /** - * Allow configuring the Netty's HttpClientCodec. - */ - public final static String HTTP_CLIENT_CODEC_MAX_INITIAL_LINE_LENGTH = "httpClientCodecMaxInitialLineLength"; - public final static String HTTP_CLIENT_CODEC_MAX_HEADER_SIZE = "httpClientCodecMaxHeaderSize"; - public final static String HTTP_CLIENT_CODEC_MAX_CHUNK_SIZE = "httpClientCodecMaxChunkSize"; - - /** - * Allow configuring the Netty's HttpClientCodec. - */ - public final static String HTTPS_CLIENT_CODEC_MAX_INITIAL_LINE_LENGTH = "httpsClientCodecMaxInitialLineLength"; - public final static String HTTPS_CLIENT_CODEC_MAX_HEADER_SIZE = "httpsClientCodecMaxHeaderSize"; - public final static String HTTPS_CLIENT_CODEC_MAX_CHUNK_SIZE = "httpsClientCodecMaxChunkSize"; - - /** - * Allow configuring the Netty's socket channel factory. - */ - public final static String SOCKET_CHANNEL_FACTORY = "socketChannelFactory"; - - private final ConcurrentHashMap properties = new ConcurrentHashMap(); - - /** - * Allow one to disable zero copy for bodies and use chunking instead; - */ - private boolean disableZeroCopy; - - private Timer nettyTimer; - private long handshakeTimeoutInMillis = 10000L; - - public NettyAsyncHttpProviderConfig() { - properties.put(REUSE_ADDRESS, "false"); - } + private final ConcurrentHashMap properties = new ConcurrentHashMap(); /** * Add a property that will be used when the AsyncHttpClient initialize its {@link com.ning.http.client.AsyncHttpProvider} @@ -150,6 +90,92 @@ public Set> propertiesSet() { return properties.entrySet(); } + /** + * Enable Netty DeadLockChecker + */ + private boolean useDeadLockChecker; + + /** + * Allow configuring the Netty's boss executor service. + */ + private ExecutorService bossExecutorService; + + /** + * Allow configuring Netty's HttpClientCodecs. + */ + private int httpClientCodecMaxInitialLineLength = 4096; + private int httpClientCodecMaxHeaderSize = 8192; + private int httpClientCodecMaxChunkSize = 8192; + + /** + * Allow configuring the Netty's socket channel factory. + */ + private NioClientSocketChannelFactory socketChannelFactory; + + /** + * Allow one to disable zero copy for bodies and use chunking instead; + */ + private boolean disableZeroCopy; + + private Timer nettyTimer; + + private long handshakeTimeoutInMillis = 10000L; + + private ChannelPool channelPool; + + /** + * chunkedFileChunkSize + */ + private int chunkedFileChunkSize = 8192; + + public boolean isUseDeadLockChecker() { + return useDeadLockChecker; + } + + public void setUseDeadLockChecker(boolean useDeadLockChecker) { + this.useDeadLockChecker = useDeadLockChecker; + } + + public ExecutorService getBossExecutorService() { + return bossExecutorService; + } + + public void setBossExecutorService(ExecutorService bossExecutorService) { + this.bossExecutorService = bossExecutorService; + } + + public int getHttpClientCodecMaxInitialLineLength() { + return httpClientCodecMaxInitialLineLength; + } + + public void setHttpClientCodecMaxInitialLineLength(int httpClientCodecMaxInitialLineLength) { + this.httpClientCodecMaxInitialLineLength = httpClientCodecMaxInitialLineLength; + } + + public int getHttpClientCodecMaxHeaderSize() { + return httpClientCodecMaxHeaderSize; + } + + public void setHttpClientCodecMaxHeaderSize(int httpClientCodecMaxHeaderSize) { + this.httpClientCodecMaxHeaderSize = httpClientCodecMaxHeaderSize; + } + + public int getHttpClientCodecMaxChunkSize() { + return httpClientCodecMaxChunkSize; + } + + public void setHttpClientCodecMaxChunkSize(int httpClientCodecMaxChunkSize) { + this.httpClientCodecMaxChunkSize = httpClientCodecMaxChunkSize; + } + + public NioClientSocketChannelFactory getSocketChannelFactory() { + return socketChannelFactory; + } + + public void setSocketChannelFactory(NioClientSocketChannelFactory socketChannelFactory) { + this.socketChannelFactory = socketChannelFactory; + } + public void setDisableZeroCopy(boolean disableZeroCopy) { this.disableZeroCopy = disableZeroCopy; } @@ -173,4 +199,20 @@ public long getHandshakeTimeoutInMillis() { public void setHandshakeTimeoutInMillis(long handshakeTimeoutInMillis) { this.handshakeTimeoutInMillis = handshakeTimeoutInMillis; } + + public ChannelPool getChannelPool() { + return channelPool; + } + + public void setChannelPool(ChannelPool channelPool) { + this.channelPool = channelPool; + } + + public int getChunkedFileChunkSize() { + return chunkedFileChunkSize; + } + + public void setChunkedFileChunkSize(int chunkedFileChunkSize) { + this.chunkedFileChunkSize = chunkedFileChunkSize; + } } 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 deleted file mode 100644 index 94186250c4..0000000000 --- a/src/main/java/com/ning/http/client/providers/netty/NettyConnectionsPool.java +++ /dev/null @@ -1,300 +0,0 @@ -/* - * 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.providers.netty; - -import static com.ning.http.util.DateUtils.millisTime; - -import java.util.ArrayList; -import java.util.List; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; - -import org.jboss.netty.channel.Channel; -import org.jboss.netty.util.Timeout; -import org.jboss.netty.util.Timer; -import org.jboss.netty.util.TimerTask; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.ning.http.client.ConnectionsPool; - -/** - * A simple implementation of {@link com.ning.http.client.ConnectionsPool} based on a {@link java.util.concurrent.ConcurrentHashMap} - */ -public class NettyConnectionsPool implements ConnectionsPool { - - private static final Logger LOGGER = 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 nettyTimer; - private final boolean sslConnectionPoolEnabled; - private final int maxTotalConnections; - private final int maxConnectionPerHost; - private final int maxConnectionLifeTimeInMs; - private final long maxIdleTime; - - public NettyConnectionsPool(NettyAsyncHttpProvider provider, Timer hashedWheelTimer) { - this(provider.getConfig().getMaxTotalConnections(),// - provider.getConfig().getMaxConnectionPerHost(),// - provider.getConfig().getIdleConnectionInPoolTimeoutInMs(),// - provider.getConfig().getMaxConnectionLifeTimeInMs(),// - provider.getConfig().isSslConnectionPoolEnabled(),// - hashedWheelTimer); - } - - public NettyConnectionsPool(int maxTotalConnections, int maxConnectionPerHost, long maxIdleTime, int maxConnectionLifeTimeInMs, - boolean sslConnectionPoolEnabled, Timer nettyTimer) { - this.maxTotalConnections = maxTotalConnections; - this.maxConnectionPerHost = maxConnectionPerHost; - this.sslConnectionPoolEnabled = sslConnectionPoolEnabled; - this.maxIdleTime = maxIdleTime; - this.maxConnectionLifeTimeInMs = maxConnectionLifeTimeInMs; - this.nettyTimer = nettyTimer; - if (maxIdleTime > 0L) { - scheduleNewIdleChannelDetector(new IdleChannelDetector()); - } - } - - private void scheduleNewIdleChannelDetector(TimerTask task) { - this.nettyTimer.newTimeout(task, maxIdleTime, TimeUnit.MILLISECONDS); - } - - private static final class IdleChannel { - final String key; - final Channel channel; - final long start; - - IdleChannel(String key, Channel channel) { - if (key == null) - throw new NullPointerException("key"); - if (channel == null) - throw new NullPointerException("channel"); - this.key = key; - this.channel = channel; - this.start = millisTime(); - } - - @Override - public boolean equals(Object o) { - return this == o || (o instanceof IdleChannel && channel.equals(IdleChannel.class.cast(o).channel)); - } - - @Override - public int hashCode() { - return channel != null ? channel.hashCode() : 0; - } - } - - private class IdleChannelDetector implements TimerTask { - - public void run(Timeout timeout) throws Exception { - try { - if (isClosed.get()) - return; - - if (LOGGER.isDebugEnabled()) { - Set keys = connectionsPool.keySet(); - - for (String s : keys) { - LOGGER.debug("Entry count for : {} : {}", s, connectionsPool.get(s).size()); - } - } - - List channelsInTimeout = new ArrayList(); - long currentTime = millisTime(); - - for (IdleChannel idleChannel : channel2IdleChannel.values()) { - long age = currentTime - idleChannel.start; - if (age > maxIdleTime) { - - LOGGER.debug("Adding Candidate Idle Channel {}", idleChannel.channel); - - // store in an unsynchronized list to minimize the impact on the ConcurrentHashMap. - channelsInTimeout.add(idleChannel); - } - } - long endConcurrentLoop = millisTime(); - - for (IdleChannel idleChannel : channelsInTimeout) { - Object attachment = idleChannel.channel.getPipeline().getContext(NettyAsyncHttpProvider.class).getAttachment(); - if (attachment instanceof NettyResponseFuture) { - NettyResponseFuture future = (NettyResponseFuture) attachment; - if (!future.isDone() && !future.isCancelled()) { - LOGGER.debug("Future not in appropriate state %s\n", future); - continue; - } - } - - if (remove(idleChannel)) { - LOGGER.debug("Closing Idle Channel {}", idleChannel.channel); - close(idleChannel.channel); - } - } - - if (LOGGER.isTraceEnabled()) { - int openChannels = 0; - for (ConcurrentLinkedQueue hostChannels : connectionsPool.values()) { - openChannels += hostChannels.size(); - } - LOGGER.trace(String.format("%d channel open, %d idle channels closed (times: 1st-loop=%d, 2nd-loop=%d).\n", openChannels, - channelsInTimeout.size(), endConcurrentLoop - currentTime, millisTime() - endConcurrentLoop)); - } - - } catch (Throwable t) { - LOGGER.error("uncaught exception!", t); - } - - scheduleNewIdleChannelDetector(timeout.getTask()); - } - } - - /** - * {@inheritDoc} - */ - public boolean offer(String uri, Channel channel) { - if (isClosed.get() || (!sslConnectionPoolEnabled && uri.startsWith("https"))) - return false; - - Long createTime = channel2CreationDate.get(channel); - if (createTime == null) { - channel2CreationDate.putIfAbsent(channel, millisTime()); - - } else if (maxConnectionLifeTimeInMs != -1 && (createTime + maxConnectionLifeTimeInMs) < millisTime()) { - LOGGER.debug("Channel {} expired", channel); - return false; - } - - LOGGER.debug("Adding uri: {} for channel {}", uri, channel); - channel.getPipeline().getContext(NettyAsyncHttpProvider.class).setAttachment(new NettyAsyncHttpProvider.DiscardEvent()); - - ConcurrentLinkedQueue idleConnectionForHost = connectionsPool.get(uri); - if (idleConnectionForHost == null) { - ConcurrentLinkedQueue newPool = new ConcurrentLinkedQueue(); - idleConnectionForHost = connectionsPool.putIfAbsent(uri, newPool); - if (idleConnectionForHost == null) - idleConnectionForHost = newPool; - } - - boolean added; - int size = idleConnectionForHost.size(); - if (maxConnectionPerHost == -1 || size < maxConnectionPerHost) { - IdleChannel idleChannel = new IdleChannel(uri, channel); - synchronized (idleConnectionForHost) { - added = idleConnectionForHost.add(idleChannel); - - if (channel2IdleChannel.put(channel, idleChannel) != null) { - LOGGER.error("Channel {} already exists in the connections pool!", channel); - } - } - } else { - LOGGER.debug("Maximum number of requests per host reached {} for {}", maxConnectionPerHost, uri); - added = false; - } - return added; - } - - /** - * {@inheritDoc} - */ - public Channel poll(String uri) { - if (!sslConnectionPoolEnabled && uri.startsWith("https")) { - return null; - } - - IdleChannel idleChannel = null; - ConcurrentLinkedQueue pooledConnectionForKey = connectionsPool.get(uri); - if (pooledConnectionForKey != null) { - boolean poolEmpty = false; - while (!poolEmpty && idleChannel == null) { - if (!pooledConnectionForKey.isEmpty()) { - synchronized (pooledConnectionForKey) { - idleChannel = pooledConnectionForKey.poll(); - if (idleChannel != null) { - channel2IdleChannel.remove(idleChannel.channel); - } - } - } - - if (idleChannel == null) { - poolEmpty = true; - } else if (!idleChannel.channel.isConnected() || !idleChannel.channel.isOpen()) { - idleChannel = null; - LOGGER.trace("Channel not connected or not opened!"); - } - } - } - return idleChannel != null ? idleChannel.channel : null; - } - - private boolean remove(IdleChannel pooledChannel) { - if (pooledChannel == null || isClosed.get()) - return false; - - boolean isRemoved = false; - ConcurrentLinkedQueue pooledConnectionForKey = connectionsPool.get(pooledChannel.key); - if (pooledConnectionForKey != null) { - isRemoved = pooledConnectionForKey.remove(pooledChannel); - } - return isRemoved |= channel2IdleChannel.remove(pooledChannel.channel) != null; - } - - /** - * {@inheritDoc} - */ - public boolean removeAll(Channel channel) { - channel2CreationDate.remove(channel); - return !isClosed.get() && remove(channel2IdleChannel.get(channel)); - } - - /** - * {@inheritDoc} - */ - public boolean canCacheConnection() { - return !isClosed.get() && (maxTotalConnections == -1 || channel2IdleChannel.size() < maxTotalConnections); - } - - /** - * {@inheritDoc} - */ - public void destroy() { - if (isClosed.getAndSet(true)) - return; - - for (Channel channel : channel2IdleChannel.keySet()) { - close(channel); - } - 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 - } - } - - public final String toString() { - return String.format("NettyConnectionPool: {pool-size: %d}", channel2IdleChannel.size()); - } -} 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 f1a9dc7d62..08e45ae2e4 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 @@ -40,6 +40,7 @@ import com.ning.http.client.ProxyServer; import com.ning.http.client.Request; import com.ning.http.client.listenable.AbstractListenableFuture; +import com.ning.http.client.providers.netty.NettyAsyncHttpProvider.DiscardEvent; import com.ning.http.client.providers.netty.timeout.TimeoutsHolder; import com.ning.http.client.uri.UriComponents; @@ -168,7 +169,7 @@ public boolean cancel(boolean force) { return false; try { - channel.getPipeline().getContext(NettyAsyncHttpProvider.class).setAttachment(new NettyAsyncHttpProvider.DiscardEvent()); + channel.getPipeline().getContext(NettyAsyncHttpProvider.class).setAttachment(DiscardEvent.INSTANCE); channel.close(); } catch (Throwable t) { // Ignore @@ -250,14 +251,14 @@ 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.getPipeline().getContext(NettyAsyncHttpProvider.class).setAttachment(DiscardEvent.INSTANCE); channel.close(); } catch (Throwable t) { // Ignore } if (!onThrowableCalled.getAndSet(true)) { try { - TimeoutException te = new TimeoutException(String.format("No response received after %s", l)); + TimeoutException te = new TimeoutException(String.format("No response received after %s ms", l)); try { asyncHandler.onThrowable(te); } catch (Throwable t) { diff --git a/src/main/java/com/ning/http/client/providers/netty/Protocol.java b/src/main/java/com/ning/http/client/providers/netty/Protocol.java index 3e8e9862c4..edf62a96cb 100644 --- a/src/main/java/com/ning/http/client/providers/netty/Protocol.java +++ b/src/main/java/com/ning/http/client/providers/netty/Protocol.java @@ -19,7 +19,7 @@ public interface Protocol { - void handle(ChannelHandlerContext ctx, MessageEvent e) throws Exception; + void handle(ChannelHandlerContext ctx, MessageEvent e, NettyResponseFuture future) throws Exception; void onError(ChannelHandlerContext ctx, ExceptionEvent e); diff --git a/src/main/java/com/ning/http/util/MiscUtils.java b/src/main/java/com/ning/http/util/MiscUtils.java index 0db03068e3..dab4d5df95 100644 --- a/src/main/java/com/ning/http/util/MiscUtils.java +++ b/src/main/java/com/ning/http/util/MiscUtils.java @@ -44,8 +44,4 @@ public static boolean getBoolean(String systemPropName, boolean defaultValue) { String systemPropValue = System.getProperty(systemPropName); return systemPropValue != null ? systemPropValue.equalsIgnoreCase("true") : defaultValue; } - - public static T withDefault(T value, T defaults) { - return value != null? value : value; - } } 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 b74433783c..ca2316fbb5 100644 --- a/src/test/java/com/ning/http/client/async/RetryNonBlockingIssue.java +++ b/src/test/java/com/ning/http/client/async/RetryNonBlockingIssue.java @@ -183,11 +183,6 @@ public void testRetryNonBlockingAsyncConnect() throws IOException, InterruptedEx bc.setConnectionTimeoutInMs(60000); bc.setRequestTimeoutInMs(30000); - NettyAsyncHttpProviderConfig config = new - NettyAsyncHttpProviderConfig(); - config.addProperty(NettyAsyncHttpProviderConfig.EXECUTE_ASYNC_CONNECT, "true"); - - bc.setAsyncHttpClientProviderConfig(config); c = new AsyncHttpClient(bc.build()); for (int i = 0; i < 32; i++) { @@ -228,11 +223,6 @@ public void testRetryBlocking() throws IOException, InterruptedException, bc.setConnectionTimeoutInMs(30000); bc.setRequestTimeoutInMs(30000); - NettyAsyncHttpProviderConfig config = new - NettyAsyncHttpProviderConfig(); - config.addProperty(NettyAsyncHttpProviderConfig.USE_BLOCKING_IO, "true"); - - bc.setAsyncHttpClientProviderConfig(config); c = new AsyncHttpClient(bc.build()); for (int i = 0; i < 32; i++) { diff --git a/src/test/java/com/ning/http/client/async/netty/NettyAsyncHttpProviderTest.java b/src/test/java/com/ning/http/client/async/netty/NettyAsyncHttpProviderTest.java index 0ee45a5752..b7073c42ef 100644 --- a/src/test/java/com/ning/http/client/async/netty/NettyAsyncHttpProviderTest.java +++ b/src/test/java/com/ning/http/client/async/netty/NettyAsyncHttpProviderTest.java @@ -29,7 +29,7 @@ public class NettyAsyncHttpProviderTest extends AbstractBasicTest { @Test public void bossThreadPoolExecutor() throws Throwable { NettyAsyncHttpProviderConfig conf = new NettyAsyncHttpProviderConfig(); - conf.addProperty(NettyAsyncHttpProviderConfig.BOSS_EXECUTOR_SERVICE, Executors.newSingleThreadExecutor()); + conf.setBossExecutorService(Executors.newSingleThreadExecutor()); AsyncHttpClientConfig cf = new AsyncHttpClientConfig.Builder().setAsyncHttpClientProviderConfig(conf).build(); AsyncHttpClient c = getAsyncHttpClient(cf); diff --git a/src/test/java/com/ning/http/client/async/netty/NettyConnectionPoolTest.java b/src/test/java/com/ning/http/client/async/netty/NettyConnectionPoolTest.java index ac2333ddf5..2283c8047c 100644 --- a/src/test/java/com/ning/http/client/async/netty/NettyConnectionPoolTest.java +++ b/src/test/java/com/ning/http/client/async/netty/NettyConnectionPoolTest.java @@ -17,19 +17,20 @@ import static org.testng.Assert.assertNull; import static org.testng.Assert.assertTrue; import static org.testng.Assert.fail; -import java.net.ConnectException; -import java.util.concurrent.TimeUnit; -import com.ning.http.client.Response; -import com.ning.http.client.providers.netty.NettyAsyncHttpProviderConfig; import org.jboss.netty.channel.Channel; import org.testng.annotations.Test; 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; +import com.ning.http.client.providers.netty.ChannelPool; +import com.ning.http.client.providers.netty.NettyAsyncHttpProviderConfig; + +import java.net.ConnectException; +import java.util.concurrent.TimeUnit; public class NettyConnectionPoolTest extends ConnectionPoolTest { @@ -41,7 +42,7 @@ public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { @Test(groups = { "standalone", "default_provider" }) public void testInvalidConnectionsPool() { - ConnectionsPool cp = new ConnectionsPool() { + ChannelPool cp = new ChannelPool() { public boolean offer(String key, Channel connection) { return false; @@ -64,7 +65,9 @@ public void destroy() { } }; - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setConnectionsPool(cp).build()); + NettyAsyncHttpProviderConfig providerConfig = new NettyAsyncHttpProviderConfig(); + providerConfig.setChannelPool(cp); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setAsyncHttpClientProviderConfig(providerConfig).build()); try { Exception exception = null; try { @@ -83,7 +86,7 @@ public void destroy() { @Test(groups = { "standalone", "default_provider" }) public void testValidConnectionsPool() { - ConnectionsPool cp = new ConnectionsPool() { + ChannelPool cp = new ChannelPool() { public boolean offer(String key, Channel connection) { return true; @@ -106,7 +109,9 @@ public void destroy() { } }; - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setConnectionsPool(cp).build()); + NettyAsyncHttpProviderConfig providerConfig = new NettyAsyncHttpProviderConfig(); + providerConfig.setChannelPool(cp); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setAsyncHttpClientProviderConfig(providerConfig).build()); try { Exception exception = null; try { @@ -123,9 +128,7 @@ public void destroy() { @Test public void testHostNotContactable() { - NettyAsyncHttpProviderConfig conf = new NettyAsyncHttpProviderConfig(); - conf.addProperty(NettyAsyncHttpProviderConfig.EXECUTE_ASYNC_CONNECT,false); - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setAsyncHttpClientProviderConfig(conf) + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder() .setAllowPoolingConnection(true).setMaximumConnectionsTotal(1).build()); try { String url = null; 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 c179b9d63d..7bb6e5c10f 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 @@ -27,11 +27,6 @@ public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { @Override protected AsyncHttpProviderConfig getProviderConfig() { - final NettyAsyncHttpProviderConfig config = - new NettyAsyncHttpProviderConfig(); - if (System.getProperty("blockingio") != null) { - config.addProperty(NettyAsyncHttpProviderConfig.USE_BLOCKING_IO, "true"); - } - return config; + return new NettyAsyncHttpProviderConfig(); } } From 02e7358de24739fc29eb7be36cdcc13693ee2bae Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 14 Jul 2014 15:19:37 +0200 Subject: [PATCH 387/701] minor clean up: finishChannel --- .../netty/NettyAsyncHttpProvider.java | 26 ++++++++----------- 1 file changed, 11 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 852e05b896..583cadbf9d 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 @@ -1024,23 +1024,19 @@ private void closeChannel(final ChannelHandlerContext ctx) { private void finishChannel(final ChannelHandlerContext ctx) { ctx.setAttachment(DiscardEvent.INSTANCE); - // The channel may have already been removed if a timeout occurred, and this method may be called just after. - if (ctx.getChannel() == null) { - return; - } - - LOGGER.debug("Closing Channel {} ", ctx.getChannel()); - - try { - ctx.getChannel().close(); - } catch (Throwable t) { - LOGGER.debug("Error closing a connection", t); - } + Channel channel = ctx.getChannel(); - if (ctx.getChannel() != null) { - openChannels.remove(ctx.getChannel()); + // The channel may have already been removed if a timeout occurred, and this method may be called just after. + if (channel != null) { + // FIXME can the context channel really be null? + LOGGER.debug("Closing Channel {} ", ctx.getChannel()); + try { + channel.close(); + } catch (Throwable t) { + LOGGER.debug("Error closing a connection", t); + } + openChannels.remove(channel); } - } @Override From 45b5e707258bcc46bee4597b4e7ae271dc6d48e0 Mon Sep 17 00:00:00 2001 From: oleksiys Date: Mon, 14 Jul 2014 22:03:42 -0700 Subject: [PATCH 388/701] [1.9.x] + fix the issue #610 https://github.com/AsyncHttpClient/async-http-client/issues/610 "Backport #525 to Grizzly provider" --- .../grizzly/GrizzlyAsyncHttpProvider.java | 140 ++++++++++-------- .../grizzly/GrizzlyConnectionPool.java | 13 +- .../grizzly/HostnameVerifierListener.java | 133 +++++++++++++++++ .../http/client/providers/grizzly/Utils.java | 34 +++++ .../async/grizzly/GrizzlyBasicHttpsTest.java | 7 +- 5 files changed, 250 insertions(+), 77 deletions(-) create mode 100644 src/main/java/com/ning/http/client/providers/grizzly/HostnameVerifierListener.java create mode 100644 src/main/java/com/ning/http/client/providers/grizzly/Utils.java 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 f598af7bdd..3c610ec43e 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,12 +13,52 @@ package com.ning.http.client.providers.grizzly; -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; +import com.ning.http.client.AsyncHandler; +import com.ning.http.client.AsyncHandlerExtensions; +import com.ning.http.client.AsyncHttpClient; +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.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.Param; +import com.ning.http.client.Part; +import com.ning.http.client.ProxyServer; +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.UpgradeHandler; +import com.ning.http.client.cookie.Cookie; +import com.ning.http.client.cookie.CookieDecoder; +import com.ning.http.client.filter.FilterContext; +import com.ning.http.client.filter.ResponseFilter; +import com.ning.http.client.listener.TransferCompletionHandler; +import com.ning.http.client.ntlm.NTLMEngine; +import com.ning.http.client.uri.UriComponents; +import com.ning.http.client.websocket.WebSocket; +import com.ning.http.client.websocket.WebSocketByteListener; +import com.ning.http.client.websocket.WebSocketCloseCodeReasonListener; +import com.ning.http.client.websocket.WebSocketListener; +import com.ning.http.client.websocket.WebSocketPingListener; +import com.ning.http.client.websocket.WebSocketPongListener; +import com.ning.http.client.websocket.WebSocketTextListener; +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 static com.ning.http.util.AsyncHttpProviderUtils.getNonEmptyPath; +import com.ning.http.util.AuthenticatorUtils; import static com.ning.http.util.MiscUtils.isNonEmpty; +import com.ning.http.util.ProxyUtils; +import com.ning.http.util.SslUtils; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; @@ -43,10 +83,12 @@ import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; - +import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLContext; - import org.glassfish.grizzly.Buffer; +import org.glassfish.grizzly.CloseListener; +import org.glassfish.grizzly.CloseType; +import org.glassfish.grizzly.Closeable; import org.glassfish.grizzly.CompletionHandler; import org.glassfish.grizzly.Connection; import org.glassfish.grizzly.EmptyCompletionHandler; @@ -103,53 +145,9 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.ning.http.client.AsyncHandler; -import com.ning.http.client.AsyncHandlerExtensions; -import com.ning.http.client.AsyncHttpClient; -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.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.Param; -import com.ning.http.client.Part; -import com.ning.http.client.ProxyServer; -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.UpgradeHandler; -import com.ning.http.client.cookie.Cookie; -import com.ning.http.client.cookie.CookieDecoder; -import com.ning.http.client.filter.FilterContext; -import com.ning.http.client.filter.ResponseFilter; -import com.ning.http.client.listener.TransferCompletionHandler; -import com.ning.http.client.ntlm.NTLMEngine; -import com.ning.http.client.uri.UriComponents; -import com.ning.http.client.websocket.WebSocket; -import com.ning.http.client.websocket.WebSocketByteListener; -import com.ning.http.client.websocket.WebSocketCloseCodeReasonListener; -import com.ning.http.client.websocket.WebSocketListener; -import com.ning.http.client.websocket.WebSocketPingListener; -import com.ning.http.client.websocket.WebSocketPongListener; -import com.ning.http.client.websocket.WebSocketTextListener; -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.ProxyUtils; -import com.ning.http.util.SslUtils; - -import org.glassfish.grizzly.CloseListener; -import org.glassfish.grizzly.CloseType; -import org.glassfish.grizzly.Closeable; +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; /** * A Grizzly 2.0-based implementation of {@link AsyncHttpProvider}. @@ -396,8 +394,13 @@ public void onTimeout(Connection connection) { true, false, false); - final SwitchingSSLFilter filter = new SwitchingSSLFilter(configurator, defaultSecState); - fcb.add(filter); + final SwitchingSSLFilter sslFilter = + new SwitchingSSLFilter(configurator, defaultSecState); + if (clientConfig.getHostnameVerifier() != null) { + sslFilter.addHandshakeListener(new HostnameVerifierListener()); + } + fcb.add(sslFilter); + final AsyncHttpClientEventFilter eventFilter = new AsyncHttpClientEventFilter(this, (Integer) providerConfig.getProperty(MAX_HTTP_PACKET_HEADER_SIZE)); final AsyncHttpClientFilter clientFilter = @@ -2394,12 +2397,29 @@ void doAsyncConnect(final Request request, final UriComponents uri = request.getURI(); String host = ((proxy != null) ? proxy.getHost() : uri.getHost()); int port = ((proxy != null) ? proxy.getPort() : uri.getPort()); - if(request.getLocalAddress()!=null) { - connectionHandler.connect(new InetSocketAddress(host, getPort(uri, port)), new InetSocketAddress(request.getLocalAddress(), 0), - createConnectionCompletionHandler(request, requestFuture, connectHandler)); + + CompletionHandler completionHandler = + createConnectionCompletionHandler(request, requestFuture, + connectHandler); + + final HostnameVerifier verifier = + provider.clientConfig.getHostnameVerifier(); + + if (Utils.isSecure(uri) && verifier != null) { + completionHandler = + HostnameVerifierListener.wrapWithHostnameVerifierHandler( + completionHandler, verifier, uri.getHost()); + } + + if (request.getLocalAddress() != null) { + connectionHandler.connect(new InetSocketAddress(host, + getPort(uri, port)), + new InetSocketAddress(request.getLocalAddress(), 0), + completionHandler); } else { - connectionHandler.connect(new InetSocketAddress(host, getPort(uri, port)), - createConnectionCompletionHandler(request, requestFuture, connectHandler)); + connectionHandler.connect(new InetSocketAddress(host, + getPort(uri, port)), + completionHandler); } } @@ -2452,7 +2472,7 @@ void destroy() { pool.destroy(); } - + CompletionHandler createConnectionCompletionHandler(final Request request, final GrizzlyResponseFuture future, final CompletionHandler wrappedHandler) { diff --git a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyConnectionPool.java b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyConnectionPool.java index 4828b762ee..63729a6cfb 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyConnectionPool.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyConnectionPool.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012 Sonatype, Inc. All rights reserved. + * Copyright (c) 2012-2014 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. @@ -14,6 +14,7 @@ package com.ning.http.client.providers.grizzly; import static com.ning.http.util.DateUtils.millisTime; +import static com.ning.http.client.providers.grizzly.Utils.*; import com.ning.http.client.AsyncHttpClientConfig; @@ -267,16 +268,6 @@ public void destroy() { } - // --------------------------------------------------------- Private Methods - - - private boolean isSecure(String uri) { - - return (uri.startsWith("https") || uri.startsWith("wss")); - - } - - // ---------------------------------------------------------- Nested Classes diff --git a/src/main/java/com/ning/http/client/providers/grizzly/HostnameVerifierListener.java b/src/main/java/com/ning/http/client/providers/grizzly/HostnameVerifierListener.java new file mode 100644 index 0000000000..6bcc889a32 --- /dev/null +++ b/src/main/java/com/ning/http/client/providers/grizzly/HostnameVerifierListener.java @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2014 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.providers.grizzly; + +import com.ning.http.util.Base64; +import java.io.IOException; +import java.net.ConnectException; +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.SSLSession; +import org.glassfish.grizzly.CompletionHandler; +import org.glassfish.grizzly.Connection; +import org.glassfish.grizzly.Grizzly; +import org.glassfish.grizzly.attributes.Attribute; +import org.glassfish.grizzly.ssl.SSLBaseFilter; +import org.glassfish.grizzly.ssl.SSLUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * The SSL handshake listener, that checks the SSL session hostname after + * handshake is completed. + * + * @author Grizzly Team + */ +class HostnameVerifierListener implements SSLBaseFilter.HandshakeListener { + private final static Logger LOGGER = LoggerFactory.getLogger(HostnameVerifierListener.class); + + private static final Attribute VERIFIER_TASK_ATTR = + Grizzly.DEFAULT_ATTRIBUTE_BUILDER.createAttribute( + HostnameVerifierTask.class.getName()); + + public HostnameVerifierListener() { + } + + @Override + public void onStart(final Connection connection) { + // do nothing + LOGGER.debug("SSL Handshake onStart: "); + } + + @Override + public void onComplete(final Connection connection) { + final HostnameVerifierTask task = VERIFIER_TASK_ATTR.remove(connection); + if (task != null) { + task.verify(); + } + } + + static CompletionHandler wrapWithHostnameVerifierHandler( + final CompletionHandler completionHandler, + final HostnameVerifier verifier, final String host) { + + return new CompletionHandler() { + + public void cancelled() { + if (completionHandler != null) { + completionHandler.cancelled(); + } + } + + public void failed(final Throwable throwable) { + if (completionHandler != null) { + completionHandler.failed(throwable); + } + } + + public void completed(final Connection connection) { + assignHostnameVerifyTask(connection, verifier, host, + completionHandler); + + if (completionHandler != null) { + completionHandler.completed(connection); + } + } + + public void updated(final Connection connection) { + if (completionHandler != null) { + completionHandler.updated(connection); + } + } + }; + } + + private static void assignHostnameVerifyTask(final Connection connection, + final HostnameVerifier verifier, final String host, + final CompletionHandler delegate) { + final HostnameVerifierTask task = new HostnameVerifierTask( + verifier, connection, host, delegate); + VERIFIER_TASK_ATTR.set(connection, task); + } + + private static class HostnameVerifierTask { + private final HostnameVerifier verifier; + private final Connection connection; + private final String host; + private final CompletionHandler delegate; + + public HostnameVerifierTask(final HostnameVerifier verifier, + final Connection connection, + final String host, + final CompletionHandler delegate) { + this.verifier = verifier; + this.connection = connection; + this.host = host; + this.delegate = delegate; + } + + public void verify() { + final SSLSession session = SSLUtils.getSSLEngine(connection).getSession(); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("SSL Handshake onComplete: session = {}, id = {}, isValid = {}, host = {}", + session.toString(), Base64.encode(session.getId()), session.isValid(), host); + } + + if (!verifier.verify(host, session)) { + connection.close(); // XXX what's the correct way to kill a connection? + IOException e = new ConnectException("Host name verification failed for host " + host); + delegate.failed(e); + } + } + } +} diff --git a/src/main/java/com/ning/http/client/providers/grizzly/Utils.java b/src/main/java/com/ning/http/client/providers/grizzly/Utils.java new file mode 100644 index 0000000000..d03c579e80 --- /dev/null +++ b/src/main/java/com/ning/http/client/providers/grizzly/Utils.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2013-2014 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.providers.grizzly; + +import com.ning.http.client.uri.UriComponents; + +public class Utils { + // ------------------------------------------------------------ Constructors + + private Utils() { + } + + // ---------------------------------------------------------- Public Methods + + public static boolean isSecure(final String uri) { + return (uri.startsWith("https") || uri.startsWith("wss")); + } + + public static boolean isSecure(final UriComponents uri) { + final String scheme = uri.getScheme(); + return ("https".equals(scheme) || "wss".equals(scheme)); + } +} 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 46c4cfdbb7..5db83e983c 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012 Sonatype, Inc. All rights reserved. + * Copyright (c) 2012-2014 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. @@ -13,7 +13,6 @@ package com.ning.http.client.async.grizzly; -import org.testng.annotations.Test; import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClientConfig; @@ -26,8 +25,4 @@ public class GrizzlyBasicHttpsTest extends BasicHttpsTest { public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { return ProviderUtil.grizzlyProvider(config); } - - @Test(enabled = false) - public void failInstantlyIfHostNamesDiffer() throws Exception { - } } From 13f70868003555da3a5be9dc37225413de796990 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 15 Jul 2014 12:13:15 +0200 Subject: [PATCH 389/701] Introduce Channels helper --- .../http/client/providers/netty/Channels.java | 53 ++++++++++++++ .../providers/netty/DefaultChannelPool.java | 7 +- .../netty/NettyAsyncHttpProvider.java | 72 +++++++++---------- .../providers/netty/NettyConnectListener.java | 4 +- .../providers/netty/NettyResponseFuture.java | 5 +- 5 files changed, 94 insertions(+), 47 deletions(-) create mode 100644 src/main/java/com/ning/http/client/providers/netty/Channels.java diff --git a/src/main/java/com/ning/http/client/providers/netty/Channels.java b/src/main/java/com/ning/http/client/providers/netty/Channels.java new file mode 100644 index 0000000000..c0d7474205 --- /dev/null +++ b/src/main/java/com/ning/http/client/providers/netty/Channels.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2014 AsyncHttpClient Project. 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.providers.netty; + +import org.jboss.netty.channel.Channel; +import org.jboss.netty.channel.ChannelHandlerContext; + +import com.ning.http.client.providers.netty.NettyAsyncHttpProvider.DiscardEvent; + +public final class Channels { + + private Channels() { + } + + private static ChannelHandlerContext getAHCHandlerContext(Channel channel) { + return channel.getPipeline().getContext(NettyAsyncHttpProvider.class); + } + + public static Object getAttachment(ChannelHandlerContext ctx) { + return ctx.getAttachment(); + } + + public static void setAttachment(ChannelHandlerContext ctx, Object attachment) { + ctx.setAttachment(attachment); + } + + public static Object getAttachment(Channel channel) { + return getAHCHandlerContext(channel).getAttachment(); + } + + public static void setAttachment(Channel channel, Object attachment) { + setAttachment(getAHCHandlerContext(channel), attachment); + } + + public static void setDiscard(ChannelHandlerContext ctx) { + ctx.setAttachment(DiscardEvent.INSTANCE); + } + + public static void setDiscard(Channel channel) { + setAttachment(channel, DiscardEvent.INSTANCE); + } +} diff --git a/src/main/java/com/ning/http/client/providers/netty/DefaultChannelPool.java b/src/main/java/com/ning/http/client/providers/netty/DefaultChannelPool.java index 812ccc3a8e..1ab685f641 100644 --- a/src/main/java/com/ning/http/client/providers/netty/DefaultChannelPool.java +++ b/src/main/java/com/ning/http/client/providers/netty/DefaultChannelPool.java @@ -30,8 +30,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.ning.http.client.providers.netty.NettyAsyncHttpProvider.DiscardEvent; - /** * A simple implementation of {@link com.ning.http.client.ChannelPool} based on a {@link java.util.concurrent.ConcurrentHashMap} */ @@ -162,7 +160,7 @@ private List expiredChannels(ConcurrentLinkedQueue poo private boolean isChannelCloseable(Channel channel) { boolean closeable = true; - Object attachment = channel.getPipeline().getContext(NettyAsyncHttpProvider.class).getAttachment(); + Object attachment = Channels.getAttachment(channel); if (attachment instanceof NettyResponseFuture) { NettyResponseFuture future = (NettyResponseFuture) attachment; closeable = !future.isDone() || !future.isCancelled(); @@ -339,7 +337,8 @@ public void destroy() { private void close(Channel channel) { try { - channel.getPipeline().getContext(NettyAsyncHttpProvider.class).setAttachment(DiscardEvent.INSTANCE); + // FIXME pity to have to do this here + Channels.setDiscard(channel); channel2Creation.remove(channel); channel.close(); } catch (Throwable t) { 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 583cadbf9d..604f364a03 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 @@ -803,8 +803,9 @@ public void close() { for (Channel channel : openChannels) { ChannelHandlerContext ctx = channel.getPipeline().getContext(NettyAsyncHttpProvider.class); - if (ctx.getAttachment() instanceof NettyResponseFuture) { - NettyResponseFuture future = (NettyResponseFuture) ctx.getAttachment(); + Object attachment = Channels.getAttachment(ctx); + if (attachment instanceof NettyResponseFuture) { + NettyResponseFuture future = (NettyResponseFuture) attachment; future.cancelTimeouts(); } } @@ -1022,7 +1023,7 @@ private void closeChannel(final ChannelHandlerContext ctx) { } private void finishChannel(final ChannelHandlerContext ctx) { - ctx.setAttachment(DiscardEvent.INSTANCE); + Channels.setDiscard(ctx); Channel channel = ctx.getChannel(); @@ -1045,7 +1046,7 @@ public void messageReceived(final ChannelHandlerContext ctx, MessageEvent e) thr // call super to reset the read timeout super.messageReceived(ctx, e); - Object attachment = ctx.getAttachment(); + Object attachment = Channels.getAttachment(ctx); if (attachment == null) LOGGER.debug("ChannelHandlerContext doesn't have any attachment"); @@ -1063,7 +1064,7 @@ public void messageReceived(final ChannelHandlerContext ctx, MessageEvent e) thr ac.call(); } else { ac.call(); - ctx.setAttachment(DiscardEvent.INSTANCE); + Channels.setDiscard(ctx); } } else if (attachment instanceof NettyResponseFuture) { @@ -1279,17 +1280,16 @@ public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws LOGGER.trace("super.channelClosed", ex); } - LOGGER.debug("Channel Closed: {} with attachment {}", e.getChannel(), ctx.getAttachment()); + Object attachment = Channels.getAttachment(ctx); + LOGGER.debug("Channel Closed: {} with attachment {}", e.getChannel(), attachment); - if (ctx.getAttachment() instanceof AsyncCallable) { - AsyncCallable ac = (AsyncCallable) ctx.getAttachment(); + if (attachment instanceof AsyncCallable) { + AsyncCallable ac = (AsyncCallable) attachment; ctx.setAttachment(ac.future()); ac.call(); - return; - } - if (ctx.getAttachment() instanceof NettyResponseFuture) { - NettyResponseFuture future = (NettyResponseFuture) ctx.getAttachment(); + } else if (attachment instanceof NettyResponseFuture) { + NettyResponseFuture future = (NettyResponseFuture) attachment; future.touch(); if (!config.getIOExceptionFilters().isEmpty()) { @@ -1325,7 +1325,7 @@ protected boolean remotelyClosed(Channel channel, NettyResponseFuture future) connectionsPool.removeAll(channel); if (future == null) { - Object attachment = channel.getPipeline().getContext(NettyAsyncHttpProvider.class).getAttachment(); + Object attachment = Channels.getAttachment(channel); if (attachment instanceof NettyResponseFuture) future = (NettyResponseFuture) attachment; } @@ -1412,13 +1412,13 @@ public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws } try { - if (cause instanceof ClosedChannelException) { return; } - if (ctx.getAttachment() instanceof NettyResponseFuture) { - future = (NettyResponseFuture) ctx.getAttachment(); + Object attachment = Channels.getAttachment(ctx); + if (attachment instanceof NettyResponseFuture) { + future = (NettyResponseFuture) attachment; future.attachChannel(null, false); future.touch(); @@ -1448,8 +1448,8 @@ public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws LOGGER.debug("Trying to recover from dead Channel: {}", channel); return; } - } else if (ctx.getAttachment() instanceof AsyncCallable) { - future = ((AsyncCallable) ctx.getAttachment()).future(); + } else if (attachment instanceof AsyncCallable) { + future = ((AsyncCallable) attachment).future(); } } catch (Throwable t) { cause = t; @@ -1844,7 +1844,7 @@ private final boolean tryToOfferChannelToPool(ChannelHandlerContext ctx, boolean Channel channel = ctx.getChannel(); if (keepAlive && channel.isReadable() && connectionsPool.offer(poolKey, channel)) { LOGGER.debug("Adding key: {} for channel {}", poolKey, channel); - ctx.setAttachment(DiscardEvent.INSTANCE); + Channels.setDiscard(ctx); return true; } else { // not offered @@ -2228,7 +2228,6 @@ public void handle(ChannelHandlerContext ctx, MessageEvent e, final NettyRespons } catch (FilterException efe) { abort(future, efe); } - } // The handler may have been wrapped. @@ -2333,7 +2332,7 @@ public void setContent(ChannelBuffer content) { if (frame instanceof CloseWebSocketFrame) { try { - ctx.setAttachment(DiscardEvent.INSTANCE); + Channels.setDiscard(ctx); webSocket.onClose(CloseWebSocketFrame.class.cast(frame).getStatusCode(), CloseWebSocketFrame.class.cast(frame).getReasonText()); } finally { wsUpgradeHandler.resetSuccess(); @@ -2344,19 +2343,20 @@ public void setContent(ChannelBuffer content) { } } } else { - LOGGER.error("Invalid attachment {}", ctx.getAttachment()); + LOGGER.error("Invalid message {}", e.getMessage()); } } // @Override public void onError(ChannelHandlerContext ctx, ExceptionEvent e) { try { + Object attachment = Channels.getAttachment(ctx); LOGGER.warn("onError {}", e); - if (!(ctx.getAttachment() instanceof NettyResponseFuture)) { + if (!(attachment instanceof NettyResponseFuture)) { return; } - NettyResponseFuture nettyResponse = NettyResponseFuture.class.cast(ctx.getAttachment()); + NettyResponseFuture nettyResponse = (NettyResponseFuture) attachment; WebSocketUpgradeHandler h = WebSocketUpgradeHandler.class.cast(nettyResponse.getAsyncHandler()); NettyWebSocket webSocket = NettyWebSocket.class.cast(h.onCompleted()); @@ -2372,21 +2372,17 @@ public void onError(ChannelHandlerContext ctx, ExceptionEvent e) { // @Override public void onClose(ChannelHandlerContext ctx, ChannelStateEvent e) { LOGGER.trace("onClose {}", e); - if (!(ctx.getAttachment() instanceof NettyResponseFuture)) { - return; - } - - try { - NettyResponseFuture nettyResponse = NettyResponseFuture.class.cast(ctx.getAttachment()); - WebSocketUpgradeHandler h = WebSocketUpgradeHandler.class.cast(nettyResponse.getAsyncHandler()); - NettyWebSocket webSocket = NettyWebSocket.class.cast(h.onCompleted()); - h.resetSuccess(); + + Object attachment = Channels.getAttachment(ctx); + if (attachment instanceof NettyResponseFuture) { + try { + NettyResponseFuture nettyResponse = (NettyResponseFuture) attachment; + WebSocketUpgradeHandler h = WebSocketUpgradeHandler.class.cast(nettyResponse.getAsyncHandler()); + h.resetSuccess(); - LOGGER.trace("Connection was closed abnormally (that is, with no close frame being sent)."); - if (ctx.getAttachment() != DiscardEvent.INSTANCE && webSocket != null) - webSocket.close(1006, "Connection was closed abnormally (that is, with no close frame being sent)."); - } catch (Throwable t) { - LOGGER.error("onError", t); + } catch (Throwable t) { + LOGGER.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 ca05843964..81ecb60089 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 @@ -62,8 +62,8 @@ public NettyResponseFuture future() { } public final void operationComplete(ChannelFuture f) throws Exception { + Channel channel = f.getChannel(); if (f.isSuccess()) { - Channel channel = f.getChannel(); channel.getPipeline().getContext(NettyAsyncHttpProvider.class).setAttachment(future); final SslHandler sslHandler = (SslHandler) channel.getPipeline().get(NettyAsyncHttpProvider.SSL_HANDLER); @@ -104,7 +104,7 @@ public void operationComplete(ChannelFuture handshakeFuture) throws Exception { || future.getState() != NettyResponseFuture.STATE.NEW)) { LOGGER.debug("Retrying {} ", nettyRequest); - if (future.provider().remotelyClosed(f.getChannel(), future)) { + if (future.provider().remotelyClosed(channel, future)) { return; } } 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 08e45ae2e4..92e1a9d41d 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 @@ -40,7 +40,6 @@ import com.ning.http.client.ProxyServer; import com.ning.http.client.Request; import com.ning.http.client.listenable.AbstractListenableFuture; -import com.ning.http.client.providers.netty.NettyAsyncHttpProvider.DiscardEvent; import com.ning.http.client.providers.netty.timeout.TimeoutsHolder; import com.ning.http.client.uri.UriComponents; @@ -169,7 +168,7 @@ public boolean cancel(boolean force) { return false; try { - channel.getPipeline().getContext(NettyAsyncHttpProvider.class).setAttachment(DiscardEvent.INSTANCE); + Channels.setDiscard(channel); channel.close(); } catch (Throwable t) { // Ignore @@ -251,7 +250,7 @@ public V get(long l, TimeUnit tu) throws InterruptedException, TimeoutException, if (expired) { isCancelled.set(true); try { - channel.getPipeline().getContext(NettyAsyncHttpProvider.class).setAttachment(DiscardEvent.INSTANCE); + Channels.setDiscard(channel); channel.close(); } catch (Throwable t) { // Ignore From ec31f393b8b954c8139f7bba12fae81952624953 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 15 Jul 2014 16:13:16 +0200 Subject: [PATCH 390/701] 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 604f364a03..43b17db803 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 @@ -1030,7 +1030,7 @@ private void finishChannel(final ChannelHandlerContext ctx) { // The channel may have already been removed if a timeout occurred, and this method may be called just after. if (channel != null) { // FIXME can the context channel really be null? - LOGGER.debug("Closing Channel {} ", ctx.getChannel()); + LOGGER.debug("Closing Channel {} ", channel); try { channel.close(); } catch (Throwable t) { From 503253cbbd556d5b8ea17afd2e848fc983faf6e1 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 15 Jul 2014 16:14:00 +0200 Subject: [PATCH 391/701] Rename connectionsPool into channelPool --- .../netty/NettyAsyncHttpProvider.java | 20 +++++++++---------- 1 file changed, 10 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 43b17db803..3fa6e9fea5 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 @@ -175,7 +175,7 @@ public boolean remove(Object o) { return removed; } }; - private final ChannelPool connectionsPool; + private final ChannelPool channelPool; // FIXME should be the pool responsibility private Semaphore freeConnections = null; private final NettyAsyncHttpProviderConfig providerConfig; @@ -243,7 +243,7 @@ public NettyAsyncHttpProvider(AsyncHttpClientConfig config) { } else if (cp == null) { cp = new NonChannelPool(); } - this.connectionsPool = cp; + this.channelPool = cp; if (config.getMaxTotalConnections() != -1) { trackConnections = true; @@ -265,7 +265,7 @@ public String toString() { return String.format("NettyAsyncHttpProvider:\n\t- maxConnections: %d\n\t- openChannels: %s\n\t- connectionPools: %s",// config.getMaxTotalConnections() - availablePermits,// openChannels.toString(),// - connectionsPool.toString()); + channelPool.toString()); } void configureNetty() { @@ -351,7 +351,7 @@ public ChannelPipeline getPipeline() throws Exception { } private Channel lookupInCache(UriComponents uri, ProxyServer proxy, ConnectionPoolKeyStrategy strategy) { - final Channel channel = connectionsPool.poll(getPoolKey(uri, proxy, strategy)); + final Channel channel = channelPool.poll(getPoolKey(uri, proxy, strategy)); if (channel != null) { LOGGER.debug("Using cached Channel {}\n for uri {}\n", channel, uri); @@ -798,7 +798,7 @@ private static HttpRequest construct(AsyncHttpClientConfig config, Request reque public void close() { if (isClose.compareAndSet(false, true)) { try { - connectionsPool.destroy(); + channelPool.destroy(); openChannels.close(); for (Channel channel : openChannels) { @@ -943,7 +943,7 @@ private ListenableFuture doConnect(final Request request, final AsyncHand // Do not throw an exception when we need an extra connection for a redirect. if (!reclaimCache) { - if (!connectionsPool.canCacheConnection()) { + if (!channelPool.canCacheConnection()) { IOException ex = new IOException(String.format("Too many connections %s", config.getMaxTotalConnections())); try { asyncHandler.onThrowable(ex); @@ -1018,7 +1018,7 @@ private ListenableFuture doConnect(final Request request, final AsyncHand } private void closeChannel(final ChannelHandlerContext ctx) { - connectionsPool.removeAll(ctx.getChannel()); + channelPool.removeAll(ctx.getChannel()); finishChannel(ctx); } @@ -1273,7 +1273,7 @@ public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws return; } - connectionsPool.removeAll(ctx.getChannel()); + channelPool.removeAll(ctx.getChannel()); try { super.channelClosed(ctx, e); } catch (Exception ex) { @@ -1322,7 +1322,7 @@ protected boolean remotelyClosed(Channel channel, NettyResponseFuture future) return true; } - connectionsPool.removeAll(channel); + channelPool.removeAll(channel); if (future == null) { Object attachment = Channels.getAttachment(channel); @@ -1842,7 +1842,7 @@ private boolean exitAfterHandlingRedirect(ChannelHandlerContext ctx, NettyRespon private final boolean tryToOfferChannelToPool(ChannelHandlerContext ctx, boolean keepAlive, String poolKey) { Channel channel = ctx.getChannel(); - if (keepAlive && channel.isReadable() && connectionsPool.offer(poolKey, channel)) { + if (keepAlive && channel.isReadable() && channelPool.offer(poolKey, channel)) { LOGGER.debug("Adding key: {} for channel {}", poolKey, channel); Channels.setDiscard(ctx); return true; From de76dfba12fa836660a931696993249d399f4032 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 15 Jul 2014 16:15:41 +0200 Subject: [PATCH 392/701] Only compute message parameters when debug is enabled --- .../http/client/providers/netty/NettyConnectListener.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) 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 81ecb60089..070bbe5981 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 @@ -78,8 +78,9 @@ public void operationComplete(ChannelFuture handshakeFuture) throws Exception { SSLEngine engine = sslHandler.getEngine(); SSLSession session = engine.getSession(); - LOGGER.debug("onFutureSuccess: session = {}, id = {}, isValid = {}, host = {}", session.toString(), - Base64.encode(session.getId()), session.isValid(), host); + if (LOGGER.isDebugEnabled()) + LOGGER.debug("onFutureSuccess: session = {}, id = {}, isValid = {}, host = {}", session.toString(), + Base64.encode(session.getId()), session.isValid(), host); if (!hostnameVerifier.verify(host, session)) { ConnectException exception = new ConnectException("HostnameVerifier exception"); future.abort(exception); From 0305e644b4209aa74363020fb3661fd10a8c01bf Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 15 Jul 2014 16:18:04 +0200 Subject: [PATCH 393/701] First perform final boolean check so block could be jitted away --- .../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 3fa6e9fea5..14784483c3 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 @@ -169,7 +169,7 @@ public class NettyAsyncHttpProvider extends SimpleChannelUpstreamHandler impleme @Override public boolean remove(Object o) { boolean removed = super.remove(o); - if (removed && trackConnections) { + if (trackConnections && removed) { freeConnections.release(); } return removed; From f865ac8232ddf346b09a6a84208d6517c7ef9d56 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 15 Jul 2014 18:00:07 +0200 Subject: [PATCH 394/701] Move pools to own package --- .../netty/NettyAsyncHttpProvider.java | 29 +++---------- .../netty/NettyAsyncHttpProviderConfig.java | 1 + .../netty/{ => pool}/ChannelPool.java | 2 +- .../netty/{ => pool}/DefaultChannelPool.java | 20 +++++---- .../providers/netty/pool/NonChannelPool.java | 41 +++++++++++++++++++ .../async/netty/NettyConnectionPoolTest.java | 2 +- 6 files changed, 61 insertions(+), 34 deletions(-) rename src/main/java/com/ning/http/client/providers/netty/{ => pool}/ChannelPool.java (97%) rename src/main/java/com/ning/http/client/providers/netty/{ => pool}/DefaultChannelPool.java (94%) create mode 100644 src/main/java/com/ning/http/client/providers/netty/pool/NonChannelPool.java 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 14784483c3..5691551f4d 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,9 @@ 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.pool.ChannelPool; +import com.ning.http.client.providers.netty.pool.DefaultChannelPool; +import com.ning.http.client.providers.netty.pool.NonChannelPool; import com.ning.http.client.providers.netty.spnego.SpnegoEngine; import com.ning.http.client.providers.netty.timeout.IdleConnectionTimeoutTimerTask; import com.ning.http.client.providers.netty.timeout.RequestTimeoutTimerTask; @@ -239,7 +242,7 @@ public NettyAsyncHttpProvider(AsyncHttpClientConfig config) { // This is dangerous as we can't catch a wrong typed ConnectionsPool ChannelPool cp = providerConfig.getChannelPool(); if (cp == null && config.isAllowPoolingConnection()) { - cp = new DefaultChannelPool(this, nettyTimer); + cp = new DefaultChannelPool(config, nettyTimer); } else if (cp == null) { cp = new NonChannelPool(); } @@ -1745,32 +1748,10 @@ public void getBytes(byte[] bytes) { } } - protected AsyncHttpClientConfig getConfig() { + public AsyncHttpClientConfig getConfig() { return config; } - private static class NonChannelPool implements ChannelPool { - - public boolean offer(String uri, Channel connection) { - return false; - } - - public Channel poll(String uri) { - return null; - } - - public boolean removeAll(Channel connection) { - return false; - } - - public boolean canCacheConnection() { - return true; - } - - public void destroy() { - } - } - private static final boolean validateWebSocketRequest(Request request, AsyncHandler asyncHandler) { if (request.getMethod() != "GET" || !(asyncHandler instanceof WebSocketUpgradeHandler)) { return false; 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 2ee914353e..6c6e1ffa1a 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 @@ -20,6 +20,7 @@ import org.jboss.netty.util.Timer; import com.ning.http.client.AsyncHttpProviderConfig; +import com.ning.http.client.providers.netty.pool.ChannelPool; import java.util.Map; import java.util.Set; diff --git a/src/main/java/com/ning/http/client/providers/netty/ChannelPool.java b/src/main/java/com/ning/http/client/providers/netty/pool/ChannelPool.java similarity index 97% rename from src/main/java/com/ning/http/client/providers/netty/ChannelPool.java rename to src/main/java/com/ning/http/client/providers/netty/pool/ChannelPool.java index c8331cd3b7..cec8d6a0e8 100644 --- a/src/main/java/com/ning/http/client/providers/netty/ChannelPool.java +++ b/src/main/java/com/ning/http/client/providers/netty/pool/ChannelPool.java @@ -14,7 +14,7 @@ * under the License. * */ -package com.ning.http.client.providers.netty; +package com.ning.http.client.providers.netty.pool; import org.jboss.netty.channel.Channel; diff --git a/src/main/java/com/ning/http/client/providers/netty/DefaultChannelPool.java b/src/main/java/com/ning/http/client/providers/netty/pool/DefaultChannelPool.java similarity index 94% rename from src/main/java/com/ning/http/client/providers/netty/DefaultChannelPool.java rename to src/main/java/com/ning/http/client/providers/netty/pool/DefaultChannelPool.java index 1ab685f641..ea75efe0f7 100644 --- a/src/main/java/com/ning/http/client/providers/netty/DefaultChannelPool.java +++ b/src/main/java/com/ning/http/client/providers/netty/pool/DefaultChannelPool.java @@ -10,7 +10,7 @@ * "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.providers.netty; +package com.ning.http.client.providers.netty.pool; import static com.ning.http.util.DateUtils.millisTime; @@ -30,8 +30,12 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.ning.http.client.AsyncHttpClientConfig; +import com.ning.http.client.providers.netty.Channels; +import com.ning.http.client.providers.netty.NettyResponseFuture; + /** - * A simple implementation of {@link com.ning.http.client.ChannelPool} based on a {@link java.util.concurrent.ConcurrentHashMap} + * A simple implementation of {@link com.ning.http.client.providers.netty.pool.ChannelPool} based on a {@link java.util.concurrent.ConcurrentHashMap} */ public final class DefaultChannelPool implements ChannelPool { @@ -53,12 +57,12 @@ public final class DefaultChannelPool implements ChannelPool { private final boolean maxIdleTimeDisabled; private final long cleanerPeriod; - public DefaultChannelPool(NettyAsyncHttpProvider provider, Timer hashedWheelTimer) { - this(provider.getConfig().getMaxTotalConnections(),// - provider.getConfig().getMaxConnectionPerHost(),// - provider.getConfig().getIdleConnectionInPoolTimeoutInMs(),// - provider.getConfig().getMaxConnectionLifeTimeInMs(),// - provider.getConfig().isSslConnectionPoolEnabled(),// + public DefaultChannelPool(AsyncHttpClientConfig config, Timer hashedWheelTimer) { + this(config.getMaxTotalConnections(),// + config.getMaxConnectionPerHost(),// + config.getIdleConnectionInPoolTimeoutInMs(),// + config.getMaxConnectionLifeTimeInMs(),// + config.isSslConnectionPoolEnabled(),// hashedWheelTimer); } diff --git a/src/main/java/com/ning/http/client/providers/netty/pool/NonChannelPool.java b/src/main/java/com/ning/http/client/providers/netty/pool/NonChannelPool.java new file mode 100644 index 0000000000..20bca82b9c --- /dev/null +++ b/src/main/java/com/ning/http/client/providers/netty/pool/NonChannelPool.java @@ -0,0 +1,41 @@ +/* + * 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.pool; + +import org.jboss.netty.channel.Channel; + +public class NonChannelPool implements ChannelPool { + + public boolean offer(String uri, Channel connection) { + return false; + } + + public Channel poll(String uri) { + return null; + } + + public boolean removeAll(Channel connection) { + return false; + } + + public boolean canCacheConnection() { + return true; + } + + public void destroy() { + } +} diff --git a/src/test/java/com/ning/http/client/async/netty/NettyConnectionPoolTest.java b/src/test/java/com/ning/http/client/async/netty/NettyConnectionPoolTest.java index 2283c8047c..4df243e7c6 100644 --- a/src/test/java/com/ning/http/client/async/netty/NettyConnectionPoolTest.java +++ b/src/test/java/com/ning/http/client/async/netty/NettyConnectionPoolTest.java @@ -26,8 +26,8 @@ import com.ning.http.client.Response; import com.ning.http.client.async.ConnectionPoolTest; import com.ning.http.client.async.ProviderUtil; -import com.ning.http.client.providers.netty.ChannelPool; import com.ning.http.client.providers.netty.NettyAsyncHttpProviderConfig; +import com.ning.http.client.providers.netty.pool.ChannelPool; import java.net.ConnectException; import java.util.concurrent.TimeUnit; From 1ba64054eec58e2dcdd75eab39baf4edf90b3e4e Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 15 Jul 2014 18:10:28 +0200 Subject: [PATCH 395/701] Introduce ChannelManager --- .../netty/NettyAsyncHttpProvider.java | 28 ++++++---------- .../providers/netty/pool/ChannelManager.java | 33 +++++++++++++++++++ 2 files changed, 43 insertions(+), 18 deletions(-) create mode 100644 src/main/java/com/ning/http/client/providers/netty/pool/ChannelManager.java 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 5691551f4d..e1231b6107 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 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.pool.ChannelManager; import com.ning.http.client.providers.netty.pool.ChannelPool; import com.ning.http.client.providers.netty.pool.DefaultChannelPool; import com.ning.http.client.providers.netty.pool.NonChannelPool; @@ -178,7 +179,7 @@ public boolean remove(Object o) { return removed; } }; - private final ChannelPool channelPool; + private final ChannelManager channelManager; // FIXME should be the pool responsibility private Semaphore freeConnections = null; private final NettyAsyncHttpProviderConfig providerConfig; @@ -246,7 +247,7 @@ public NettyAsyncHttpProvider(AsyncHttpClientConfig config) { } else if (cp == null) { cp = new NonChannelPool(); } - this.channelPool = cp; + this.channelManager = new ChannelManager(cp); if (config.getMaxTotalConnections() != -1) { trackConnections = true; @@ -261,15 +262,6 @@ private Timer newNettyTimer() { timer.start(); return timer; } - - @Override - public String toString() { - int availablePermits = freeConnections != null ? freeConnections.availablePermits() : 0; - return String.format("NettyAsyncHttpProvider:\n\t- maxConnections: %d\n\t- openChannels: %s\n\t- connectionPools: %s",// - config.getMaxTotalConnections() - availablePermits,// - openChannels.toString(),// - channelPool.toString()); - } void configureNetty() { @@ -354,7 +346,7 @@ public ChannelPipeline getPipeline() throws Exception { } private Channel lookupInCache(UriComponents uri, ProxyServer proxy, ConnectionPoolKeyStrategy strategy) { - final Channel channel = channelPool.poll(getPoolKey(uri, proxy, strategy)); + final Channel channel = channelManager.poll(getPoolKey(uri, proxy, strategy)); if (channel != null) { LOGGER.debug("Using cached Channel {}\n for uri {}\n", channel, uri); @@ -801,7 +793,7 @@ private static HttpRequest construct(AsyncHttpClientConfig config, Request reque public void close() { if (isClose.compareAndSet(false, true)) { try { - channelPool.destroy(); + channelManager.destroy(); openChannels.close(); for (Channel channel : openChannels) { @@ -946,7 +938,7 @@ private ListenableFuture doConnect(final Request request, final AsyncHand // Do not throw an exception when we need an extra connection for a redirect. if (!reclaimCache) { - if (!channelPool.canCacheConnection()) { + if (!channelManager.canCacheConnection()) { IOException ex = new IOException(String.format("Too many connections %s", config.getMaxTotalConnections())); try { asyncHandler.onThrowable(ex); @@ -1021,7 +1013,7 @@ private ListenableFuture doConnect(final Request request, final AsyncHand } private void closeChannel(final ChannelHandlerContext ctx) { - channelPool.removeAll(ctx.getChannel()); + channelManager.removeAll(ctx.getChannel()); finishChannel(ctx); } @@ -1276,7 +1268,7 @@ public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws return; } - channelPool.removeAll(ctx.getChannel()); + channelManager.removeAll(ctx.getChannel()); try { super.channelClosed(ctx, e); } catch (Exception ex) { @@ -1325,7 +1317,7 @@ protected boolean remotelyClosed(Channel channel, NettyResponseFuture future) return true; } - channelPool.removeAll(channel); + channelManager.removeAll(channel); if (future == null) { Object attachment = Channels.getAttachment(channel); @@ -1823,7 +1815,7 @@ private boolean exitAfterHandlingRedirect(ChannelHandlerContext ctx, NettyRespon private final boolean tryToOfferChannelToPool(ChannelHandlerContext ctx, boolean keepAlive, String poolKey) { Channel channel = ctx.getChannel(); - if (keepAlive && channel.isReadable() && channelPool.offer(poolKey, channel)) { + if (keepAlive && channel.isReadable() && channelManager.offer(poolKey, channel)) { LOGGER.debug("Adding key: {} for channel {}", poolKey, channel); Channels.setDiscard(ctx); return true; diff --git a/src/main/java/com/ning/http/client/providers/netty/pool/ChannelManager.java b/src/main/java/com/ning/http/client/providers/netty/pool/ChannelManager.java new file mode 100644 index 0000000000..a2a167c408 --- /dev/null +++ b/src/main/java/com/ning/http/client/providers/netty/pool/ChannelManager.java @@ -0,0 +1,33 @@ +package com.ning.http.client.providers.netty.pool; + +import org.jboss.netty.channel.Channel; + +public class ChannelManager { + + private final ChannelPool channelPool; + + public ChannelManager(ChannelPool channelPool) { + this.channelPool = channelPool; + } + + public boolean offer(String uri, Channel connection) { + return channelPool.offer(uri, connection); + } + + public Channel poll(String uri) { + return channelPool.poll(uri); + } + + public boolean removeAll(Channel connection) { + return channelPool.removeAll(connection); + } + + public boolean canCacheConnection() { + return channelPool.canCacheConnection(); + } + + public void destroy() { + channelPool.destroy(); + ; + } +} From 80ee0c302547dbb81da89616d7d5bb683dac2f60 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 15 Jul 2014 18:26:45 +0200 Subject: [PATCH 396/701] Move limits to ChannelManager --- .../netty/NettyAsyncHttpProvider.java | 75 ++++--------------- .../providers/netty/pool/ChannelManager.java | 71 +++++++++++++++++- .../ning/http/client/uri/UriComponents.java | 3 +- 3 files changed, 84 insertions(+), 65 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 e1231b6107..8a43980015 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 @@ -40,7 +40,6 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.RejectedExecutionException; -import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; @@ -61,7 +60,6 @@ import org.jboss.netty.channel.FileRegion; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelUpstreamHandler; -import org.jboss.netty.channel.group.ChannelGroup; import org.jboss.netty.channel.socket.ClientSocketChannelFactory; import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory; import org.jboss.netty.handler.codec.PrematureChannelClosureException; @@ -169,21 +167,8 @@ public class NettyAsyncHttpProvider extends SimpleChannelUpstreamHandler impleme private final ClientSocketChannelFactory socketChannelFactory; private final boolean allowReleaseSocketChannelFactory; - private final ChannelGroup openChannels = new CleanupChannelGroup("asyncHttpClient") { - @Override - public boolean remove(Object o) { - boolean removed = super.remove(o); - if (trackConnections && removed) { - freeConnections.release(); - } - return removed; - } - }; private final ChannelManager channelManager; - // FIXME should be the pool responsibility - private Semaphore freeConnections = null; private final NettyAsyncHttpProviderConfig providerConfig; - private final boolean trackConnections; private final boolean disableZeroCopy; private static final NTLMEngine ntlmEngine = new NTLMEngine(); private static SpnegoEngine spnegoEngine = null; @@ -247,14 +232,7 @@ public NettyAsyncHttpProvider(AsyncHttpClientConfig config) { } else if (cp == null) { cp = new NonChannelPool(); } - this.channelManager = new ChannelManager(cp); - - if (config.getMaxTotalConnections() != -1) { - trackConnections = true; - freeConnections = new Semaphore(config.getMaxTotalConnections()); - } else { - trackConnections = false; - } + this.channelManager = new ChannelManager(config, cp); } private Timer newNettyTimer() { @@ -794,16 +772,6 @@ public void close() { if (isClose.compareAndSet(false, true)) { try { channelManager.destroy(); - openChannels.close(); - - for (Channel channel : openChannels) { - ChannelHandlerContext ctx = channel.getPipeline().getContext(NettyAsyncHttpProvider.class); - Object attachment = Channels.getAttachment(ctx); - if (attachment instanceof NettyResponseFuture) { - NettyResponseFuture future = (NettyResponseFuture) attachment; - future.cancelTimeouts(); - } - } config.executorService().shutdown(); if (allowReleaseSocketChannelFactory) { @@ -938,29 +906,17 @@ private ListenableFuture doConnect(final Request request, final AsyncHand // Do not throw an exception when we need an extra connection for a redirect. if (!reclaimCache) { - if (!channelManager.canCacheConnection()) { + if (channelManager.canCacheConnection()) { + acquiredConnection = true; + } else { IOException ex = new IOException(String.format("Too many connections %s", config.getMaxTotalConnections())); try { asyncHandler.onThrowable(ex); - } catch (Throwable t) { - LOGGER.warn("!connectionsPool.canCacheConnection()", t); + } catch (Exception e) { + LOGGER.warn("asyncHandler.onThrowable crashed", e); } throw ex; } - - if (trackConnections) { - if (!freeConnections.tryAcquire()) { - IOException ex = new IOException(String.format("Too many connections %s", config.getMaxTotalConnections())); - try { - asyncHandler.onThrowable(ex); - } catch (Throwable t) { - LOGGER.warn("!connectionsPool.canCacheConnection()", t); - } - throw ex; - } else { - acquiredConnection = true; - } - } } NettyConnectListener connectListener = new NettyConnectListener.Builder(config, request, asyncHandler, f, this, bufferedBytes).build(uri); @@ -990,9 +946,8 @@ private ListenableFuture doConnect(final Request request, final AsyncHand } } catch (Throwable t) { - if (acquiredConnection) { - freeConnections.release(); - } + if (acquiredConnection) + channelManager.releaseFreeConnection(); abort(connectListener.future(), t.getCause() == null ? t : t.getCause()); return connectListener.future(); } @@ -1001,13 +956,12 @@ private ListenableFuture doConnect(final Request request, final AsyncHand LOGGER.debug("\nNon cached request \n{}\n\nusing Channel \n{}\n", connectListener.future().getNettyRequest(), channelFuture.getChannel()); + // FIXME this should be done in the listener + properly handler connection failures if (!connectListener.future().isCancelled() || !connectListener.future().isDone()) { - openChannels.add(channelFuture.getChannel()); + channelManager.registerOpenChannel(channelFuture.getChannel()); connectListener.future().attachChannel(channelFuture.getChannel(), false); - } else { - if (acquiredConnection) { - freeConnections.release(); - } + } else if (acquiredConnection) { + channelManager.releaseFreeConnection(); } return connectListener.future(); } @@ -1031,7 +985,7 @@ private void finishChannel(final ChannelHandlerContext ctx) { } catch (Throwable t) { LOGGER.debug("Error closing a connection", t); } - openChannels.remove(channel); + channelManager.unregisterOpenChannel(channel); } } @@ -1227,9 +1181,8 @@ private void nextRequest(final Request request, final NettyResponseFuture fut public void abort(NettyResponseFuture future, Throwable t) { Channel channel = future.channel(); - if (channel != null && openChannels.contains(channel)) { + if (channel != null && channelManager.unregisterOpenChannel(channel)) { closeChannel(channel.getPipeline().getContext(NettyAsyncHttpProvider.class)); - openChannels.remove(channel); } if (!future.isCancelled() && !future.isDone()) { diff --git a/src/main/java/com/ning/http/client/providers/netty/pool/ChannelManager.java b/src/main/java/com/ning/http/client/providers/netty/pool/ChannelManager.java index a2a167c408..c51d6ce0b4 100644 --- a/src/main/java/com/ning/http/client/providers/netty/pool/ChannelManager.java +++ b/src/main/java/com/ning/http/client/providers/netty/pool/ChannelManager.java @@ -1,12 +1,56 @@ +/* + * Copyright (c) 2014 AsyncHttpClient Project. 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.providers.netty.pool; import org.jboss.netty.channel.Channel; +import org.jboss.netty.channel.ChannelHandlerContext; +import org.jboss.netty.channel.group.ChannelGroup; + +import com.ning.http.client.AsyncHttpClientConfig; +import com.ning.http.client.providers.netty.Channels; +import com.ning.http.client.providers.netty.CleanupChannelGroup; +import com.ning.http.client.providers.netty.NettyAsyncHttpProvider; +import com.ning.http.client.providers.netty.NettyResponseFuture; + +import java.util.concurrent.Semaphore; public class ChannelManager { private final ChannelPool channelPool; + private final Semaphore freeConnections; + private final boolean trackConnections; + + private final ChannelGroup openChannels; - public ChannelManager(ChannelPool channelPool) { + public ChannelManager(AsyncHttpClientConfig config, ChannelPool channelPool) { + if (config.getMaxTotalConnections() != -1) { + trackConnections = true; + openChannels = new CleanupChannelGroup("asyncHttpClient") { + @Override + public boolean remove(Object o) { + boolean removed = super.remove(o); + if (removed) + freeConnections.release(); + return removed; + } + }; + freeConnections = new Semaphore(config.getMaxTotalConnections()); + } else { + trackConnections = false; + openChannels = new CleanupChannelGroup("asyncHttpClient"); + freeConnections = null; + } this.channelPool = channelPool; } @@ -23,11 +67,32 @@ public boolean removeAll(Channel connection) { } public boolean canCacheConnection() { - return channelPool.canCacheConnection(); + return channelPool.canCacheConnection() && (!trackConnections || freeConnections.tryAcquire()); } public void destroy() { channelPool.destroy(); - ; + openChannels.close(); + for (Channel channel : openChannels) { + ChannelHandlerContext ctx = channel.getPipeline().getContext(NettyAsyncHttpProvider.class); + Object attachment = Channels.getAttachment(ctx); + if (attachment instanceof NettyResponseFuture) { + NettyResponseFuture future = (NettyResponseFuture) attachment; + future.cancelTimeouts(); + } + } + } + + // temp + public void releaseFreeConnection() { + freeConnections.release(); + } + + public void registerOpenChannel(Channel channel) { + openChannels.add(channel); + } + + public boolean unregisterOpenChannel(Channel channel) { + return openChannels.remove(channel); } } diff --git a/src/main/java/com/ning/http/client/uri/UriComponents.java b/src/main/java/com/ning/http/client/uri/UriComponents.java index fff21ac7ab..84202d6efd 100644 --- a/src/main/java/com/ning/http/client/uri/UriComponents.java +++ b/src/main/java/com/ning/http/client/uri/UriComponents.java @@ -3,7 +3,8 @@ * * 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. + * 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 From c211bcb1680679acf5f656b4d140283e040554b3 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 15 Jul 2014 18:29:50 +0200 Subject: [PATCH 397/701] remove dead code --- .../providers/netty/NettyConnectListener.java | 34 ++++++++----------- 1 file changed, 14 insertions(+), 20 deletions(-) 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 070bbe5981..8751aad1c2 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 @@ -50,8 +50,7 @@ final class NettyConnectListener implements ChannelFutureListener { private final NettyResponseFuture future; private final HttpRequest nettyRequest; - private NettyConnectListener(AsyncHttpClientConfig config, - NettyResponseFuture future) { + private NettyConnectListener(AsyncHttpClientConfig config, NettyResponseFuture future) { this.config = config; this.future = future; this.nettyRequest = future.getNettyRequest(); @@ -66,7 +65,7 @@ public final void operationComplete(ChannelFuture f) throws Exception { if (f.isSuccess()) { channel.getPipeline().getContext(NettyAsyncHttpProvider.class).setAttachment(future); final SslHandler sslHandler = (SslHandler) channel.getPipeline().get(NettyAsyncHttpProvider.SSL_HANDLER); - + final HostnameVerifier hostnameVerifier = config.getHostnameVerifier(); if (hostnameVerifier != null && sslHandler != null) { final String host = future.getURI().getHost(); @@ -100,9 +99,10 @@ public void operationComplete(ChannelFuture handshakeFuture) throws Exception { boolean canRetry = future.canRetry(); LOGGER.debug("Trying to recover a dead cached channel {} with a retry value of {} ", f.getChannel(), canRetry); - if (canRetry && cause != null && (NettyAsyncHttpProvider.abortOnDisconnectException(cause) - || cause instanceof ClosedChannelException - || future.getState() != NettyResponseFuture.STATE.NEW)) { + if (canRetry + && cause != null + && (NettyAsyncHttpProvider.abortOnDisconnectException(cause) || cause instanceof ClosedChannelException || future + .getState() != NettyResponseFuture.STATE.NEW)) { LOGGER.debug("Retrying {} ", nettyRequest); if (future.provider().remotelyClosed(channel, future)) { @@ -113,7 +113,8 @@ public void operationComplete(ChannelFuture handshakeFuture) throws Exception { LOGGER.debug("Failed to recover from exception: {} with channel {}", cause, f.getChannel()); boolean printCause = f.getCause() != null && cause.getMessage() != null; - ConnectException e = new ConnectException(printCause ? cause.getMessage() + " to " + future.getURI().toString() : future.getURI().toString()); + ConnectException e = new ConnectException(printCause ? cause.getMessage() + " to " + future.getURI().toString() : future + .getURI().toString()); if (cause != null) { e.initCause(cause); } @@ -130,19 +131,12 @@ public static class Builder { private final NettyAsyncHttpProvider provider; private final ChannelBuffer buffer; - public Builder(AsyncHttpClientConfig config, Request request, AsyncHandler asyncHandler, - NettyAsyncHttpProvider provider, ChannelBuffer buffer) { - - this.config = config; - this.request = request; - this.asyncHandler = asyncHandler; - this.future = null; - this.provider = provider; - this.buffer = buffer; - } - - public Builder(AsyncHttpClientConfig config, Request request, AsyncHandler asyncHandler, - NettyResponseFuture future, NettyAsyncHttpProvider provider, ChannelBuffer buffer) { + public Builder(AsyncHttpClientConfig config,// + Request request,// + AsyncHandler asyncHandler,// + NettyResponseFuture future,// + NettyAsyncHttpProvider provider,// + ChannelBuffer buffer) { this.config = config; this.request = request; From d5b3145bcb749c309badcc62a408adde083fbd81 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 15 Jul 2014 18:32:34 +0200 Subject: [PATCH 398/701] Don't store the provider in the future!!! --- .../client/providers/netty/NettyConnectListener.java | 12 +++++++----- .../client/providers/netty/NettyResponseFuture.java | 6 ------ 2 files changed, 7 insertions(+), 11 deletions(-) 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 8751aad1c2..02ba9a3e09 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 @@ -49,11 +49,13 @@ final class NettyConnectListener implements ChannelFutureListener { private final AsyncHttpClientConfig config; private final NettyResponseFuture future; private final HttpRequest nettyRequest; + private final NettyAsyncHttpProvider provider; - private NettyConnectListener(AsyncHttpClientConfig config, NettyResponseFuture future) { + private NettyConnectListener(AsyncHttpClientConfig config, NettyResponseFuture future, NettyAsyncHttpProvider provider) { this.config = config; this.future = future; this.nettyRequest = future.getNettyRequest(); + this.provider = provider; } public NettyResponseFuture future() { @@ -85,13 +87,13 @@ public void operationComplete(ChannelFuture handshakeFuture) throws Exception { future.abort(exception); throw exception; } else { - future.provider().writeRequest(channel, config, future); + provider.writeRequest(channel, config, future); } } } }); } else { - future.provider().writeRequest(f.getChannel(), config, future); + provider.writeRequest(f.getChannel(), config, future); } } else { @@ -105,7 +107,7 @@ public void operationComplete(ChannelFuture handshakeFuture) throws Exception { .getState() != NettyResponseFuture.STATE.NEW)) { LOGGER.debug("Retrying {} ", nettyRequest); - if (future.provider().remotelyClosed(channel, future)) { + if (provider.remotelyClosed(channel, future)) { return; } } @@ -155,7 +157,7 @@ public NettyConnectListener build(final UriComponents uri) throws IOException future.setNettyRequest(nettyRequest); future.setRequest(request); } - return new NettyConnectListener(config, future); + return new NettyConnectListener(config, future, provider); } } } 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 92e1a9d41d..6178302dac 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 @@ -78,7 +78,6 @@ enum STATE { private final AtomicBoolean statusReceived = new AtomicBoolean(false); 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); private Channel channel; @@ -108,7 +107,6 @@ public NettyResponseFuture(UriComponents uri,// this.request = request; this.nettyRequest = nettyRequest; this.uri = uri; - this.asyncHttpProvider = asyncHttpProvider; this.connectionPoolKeyStrategy = connectionPoolKeyStrategy; this.proxyServer = proxyServer; @@ -440,10 +438,6 @@ public boolean getAndSetWriteBody(boolean writeBody) { return b; } - protected NettyAsyncHttpProvider provider() { - return asyncHttpProvider; - } - protected void attachChannel(Channel channel) { this.channel = channel; } From 7de899c3690381d2593451e89c408a0b12c24067 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 15 Jul 2014 18:44:09 +0200 Subject: [PATCH 399/701] Registering after bootstrap.connect felt racy, moving to ConnectListener --- .../netty/NettyAsyncHttpProvider.java | 16 +---- .../providers/netty/NettyConnectListener.java | 58 ++++++++++++++----- 2 files changed, 47 insertions(+), 27 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 8a43980015..8d378efe6d 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 @@ -919,7 +919,7 @@ private ListenableFuture doConnect(final Request request, final AsyncHand } } - NettyConnectListener connectListener = new NettyConnectListener.Builder(config, request, asyncHandler, f, this, bufferedBytes).build(uri); + NettyConnectListener connectListener = new NettyConnectListener.Builder(config, request, asyncHandler, f, this, bufferedBytes, channelManager, acquiredConnection).build(uri); if (useSSl) constructSSLPipeline(connectListener); @@ -945,24 +945,14 @@ private ListenableFuture doConnect(final Request request, final AsyncHand channelFuture = bootstrap.connect(remoteAddress); } + channelFuture.addListener(connectListener); + } catch (Throwable t) { if (acquiredConnection) channelManager.releaseFreeConnection(); abort(connectListener.future(), t.getCause() == null ? t : t.getCause()); - return connectListener.future(); } - channelFuture.addListener(connectListener); - - LOGGER.debug("\nNon cached request \n{}\n\nusing Channel \n{}\n", connectListener.future().getNettyRequest(), channelFuture.getChannel()); - - // FIXME this should be done in the listener + properly handler connection failures - if (!connectListener.future().isCancelled() || !connectListener.future().isDone()) { - channelManager.registerOpenChannel(channelFuture.getChannel()); - connectListener.future().attachChannel(channelFuture.getChannel(), false); - } else if (acquiredConnection) { - channelManager.releaseFreeConnection(); - } return connectListener.future(); } 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 02ba9a3e09..7e3c324892 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 @@ -16,14 +16,6 @@ */ package com.ning.http.client.providers.netty; -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.client.uri.UriComponents; -import com.ning.http.util.Base64; -import com.ning.http.util.ProxyUtils; - import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFuture; @@ -33,6 +25,15 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +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.client.providers.netty.pool.ChannelManager; +import com.ning.http.client.uri.UriComponents; +import com.ning.http.util.Base64; +import com.ning.http.util.ProxyUtils; + import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLSession; @@ -50,18 +51,41 @@ final class NettyConnectListener implements ChannelFutureListener { private final NettyResponseFuture future; private final HttpRequest nettyRequest; private final NettyAsyncHttpProvider provider; - - private NettyConnectListener(AsyncHttpClientConfig config, NettyResponseFuture future, NettyAsyncHttpProvider provider) { + private final ChannelManager channelManager; + private final boolean acquiredConnection; + + private NettyConnectListener(AsyncHttpClientConfig config,// + NettyResponseFuture future,// + NettyAsyncHttpProvider provider,// + ChannelManager channelManager,// + boolean acquiredConnection) { this.config = config; this.future = future; this.nettyRequest = future.getNettyRequest(); this.provider = provider; + this.channelManager = channelManager; + this.acquiredConnection = acquiredConnection; } public NettyResponseFuture future() { return future; } + private void writeRequest(Channel channel) { + + LOGGER.debug("\nNon cached request \n{}\n\nusing Channel \n{}\n", future.getNettyRequest(), channel); + + // FIXME this should be done in the listener + properly handler connection failures + if (!future.isCancelled() || !future.isDone()) { + channelManager.registerOpenChannel(channel); + future.attachChannel(channel, false); + } else if (acquiredConnection) { + channelManager.releaseFreeConnection(); + } + + provider.writeRequest(channel, config, future); + } + public final void operationComplete(ChannelFuture f) throws Exception { Channel channel = f.getChannel(); if (f.isSuccess()) { @@ -87,13 +111,13 @@ public void operationComplete(ChannelFuture handshakeFuture) throws Exception { future.abort(exception); throw exception; } else { - provider.writeRequest(channel, config, future); + writeRequest(channel); } } } }); } else { - provider.writeRequest(f.getChannel(), config, future); + writeRequest(f.getChannel()); } } else { @@ -132,13 +156,17 @@ public static class Builder { private NettyResponseFuture future; private final NettyAsyncHttpProvider provider; private final ChannelBuffer buffer; + private final ChannelManager channelManager; + private final boolean acquiredConnection; public Builder(AsyncHttpClientConfig config,// Request request,// AsyncHandler asyncHandler,// NettyResponseFuture future,// NettyAsyncHttpProvider provider,// - ChannelBuffer buffer) { + ChannelBuffer buffer,// + ChannelManager channelManager,// + boolean acquiredConnection) { this.config = config; this.request = request; @@ -146,6 +174,8 @@ public Builder(AsyncHttpClientConfig config,// this.future = future; this.provider = provider; this.buffer = buffer; + this.channelManager = channelManager; + this.acquiredConnection = acquiredConnection; } public NettyConnectListener build(final UriComponents uri) throws IOException { @@ -157,7 +187,7 @@ public NettyConnectListener build(final UriComponents uri) throws IOException future.setNettyRequest(nettyRequest); future.setRequest(request); } - return new NettyConnectListener(config, future, provider); + return new NettyConnectListener(config, future, provider, channelManager, acquiredConnection); } } } From a6a583c89e9ed90ea51d13b006345bdc5b8f8f26 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 15 Jul 2014 18:46:08 +0200 Subject: [PATCH 400/701] minor clean up --- .../http/client/providers/netty/NettyConnectListener.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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 7e3c324892..6cedbc8a38 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 @@ -106,12 +106,12 @@ public void operationComplete(ChannelFuture handshakeFuture) throws Exception { if (LOGGER.isDebugEnabled()) LOGGER.debug("onFutureSuccess: session = {}, id = {}, isValid = {}, host = {}", session.toString(), Base64.encode(session.getId()), session.isValid(), host); - if (!hostnameVerifier.verify(host, session)) { + if (hostnameVerifier.verify(host, session)) { + writeRequest(channel); + } else { ConnectException exception = new ConnectException("HostnameVerifier exception"); future.abort(exception); throw exception; - } else { - writeRequest(channel); } } } From c3248bde49ac7e7d7cf120a2fe6305a621d0e21a Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 15 Jul 2014 22:39:04 +0200 Subject: [PATCH 401/701] Fix: release on connect failure --- .../providers/netty/NettyConnectListener.java | 17 +++++++++++------ .../providers/netty/pool/ChannelManager.java | 3 ++- 2 files changed, 13 insertions(+), 7 deletions(-) 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 6cedbc8a38..c0bc2ba63c 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 @@ -71,19 +71,23 @@ public NettyResponseFuture future() { return future; } + private void release() { + if (acquiredConnection) + channelManager.releaseFreeConnection(); + } + private void writeRequest(Channel channel) { LOGGER.debug("\nNon cached request \n{}\n\nusing Channel \n{}\n", future.getNettyRequest(), channel); - // FIXME this should be done in the listener + properly handler connection failures - if (!future.isCancelled() || !future.isDone()) { + if (!future.isDone()) { channelManager.registerOpenChannel(channel); future.attachChannel(channel, false); - } else if (acquiredConnection) { - channelManager.releaseFreeConnection(); - } + provider.writeRequest(channel, config, future); - provider.writeRequest(channel, config, future); + } else { + release(); + } } public final void operationComplete(ChannelFuture f) throws Exception { @@ -121,6 +125,7 @@ public void operationComplete(ChannelFuture handshakeFuture) throws Exception { } } else { + release(); Throwable cause = f.getCause(); boolean canRetry = future.canRetry(); diff --git a/src/main/java/com/ning/http/client/providers/netty/pool/ChannelManager.java b/src/main/java/com/ning/http/client/providers/netty/pool/ChannelManager.java index c51d6ce0b4..1752c22ea6 100644 --- a/src/main/java/com/ning/http/client/providers/netty/pool/ChannelManager.java +++ b/src/main/java/com/ning/http/client/providers/netty/pool/ChannelManager.java @@ -85,7 +85,8 @@ public void destroy() { // temp public void releaseFreeConnection() { - freeConnections.release(); + if (trackConnections) + freeConnections.release(); } public void registerOpenChannel(Channel channel) { From 45554ba0ef2d889c686b1e32d0675cc66965eaed Mon Sep 17 00:00:00 2001 From: oleksiys Date: Tue, 15 Jul 2014 22:53:21 -0700 Subject: [PATCH 402/701] [1.9.x] fix issue #608 https://github.com/AsyncHttpClient/async-http-client/issues/608 "Grizzly provider can't deal with wss + proxy" --- .../providers/grizzly/GrizzlyAsyncHttpProvider.java | 10 ++++++---- .../websocket/grizzly/GrizzlyProxyTunnellingTest.java | 5 ----- 2 files changed, 6 insertions(+), 9 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 3c610ec43e..7d16b44672 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 @@ -1010,11 +1010,13 @@ private boolean isWSRequest(final UriComponents requestUri) { private void convertToUpgradeRequest(final HttpTransactionContext ctx) { - UriComponents originalUri = ctx.requestUri; - String newScheme = originalUri.getScheme().equalsIgnoreCase("https") ? "wss" : "ws"; + final UriComponents requestUri = ctx.requestUri; - ctx.wsRequestURI = originalUri; - ctx.requestUri = originalUri.withNewScheme(newScheme); + ctx.wsRequestURI = requestUri; + ctx.requestUri = requestUri.withNewScheme( + "ws".equals(requestUri.getScheme()) + ? "http" + : "https"); } private void addHeaders(final Request request, diff --git a/src/test/java/com/ning/http/client/websocket/grizzly/GrizzlyProxyTunnellingTest.java b/src/test/java/com/ning/http/client/websocket/grizzly/GrizzlyProxyTunnellingTest.java index cb6251e6b9..d76c131944 100644 --- a/src/test/java/com/ning/http/client/websocket/grizzly/GrizzlyProxyTunnellingTest.java +++ b/src/test/java/com/ning/http/client/websocket/grizzly/GrizzlyProxyTunnellingTest.java @@ -26,9 +26,4 @@ public class GrizzlyProxyTunnellingTest extends ProxyTunnellingTest { public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { return ProviderUtil.grizzlyProvider(config); } - - @Test(timeOut = 60000, enabled = false) - public void echoText() throws Exception { - // FIXME - } } From 68cf0904229dc5429114363f51a15bd3543f4976 Mon Sep 17 00:00:00 2001 From: oleksiys Date: Tue, 15 Jul 2014 22:55:29 -0700 Subject: [PATCH 403/701] [1.9.x] + minor cleanup --- pom.xml | 2 +- .../http/client/providers/grizzly/HostnameVerifierListener.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 201d84a35f..5a3a81753d 100644 --- a/pom.xml +++ b/pom.xml @@ -591,7 +591,7 @@ com/ning/http/client/providers/grizzly/*.java com/ning/http/client/async/grizzly/*.java com.ning.http.client.providers.grizzly - 2.3.14 + 2.3.16 1.5 1.5 2.12 diff --git a/src/main/java/com/ning/http/client/providers/grizzly/HostnameVerifierListener.java b/src/main/java/com/ning/http/client/providers/grizzly/HostnameVerifierListener.java index 6bcc889a32..448631709b 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/HostnameVerifierListener.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/HostnameVerifierListener.java @@ -124,7 +124,7 @@ public void verify() { } if (!verifier.verify(host, session)) { - connection.close(); // XXX what's the correct way to kill a connection? + connection.terminateSilently(); IOException e = new ConnectException("Host name verification failed for host " + host); delegate.failed(e); } From 45435f6844867b381620842875a0047673558852 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 15 Jul 2014 22:39:28 +0200 Subject: [PATCH 404/701] Disable GrizzlyBodyDeferringAsyncHandlerTest for Grizzly, see #625 --- .../GrizzlyBodyDeferringAsyncHandlerTest.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) 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 5b0810feea..1945a7bda7 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 @@ -13,15 +13,34 @@ 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.BodyDeferringAsyncHandlerTest; import com.ning.http.client.async.ProviderUtil; +import java.io.IOException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeoutException; + public class GrizzlyBodyDeferringAsyncHandlerTest extends BodyDeferringAsyncHandlerTest { @Override public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { return ProviderUtil.grizzlyProvider(config); } + + @Test(enabled = false) + public void deferredInputStreamTrick() throws IOException, ExecutionException, TimeoutException, InterruptedException { + } + + @Test(enabled = false) + public void deferredSimple() throws IOException, ExecutionException, TimeoutException, InterruptedException { + } + + @Test(enabled = false) + public void deferredInputStreamTrickWithFailure() throws IOException, ExecutionException, TimeoutException, InterruptedException { + } + } From c8d196c1483ddf64247eb3d1d873be3054b27734 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 15 Jul 2014 22:53:19 +0200 Subject: [PATCH 405/701] Rename methods --- .../netty/NettyAsyncHttpProvider.java | 41 ++++--------------- .../providers/netty/NettyConnectListener.java | 8 ++-- .../providers/netty/pool/ChannelManager.java | 35 ++++++++++++---- 3 files changed, 39 insertions(+), 45 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 8d378efe6d..a75c36212c 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 @@ -906,7 +906,7 @@ private ListenableFuture doConnect(final Request request, final AsyncHand // Do not throw an exception when we need an extra connection for a redirect. if (!reclaimCache) { - if (channelManager.canCacheConnection()) { + if (channelManager.preemptChannel()) { acquiredConnection = true; } else { IOException ex = new IOException(String.format("Too many connections %s", config.getMaxTotalConnections())); @@ -949,36 +949,13 @@ private ListenableFuture doConnect(final Request request, final AsyncHand } catch (Throwable t) { if (acquiredConnection) - channelManager.releaseFreeConnection(); + channelManager.abortChannelPreemption(); abort(connectListener.future(), t.getCause() == null ? t : t.getCause()); } return connectListener.future(); } - private void closeChannel(final ChannelHandlerContext ctx) { - channelManager.removeAll(ctx.getChannel()); - finishChannel(ctx); - } - - private void finishChannel(final ChannelHandlerContext ctx) { - Channels.setDiscard(ctx); - - Channel channel = ctx.getChannel(); - - // The channel may have already been removed if a timeout occurred, and this method may be called just after. - if (channel != null) { - // FIXME can the context channel really be null? - LOGGER.debug("Closing Channel {} ", channel); - try { - channel.close(); - } catch (Throwable t) { - LOGGER.debug("Error closing a connection", t); - } - channelManager.unregisterOpenChannel(channel); - } - } - @Override public void messageReceived(final ChannelHandlerContext ctx, MessageEvent e) throws Exception { @@ -1171,9 +1148,7 @@ private void nextRequest(final Request request, final NettyResponseFuture fut public void abort(NettyResponseFuture future, Throwable t) { Channel channel = future.channel(); - if (channel != null && channelManager.unregisterOpenChannel(channel)) { - closeChannel(channel.getPipeline().getContext(NettyAsyncHttpProvider.class)); - } + channelManager.closeChannel(channel.getPipeline().getContext(NettyAsyncHttpProvider.class)); if (!future.isCancelled() && !future.isDone()) { LOGGER.debug("Aborting Future {}\n", future); @@ -1249,7 +1224,7 @@ public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws abort(future, REMOTELY_CLOSED_EXCEPTION); } } else { - closeChannel(ctx); + channelManager.closeChannel(ctx); } } } @@ -1301,7 +1276,7 @@ private void markAsDone(final NettyResponseFuture future, final ChannelHandle } if (!future.getKeepAlive() || !ctx.getChannel().isReadable()) { - closeChannel(ctx); + channelManager.closeChannel(ctx); } } @@ -1405,7 +1380,7 @@ public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Protocol p = (ctx.getPipeline().get(HttpClientCodec.class) != null ? httpProtocol : webSocketProtocol); p.onError(ctx, e); - closeChannel(ctx); + channelManager.closeChannel(ctx); ctx.sendUpstream(e); } @@ -1764,7 +1739,7 @@ private final boolean tryToOfferChannelToPool(ChannelHandlerContext ctx, boolean return true; } else { // not offered - finishChannel(ctx); + channelManager.closeChannel(ctx); return false; } } @@ -2062,7 +2037,7 @@ public void handle(final ChannelHandlerContext ctx, final MessageEvent e, final // The connect timeout occurred. if (future.isCancelled() || future.isDone()) { - finishChannel(ctx); + channelManager.closeChannel(ctx); 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 c0bc2ba63c..1a948061c5 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 @@ -71,9 +71,9 @@ public NettyResponseFuture future() { return future; } - private void release() { + private void abortChannelPreemption() { if (acquiredConnection) - channelManager.releaseFreeConnection(); + channelManager.abortChannelPreemption(); } private void writeRequest(Channel channel) { @@ -86,7 +86,7 @@ private void writeRequest(Channel channel) { provider.writeRequest(channel, config, future); } else { - release(); + abortChannelPreemption(); } } @@ -125,7 +125,7 @@ public void operationComplete(ChannelFuture handshakeFuture) throws Exception { } } else { - release(); + abortChannelPreemption(); Throwable cause = f.getCause(); boolean canRetry = future.canRetry(); diff --git a/src/main/java/com/ning/http/client/providers/netty/pool/ChannelManager.java b/src/main/java/com/ning/http/client/providers/netty/pool/ChannelManager.java index 1752c22ea6..3ff0ec7529 100644 --- a/src/main/java/com/ning/http/client/providers/netty/pool/ChannelManager.java +++ b/src/main/java/com/ning/http/client/providers/netty/pool/ChannelManager.java @@ -16,6 +16,8 @@ import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.group.ChannelGroup; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.providers.netty.Channels; @@ -27,6 +29,8 @@ public class ChannelManager { + private static final Logger LOGGER = LoggerFactory.getLogger(ChannelManager.class); + private final ChannelPool channelPool; private final Semaphore freeConnections; private final boolean trackConnections; @@ -66,7 +70,7 @@ public boolean removeAll(Channel connection) { return channelPool.removeAll(connection); } - public boolean canCacheConnection() { + public boolean preemptChannel() { return channelPool.canCacheConnection() && (!trackConnections || freeConnections.tryAcquire()); } @@ -82,18 +86,33 @@ public void destroy() { } } } - + + public void closeChannel(final ChannelHandlerContext ctx) { + removeAll(ctx.getChannel()); + Channels.setDiscard(ctx); + + Channel channel = ctx.getChannel(); + + // The channel may have already been removed if a timeout occurred, and this method may be called just after. + if (channel != null) { + // FIXME can the context channel really be null? + LOGGER.debug("Closing Channel {} ", channel); + try { + channel.close(); + } catch (Throwable t) { + LOGGER.debug("Error closing a connection", t); + } + openChannels.remove(channel); + } + } + // temp - public void releaseFreeConnection() { + public void abortChannelPreemption() { if (trackConnections) freeConnections.release(); } - + public void registerOpenChannel(Channel channel) { openChannels.add(channel); } - - public boolean unregisterOpenChannel(Channel channel) { - return openChannels.remove(channel); - } } From 2843b13f95654c111870969261e375fb1993f69e Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 15 Jul 2014 23:06:35 +0200 Subject: [PATCH 406/701] Remove NettyConnectListener.Builder --- .../netty/NettyAsyncHttpProvider.java | 21 +++++++- .../providers/netty/NettyConnectListener.java | 52 +------------------ 2 files changed, 21 insertions(+), 52 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 a75c36212c..4bae403e41 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 @@ -848,6 +848,24 @@ private NettyResponseFuture buildNettyResponseFutureWithCachedChannel(Req return null; } + private NettyResponseFuture buildConnectListenerFuture(AsyncHttpClientConfig config,// + Request request,// + AsyncHandler asyncHandler,// + NettyResponseFuture future,// + NettyAsyncHttpProvider provider,// + ChannelBuffer buffer,// + UriComponents uri) throws IOException { + ProxyServer proxyServer = ProxyUtils.getProxyServer(config, request); + HttpRequest nettyRequest = NettyAsyncHttpProvider.buildRequest(config, request, uri, true, buffer, proxyServer); + if (future == null) { + return NettyAsyncHttpProvider.newFuture(uri, request, asyncHandler, nettyRequest, config, provider, proxyServer); + } else { + future.setNettyRequest(nettyRequest); + future.setRequest(request); + return future; + } + } + private ListenableFuture doConnect(final Request request, final AsyncHandler asyncHandler, NettyResponseFuture f, boolean useCache, boolean reclaimCache) throws IOException { @@ -919,7 +937,8 @@ private ListenableFuture doConnect(final Request request, final AsyncHand } } - NettyConnectListener connectListener = new NettyConnectListener.Builder(config, request, asyncHandler, f, this, bufferedBytes, channelManager, acquiredConnection).build(uri); + NettyResponseFuture connectListenerFuture = buildConnectListenerFuture(config, request, asyncHandler, f, this, bufferedBytes, uri); + NettyConnectListener connectListener = new NettyConnectListener(config, connectListenerFuture, this, channelManager, acquiredConnection); if (useSSl) constructSSLPipeline(connectListener); 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 1a948061c5..640461453a 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 @@ -16,7 +16,6 @@ */ package com.ning.http.client.providers.netty; -import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelFutureListener; @@ -25,20 +24,14 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -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.client.providers.netty.pool.ChannelManager; -import com.ning.http.client.uri.UriComponents; import com.ning.http.util.Base64; -import com.ning.http.util.ProxyUtils; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLSession; -import java.io.IOException; import java.net.ConnectException; import java.nio.channels.ClosedChannelException; @@ -54,7 +47,7 @@ final class NettyConnectListener implements ChannelFutureListener { private final ChannelManager channelManager; private final boolean acquiredConnection; - private NettyConnectListener(AsyncHttpClientConfig config,// + public NettyConnectListener(AsyncHttpClientConfig config,// NettyResponseFuture future,// NettyAsyncHttpProvider provider,// ChannelManager channelManager,// @@ -152,47 +145,4 @@ public void operationComplete(ChannelFuture handshakeFuture) throws Exception { future.abort(e); } } - - public static class Builder { - private final AsyncHttpClientConfig config; - - private final Request request; - private final AsyncHandler asyncHandler; - private NettyResponseFuture future; - private final NettyAsyncHttpProvider provider; - private final ChannelBuffer buffer; - private final ChannelManager channelManager; - private final boolean acquiredConnection; - - public Builder(AsyncHttpClientConfig config,// - Request request,// - AsyncHandler asyncHandler,// - NettyResponseFuture future,// - NettyAsyncHttpProvider provider,// - ChannelBuffer buffer,// - ChannelManager channelManager,// - boolean acquiredConnection) { - - this.config = config; - this.request = request; - this.asyncHandler = asyncHandler; - this.future = future; - this.provider = provider; - this.buffer = buffer; - this.channelManager = channelManager; - this.acquiredConnection = acquiredConnection; - } - - public NettyConnectListener build(final UriComponents uri) throws IOException { - 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, proxyServer); - } else { - future.setNettyRequest(nettyRequest); - future.setRequest(request); - } - return new NettyConnectListener(config, future, provider, channelManager, acquiredConnection); - } - } } From 684f2398fe5c348b1659a7da299b6d54b09b334d Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 15 Jul 2014 23:12:52 +0200 Subject: [PATCH 407/701] Move tryToOfferChannelToPool to ChannelManager --- .../providers/netty/NettyAsyncHttpProvider.java | 17 ++--------------- .../providers/netty/pool/ChannelManager.java | 13 +++++++++++-- 2 files 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 4bae403e41..4f2bc32a83 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 @@ -1304,7 +1304,7 @@ private void finishUpdate(final NettyResponseFuture future, final ChannelHand if (expectOtherChunks && keepAlive) drainChannel(ctx, future); else - tryToOfferChannelToPool(ctx, keepAlive, getPoolKey(future)); + channelManager.tryToOfferChannelToPool(ctx, keepAlive, getPoolKey(future)); markAsDone(future, ctx); } @@ -1750,24 +1750,11 @@ private boolean exitAfterHandlingRedirect(ChannelHandlerContext ctx, NettyRespon return false; } - private final boolean tryToOfferChannelToPool(ChannelHandlerContext ctx, boolean keepAlive, String poolKey) { - Channel channel = ctx.getChannel(); - if (keepAlive && channel.isReadable() && channelManager.offer(poolKey, channel)) { - LOGGER.debug("Adding key: {} for channel {}", poolKey, channel); - Channels.setDiscard(ctx); - return true; - } else { - // not offered - channelManager.closeChannel(ctx); - return false; - } - } - private final AsyncCallable newDrainCallable(final NettyResponseFuture future, final ChannelHandlerContext ctx, final boolean keepAlive, final String poolKey) { return new AsyncCallable(future) { public Object call() throws Exception { - tryToOfferChannelToPool(ctx, keepAlive, poolKey); + channelManager.tryToOfferChannelToPool(ctx, keepAlive, poolKey); return null; } }; diff --git a/src/main/java/com/ning/http/client/providers/netty/pool/ChannelManager.java b/src/main/java/com/ning/http/client/providers/netty/pool/ChannelManager.java index 3ff0ec7529..247b35b1a3 100644 --- a/src/main/java/com/ning/http/client/providers/netty/pool/ChannelManager.java +++ b/src/main/java/com/ning/http/client/providers/netty/pool/ChannelManager.java @@ -58,8 +58,17 @@ public boolean remove(Object o) { this.channelPool = channelPool; } - public boolean offer(String uri, Channel connection) { - return channelPool.offer(uri, connection); + public final boolean tryToOfferChannelToPool(ChannelHandlerContext ctx, boolean keepAlive, String poolKey) { + Channel channel = ctx.getChannel(); + if (keepAlive && channel.isReadable() && channelPool.offer(poolKey, channel)) { + LOGGER.debug("Adding key: {} for channel {}", poolKey, channel); + Channels.setDiscard(ctx); + return true; + } else { + // not offered + closeChannel(ctx); + return false; + } } public Channel poll(String uri) { From 2cd700d1d643962146fee6a3b6f7d667170c6c1e Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 15 Jul 2014 23:19:49 +0200 Subject: [PATCH 408/701] Invert NettyResponseFuture.cannotBeReplay into canBeReplay --- .../netty/NettyAsyncHttpProvider.java | 38 +++++++++---------- .../providers/netty/NettyResponseFuture.java | 4 +- 2 files changed, 21 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 4f2bc32a83..01746c4503 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 @@ -1229,7 +1229,7 @@ public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws .ioException(new IOException("Channel Closed")).build(); fc = handleIoException(fc, future); - if (fc.replayRequest() && !future.cannotBeReplay()) { + if (fc.replayRequest() && future.canBeReplay()) { replayRequest(future, fc, ctx); return; } @@ -1250,9 +1250,8 @@ public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws protected boolean remotelyClosed(Channel channel, NettyResponseFuture future) { - if (isClose()) { + if (isClose()) return true; - } channelManager.removeAll(channel); @@ -1262,25 +1261,26 @@ protected boolean remotelyClosed(Channel channel, NettyResponseFuture future) future = (NettyResponseFuture) attachment; } - if (future == null || future.cannotBeReplay()) { - LOGGER.debug("Unable to recover future {}\n", future); - return true; - } + if (future != null && future.canBeReplay()) { + future.setState(NettyResponseFuture.STATE.RECONNECTED); - future.setState(NettyResponseFuture.STATE.RECONNECTED); + LOGGER.debug("Trying to recover request {}\n", future.getNettyRequest()); + if (future.getAsyncHandler() instanceof AsyncHandlerExtensions) + AsyncHandlerExtensions.class.cast(future.getAsyncHandler()).onRetry(); - LOGGER.debug("Trying to recover request {}\n", future.getNettyRequest()); - if (future.getAsyncHandler() instanceof AsyncHandlerExtensions) { - AsyncHandlerExtensions.class.cast(future.getAsyncHandler()).onRetry(); - } + try { + nextRequest(future.getRequest(), future); + return false; - try { - nextRequest(future.getRequest(), future); - return false; - } catch (IOException iox) { - future.setState(NettyResponseFuture.STATE.CLOSED); - future.abort(iox); - LOGGER.error("Remotely Closed, unable to recover", iox); + } catch (IOException iox) { + future.setState(NettyResponseFuture.STATE.CLOSED); + future.abort(iox); + LOGGER.error("Remotely Closed, unable to recover", iox); + return true; + } + + } else { + LOGGER.debug("Unable to recover future {}\n", future); return true; } } 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 6178302dac..ec6fd212f8 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 @@ -487,8 +487,8 @@ public void setRequest(Request request) { * * @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(); + public boolean canBeReplay() { + return !isDone() && canRetry() && !isCancelled() && !(channel() != null && channel().isOpen() && uri.getScheme().compareToIgnoreCase("https") != 0) && !isInAuth(); } public long getStart() { From 286737f77229852df96ebef3324ba74c3d203de5 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 15 Jul 2014 23:22:04 +0200 Subject: [PATCH 409/701] isDone implies isCancelled --- .../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 01746c4503..d01a1af465 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 @@ -1238,7 +1238,7 @@ public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws Protocol p = (ctx.getPipeline().get(HttpClientCodec.class) != null ? httpProtocol : webSocketProtocol); p.onClose(ctx, e); - if (future != null && !future.isDone() && !future.isCancelled()) { + if (future != null && !future.isDone()) { if (remotelyClosed(ctx.getChannel(), future)) { abort(future, REMOTELY_CLOSED_EXCEPTION); } From 5f64783ee51561a133cb71e288f0c8935405e8e9 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 15 Jul 2014 23:39:01 +0200 Subject: [PATCH 410/701] removeAll has already been called --- .../http/client/providers/netty/NettyAsyncHttpProvider.java | 3 +-- 1 file changed, 1 insertion(+), 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 d01a1af465..1edc9b9f24 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 @@ -1206,6 +1206,7 @@ public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws } channelManager.removeAll(ctx.getChannel()); + try { super.channelClosed(ctx, e); } catch (Exception ex) { @@ -1253,8 +1254,6 @@ protected boolean remotelyClosed(Channel channel, NettyResponseFuture future) if (isClose()) return true; - channelManager.removeAll(channel); - if (future == null) { Object attachment = Channels.getAttachment(channel); if (attachment instanceof NettyResponseFuture) From 26b9f3494768e6ea26ef28d7e1397b3c760884f6 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 16 Jul 2014 10:56:03 +0200 Subject: [PATCH 411/701] Client not properly closed --- .../client/async/MaxTotalConnectionTest.java | 60 ++++++++++--------- 1 file changed, 31 insertions(+), 29 deletions(-) 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 307d38937b..32417e97c7 100644 --- a/src/test/java/com/ning/http/client/async/MaxTotalConnectionTest.java +++ b/src/test/java/com/ning/http/client/async/MaxTotalConnectionTest.java @@ -18,6 +18,7 @@ import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.Response; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.testng.Assert; @@ -36,34 +37,37 @@ public abstract class MaxTotalConnectionTest extends AbstractBasicTest { public void testMaxTotalConnectionsExceedingException() { 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++) { - try { - client.prepareGet(urls[i]).execute(); - } catch (IOException e) { - // assert that 2nd request fails, because maxTotalConnections=1 - Assert.assertEquals(1, i); - caughtError = true; + try { + boolean 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(1, i); + caughtError = true; + } } + Assert.assertTrue(caughtError); + } finally { + client.close(); } - Assert.assertTrue(caughtError); - client.close(); } @Test - public void testMaxTotalConnections() { + public void testMaxTotalConnections() throws IOException { 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()); + 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!"); - } + client.prepareGet(url).execute(); } } finally { client.close(); @@ -72,14 +76,18 @@ public void testMaxTotalConnections() { /** * 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. + * @throws ExecutionException + * @throws InterruptedException */ @Test(enabled = false) - public void testMaxTotalConnectionsCorrectExceptionHandling() { + public void testMaxTotalConnectionsCorrectExceptionHandling() throws InterruptedException, ExecutionException { 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()); try { - List futures = new ArrayList(); + List> futures = new ArrayList>(); boolean caughtError = false; for (int i = 0; i < urls.length; i++) { try { @@ -96,14 +104,8 @@ public void testMaxTotalConnectionsCorrectExceptionHandling() { 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); - } + for (Future future : futures) { + future.get(); } // try to execute once again, expecting that 1 connection is released From 5998a567a3fe9f5f9535536de876d2eb7ab294ee Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 16 Jul 2014 12:20:38 +0200 Subject: [PATCH 412/701] Temporarily remove maxConnectionPerHost feature as it's not properly implemented --- .../netty/NettyAsyncHttpProvider.java | 14 ++--- .../providers/netty/NettyConnectListener.java | 9 ++-- .../providers/netty/pool/ChannelManager.java | 26 ++++----- .../providers/netty/pool/ChannelPool.java | 2 +- .../netty/pool/DefaultChannelPool.java | 54 ++++--------------- .../providers/netty/pool/NonChannelPool.java | 2 +- .../async/netty/NettyConnectionPoolTest.java | 4 +- 7 files changed, 39 insertions(+), 72 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 1edc9b9f24..cafc7c36ff 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 @@ -567,7 +567,6 @@ private static String computeNonConnectRequestPath(AsyncHttpClientConfig config, private static HttpRequest construct(AsyncHttpClientConfig config, Request request, HttpMethod m, UriComponents uri, ChannelBuffer buffer, ProxyServer proxyServer) throws IOException { - HttpRequest nettyRequest; if (m.equals(HttpMethod.CONNECT)) { @@ -920,12 +919,12 @@ private ListenableFuture doConnect(final Request request, final AsyncHand } } - boolean acquiredConnection = false; + boolean channelPreempted = false; // Do not throw an exception when we need an extra connection for a redirect. if (!reclaimCache) { if (channelManager.preemptChannel()) { - acquiredConnection = true; + channelPreempted = true; } else { IOException ex = new IOException(String.format("Too many connections %s", config.getMaxTotalConnections())); try { @@ -938,7 +937,7 @@ private ListenableFuture doConnect(final Request request, final AsyncHand } NettyResponseFuture connectListenerFuture = buildConnectListenerFuture(config, request, asyncHandler, f, this, bufferedBytes, uri); - NettyConnectListener connectListener = new NettyConnectListener(config, connectListenerFuture, this, channelManager, acquiredConnection); + NettyConnectListener connectListener = new NettyConnectListener(config, connectListenerFuture, this, channelManager, channelPreempted); if (useSSl) constructSSLPipeline(connectListener); @@ -967,7 +966,7 @@ private ListenableFuture doConnect(final Request request, final AsyncHand channelFuture.addListener(connectListener); } catch (Throwable t) { - if (acquiredConnection) + if (channelPreempted) channelManager.abortChannelPreemption(); abort(connectListener.future(), t.getCause() == null ? t : t.getCause()); } @@ -1167,9 +1166,10 @@ private void nextRequest(final Request request, final NettyResponseFuture fut public void abort(NettyResponseFuture future, Throwable t) { Channel channel = future.channel(); - channelManager.closeChannel(channel.getPipeline().getContext(NettyAsyncHttpProvider.class)); + if (channel != null) + channelManager.closeChannel(channel.getPipeline().getContext(NettyAsyncHttpProvider.class)); - if (!future.isCancelled() && !future.isDone()) { + if (!future.isDone()) { LOGGER.debug("Aborting Future {}\n", future); LOGGER.debug(t.getMessage(), 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 640461453a..b4184d664e 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 @@ -45,19 +45,19 @@ final class NettyConnectListener implements ChannelFutureListener { private final HttpRequest nettyRequest; private final NettyAsyncHttpProvider provider; private final ChannelManager channelManager; - private final boolean acquiredConnection; + private final boolean channelPreempted; public NettyConnectListener(AsyncHttpClientConfig config,// NettyResponseFuture future,// NettyAsyncHttpProvider provider,// ChannelManager channelManager,// - boolean acquiredConnection) { + boolean channelPreempted) { this.config = config; this.future = future; this.nettyRequest = future.getNettyRequest(); this.provider = provider; this.channelManager = channelManager; - this.acquiredConnection = acquiredConnection; + this.channelPreempted = channelPreempted; } public NettyResponseFuture future() { @@ -65,7 +65,7 @@ public NettyResponseFuture future() { } private void abortChannelPreemption() { - if (acquiredConnection) + if (channelPreempted) channelManager.abortChannelPreemption(); } @@ -106,6 +106,7 @@ public void operationComplete(ChannelFuture handshakeFuture) throws Exception { if (hostnameVerifier.verify(host, session)) { writeRequest(channel); } else { + abortChannelPreemption(); ConnectException exception = new ConnectException("HostnameVerifier exception"); future.abort(exception); throw exception; diff --git a/src/main/java/com/ning/http/client/providers/netty/pool/ChannelManager.java b/src/main/java/com/ning/http/client/providers/netty/pool/ChannelManager.java index 247b35b1a3..a8062446e9 100644 --- a/src/main/java/com/ning/http/client/providers/netty/pool/ChannelManager.java +++ b/src/main/java/com/ning/http/client/providers/netty/pool/ChannelManager.java @@ -32,30 +32,30 @@ public class ChannelManager { private static final Logger LOGGER = LoggerFactory.getLogger(ChannelManager.class); private final ChannelPool channelPool; - private final Semaphore freeConnections; - private final boolean trackConnections; - + private final boolean maxTotalConnectionsEnabled; + private final Semaphore freeChannels; private final ChannelGroup openChannels; public ChannelManager(AsyncHttpClientConfig config, ChannelPool channelPool) { - if (config.getMaxTotalConnections() != -1) { - trackConnections = true; + this.channelPool = channelPool; + + maxTotalConnectionsEnabled = config.getMaxTotalConnections() > 0; + + if (maxTotalConnectionsEnabled) { openChannels = new CleanupChannelGroup("asyncHttpClient") { @Override public boolean remove(Object o) { boolean removed = super.remove(o); if (removed) - freeConnections.release(); + freeChannels.release(); return removed; } }; - freeConnections = new Semaphore(config.getMaxTotalConnections()); + freeChannels = new Semaphore(config.getMaxTotalConnections()); } else { - trackConnections = false; openChannels = new CleanupChannelGroup("asyncHttpClient"); - freeConnections = null; + freeChannels = null; } - this.channelPool = channelPool; } public final boolean tryToOfferChannelToPool(ChannelHandlerContext ctx, boolean keepAlive, String poolKey) { @@ -80,7 +80,7 @@ public boolean removeAll(Channel connection) { } public boolean preemptChannel() { - return channelPool.canCacheConnection() && (!trackConnections || freeConnections.tryAcquire()); + return channelPool.isOpen() && (!maxTotalConnectionsEnabled || freeChannels.tryAcquire()); } public void destroy() { @@ -117,8 +117,8 @@ public void closeChannel(final ChannelHandlerContext ctx) { // temp public void abortChannelPreemption() { - if (trackConnections) - freeConnections.release(); + if (maxTotalConnectionsEnabled) + freeChannels.release(); } public void registerOpenChannel(Channel channel) { diff --git a/src/main/java/com/ning/http/client/providers/netty/pool/ChannelPool.java b/src/main/java/com/ning/http/client/providers/netty/pool/ChannelPool.java index cec8d6a0e8..51d3842854 100644 --- a/src/main/java/com/ning/http/client/providers/netty/pool/ChannelPool.java +++ b/src/main/java/com/ning/http/client/providers/netty/pool/ChannelPool.java @@ -54,7 +54,7 @@ public interface ChannelPool { * * @return true if a connection can be cached. */ - boolean canCacheConnection(); + boolean isOpen(); /** * Destroy all connections that has been cached by this instance. diff --git a/src/main/java/com/ning/http/client/providers/netty/pool/DefaultChannelPool.java b/src/main/java/com/ning/http/client/providers/netty/pool/DefaultChannelPool.java index ea75efe0f7..c670417974 100644 --- a/src/main/java/com/ning/http/client/providers/netty/pool/DefaultChannelPool.java +++ b/src/main/java/com/ning/http/client/providers/netty/pool/DefaultChannelPool.java @@ -21,7 +21,6 @@ import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; import org.jboss.netty.channel.Channel; import org.jboss.netty.util.Timeout; @@ -43,14 +42,9 @@ public final class DefaultChannelPool implements ChannelPool { private final ConcurrentHashMap> connectionsPool = new ConcurrentHashMap>(); private final ConcurrentHashMap channel2Creation = new ConcurrentHashMap(); - private final AtomicInteger size = new AtomicInteger(); private final AtomicBoolean isClosed = new AtomicBoolean(false); private final Timer nettyTimer; private final boolean sslConnectionPoolEnabled; - private final int maxTotalConnections; - private final boolean maxTotalConnectionsDisabled; - private final int maxConnectionPerHost; - private final boolean maxConnectionPerHostDisabled; private final int maxConnectionTTL; private final boolean maxConnectionTTLDisabled; private final long maxIdleTime; @@ -58,8 +52,7 @@ public final class DefaultChannelPool implements ChannelPool { private final long cleanerPeriod; public DefaultChannelPool(AsyncHttpClientConfig config, Timer hashedWheelTimer) { - this(config.getMaxTotalConnections(),// - config.getMaxConnectionPerHost(),// + this(config.getMaxConnectionPerHost(),// config.getIdleConnectionInPoolTimeoutInMs(),// config.getMaxConnectionLifeTimeInMs(),// config.isSslConnectionPoolEnabled(),// @@ -67,16 +60,11 @@ public DefaultChannelPool(AsyncHttpClientConfig config, Timer hashedWheelTimer) } public DefaultChannelPool(// - int maxTotalConnections,// int maxConnectionPerHost,// long maxIdleTime,// int maxConnectionTTL,// boolean sslConnectionPoolEnabled,// Timer nettyTimer) { - this.maxTotalConnections = maxTotalConnections; - maxTotalConnectionsDisabled = maxTotalConnections <= 0; - this.maxConnectionPerHost = maxConnectionPerHost; - maxConnectionPerHostDisabled = maxConnectionPerHost <= 0; this.sslConnectionPoolEnabled = sslConnectionPoolEnabled; this.maxIdleTime = maxIdleTime; this.maxConnectionTTL = maxConnectionTTL; @@ -211,16 +199,18 @@ public void run(Timeout timeout) throws Exception { } long start = millisTime(); - int totalCount = size.get(); int closedCount = 0; + int totalCount = 0; for (ConcurrentLinkedQueue pool : connectionsPool.values()) { // store in intermediate unsynchronized lists to minimize the impact on the ConcurrentLinkedQueue + if (LOGGER.isDebugEnabled()) { + totalCount += pool.size(); + } List candidateExpiredChannels = expiredChannels(pool, start); List closedChannels = closeChannels(candidateExpiredChannels); pool.removeAll(closedChannels); int poolClosedCount = closedChannels.size(); - size.addAndGet(-poolClosedCount); closedCount += poolClosedCount; } @@ -236,17 +226,6 @@ public void run(Timeout timeout) throws Exception { } } - private boolean addIdleChannel(ConcurrentLinkedQueue idleConnectionForKey, String key, Channel channel, long now) { - - // FIXME computing CLQ.size is not efficient - if (maxConnectionPerHostDisabled || idleConnectionForKey.size() < maxConnectionPerHost) { - IdleChannel idleChannel = new IdleChannel(channel, now); - return idleConnectionForKey.add(idleChannel); - } - LOGGER.debug("Maximum number of requests per key reached {} for {}", maxConnectionPerHost, key); - return false; - } - /** * {@inheritDoc} */ @@ -267,11 +246,9 @@ public boolean offer(String key, Channel channel) { idleConnectionForKey = newPool; } - boolean added = addIdleChannel(idleConnectionForKey, key, channel, now); - if (added) { - size.incrementAndGet(); + boolean added = idleConnectionForKey.add(new IdleChannel(channel, now)); + if (added) channel2Creation.putIfAbsent(channel, new ChannelCreation(now, key)); - } return added; } @@ -298,11 +275,7 @@ else if (isRemotelyClosed(idleChannel.channel)) { } } } - if (idleChannel != null) { - size.decrementAndGet(); - return idleChannel.channel; - } else - return null; + return idleChannel != null ? idleChannel.channel : null; } /** @@ -316,10 +289,8 @@ public boolean removeAll(Channel channel) { /** * {@inheritDoc} */ - public boolean canCacheConnection() { - // FIXME: doesn't honor per host limit - // FIXME: doesn't account for borrowed channels - return !isClosed.get() && (maxTotalConnectionsDisabled || size.get() < maxTotalConnections); + public boolean isOpen() { + return !isClosed.get(); } /** @@ -336,7 +307,6 @@ public void destroy() { connectionsPool.clear(); channel2Creation.clear(); - size.set(0); } private void close(Channel channel) { @@ -349,8 +319,4 @@ private void close(Channel channel) { // noop } } - - public String toString() { - return String.format("NettyConnectionPool: {pool-size: %d}", size.get()); - } } diff --git a/src/main/java/com/ning/http/client/providers/netty/pool/NonChannelPool.java b/src/main/java/com/ning/http/client/providers/netty/pool/NonChannelPool.java index 20bca82b9c..5ff46b8a22 100644 --- a/src/main/java/com/ning/http/client/providers/netty/pool/NonChannelPool.java +++ b/src/main/java/com/ning/http/client/providers/netty/pool/NonChannelPool.java @@ -32,7 +32,7 @@ public boolean removeAll(Channel connection) { return false; } - public boolean canCacheConnection() { + public boolean isOpen() { return true; } diff --git a/src/test/java/com/ning/http/client/async/netty/NettyConnectionPoolTest.java b/src/test/java/com/ning/http/client/async/netty/NettyConnectionPoolTest.java index 4df243e7c6..1ab5f1a833 100644 --- a/src/test/java/com/ning/http/client/async/netty/NettyConnectionPoolTest.java +++ b/src/test/java/com/ning/http/client/async/netty/NettyConnectionPoolTest.java @@ -56,7 +56,7 @@ public boolean removeAll(Channel connection) { return false; } - public boolean canCacheConnection() { + public boolean isOpen() { return false; } @@ -100,7 +100,7 @@ public boolean removeAll(Channel connection) { return false; } - public boolean canCacheConnection() { + public boolean isOpen() { return true; } From 48bdd8ad3ee89a62a02451851b9dfac902739cba Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 16 Jul 2014 12:20:45 +0200 Subject: [PATCH 413/701] minor clean up --- src/test/java/com/ning/http/client/async/BasicHttpsTest.java | 2 -- 1 file changed, 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 295cc788e2..bea352f9ec 100644 --- a/src/test/java/com/ning/http/client/async/BasicHttpsTest.java +++ b/src/test/java/com/ning/http/client/async/BasicHttpsTest.java @@ -288,8 +288,6 @@ public void reconnectsAfterFailedCertificationPath() throws Exception { } else { assertTrue(cause instanceof IOException, "Expected an IOException, got a " + cause); } - } catch (Exception e) { - System.err.println("WTF"+ e.getMessage()); } assertNotNull(cause); From a67f5e74b17f4e3debf1d42f366cca2f938e48bc Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 16 Jul 2014 12:25:53 +0200 Subject: [PATCH 414/701] Use Channel.id as channel2Creation key, hold less Channel references --- .../providers/netty/pool/DefaultChannelPool.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/pool/DefaultChannelPool.java b/src/main/java/com/ning/http/client/providers/netty/pool/DefaultChannelPool.java index c670417974..9c576e4aaf 100644 --- a/src/main/java/com/ning/http/client/providers/netty/pool/DefaultChannelPool.java +++ b/src/main/java/com/ning/http/client/providers/netty/pool/DefaultChannelPool.java @@ -41,7 +41,7 @@ public final class DefaultChannelPool implements ChannelPool { private static final Logger LOGGER = LoggerFactory.getLogger(DefaultChannelPool.class); private final ConcurrentHashMap> connectionsPool = new ConcurrentHashMap>(); - private final ConcurrentHashMap channel2Creation = new ConcurrentHashMap(); + private final ConcurrentHashMap channel2Creation = new ConcurrentHashMap(); private final AtomicBoolean isClosed = new AtomicBoolean(false); private final Timer nettyTimer; private final boolean sslConnectionPoolEnabled; @@ -120,7 +120,7 @@ private boolean isTTLExpired(Channel channel, long now) { if (maxConnectionTTLDisabled) return false; - ChannelCreation creation = channel2Creation.get(channel); + ChannelCreation creation = channel2Creation.get(channel.getId()); return creation == null || now - creation.creationTime >= maxConnectionTTL; } @@ -248,7 +248,7 @@ public boolean offer(String key, Channel channel) { boolean added = idleConnectionForKey.add(new IdleChannel(channel, now)); if (added) - channel2Creation.putIfAbsent(channel, new ChannelCreation(now, key)); + channel2Creation.putIfAbsent(channel.getId(), new ChannelCreation(now, key)); return added; } @@ -282,7 +282,7 @@ else if (isRemotelyClosed(idleChannel.channel)) { * {@inheritDoc} */ public boolean removeAll(Channel channel) { - ChannelCreation creation = channel2Creation.remove(channel); + ChannelCreation creation = channel2Creation.remove(channel.getId()); return !isClosed.get() && creation != null && connectionsPool.get(creation.key).remove(channel); } @@ -313,7 +313,7 @@ private void close(Channel channel) { try { // FIXME pity to have to do this here Channels.setDiscard(channel); - channel2Creation.remove(channel); + channel2Creation.remove(channel.getId()); channel.close(); } catch (Throwable t) { // noop From 72ac2c07730f36bc39b05db4e0613f3463a5a316 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 16 Jul 2014 14:19:52 +0200 Subject: [PATCH 415/701] Renaming --- .../netty/NettyAsyncHttpProvider.java | 16 +++- .../providers/netty/NettyConnectListener.java | 21 +++--- .../providers/netty/pool/ChannelManager.java | 67 ++++++++++++++--- .../providers/netty/pool/ChannelPool.java | 4 +- .../netty/pool/DefaultChannelPool.java | 74 ++++++++++--------- .../providers/netty/pool/NonChannelPool.java | 2 +- .../async/netty/NettyConnectionPoolTest.java | 4 +- 7 files changed, 124 insertions(+), 64 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 cafc7c36ff..9bb39d03d2 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 @@ -919,11 +919,20 @@ private ListenableFuture doConnect(final Request request, final AsyncHand } } + NettyResponseFuture connectListenerFuture = buildConnectListenerFuture(config, request, asyncHandler, f, this, bufferedBytes, uri); + boolean channelPreempted = false; + String poolKey = null; // Do not throw an exception when we need an extra connection for a redirect. if (!reclaimCache) { - if (channelManager.preemptChannel()) { + + // only compute when maxConnectionPerHost is enabled + // FIXME clean up + if (config.getMaxConnectionPerHost() > 0) + poolKey = getPoolKey(connectListenerFuture); + + if (channelManager.preemptChannel(poolKey)) { channelPreempted = true; } else { IOException ex = new IOException(String.format("Too many connections %s", config.getMaxTotalConnections())); @@ -936,8 +945,7 @@ private ListenableFuture doConnect(final Request request, final AsyncHand } } - NettyResponseFuture connectListenerFuture = buildConnectListenerFuture(config, request, asyncHandler, f, this, bufferedBytes, uri); - NettyConnectListener connectListener = new NettyConnectListener(config, connectListenerFuture, this, channelManager, channelPreempted); + NettyConnectListener connectListener = new NettyConnectListener(config, connectListenerFuture, this, channelManager, channelPreempted, poolKey); if (useSSl) constructSSLPipeline(connectListener); @@ -967,7 +975,7 @@ private ListenableFuture doConnect(final Request request, final AsyncHand } catch (Throwable t) { if (channelPreempted) - channelManager.abortChannelPreemption(); + channelManager.abortChannelPreemption(poolKey); abort(connectListener.future(), t.getCause() == null ? t : t.getCause()); } 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 b4184d664e..4787abea99 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 @@ -46,30 +46,33 @@ final class NettyConnectListener implements ChannelFutureListener { private final NettyAsyncHttpProvider provider; private final ChannelManager channelManager; private final boolean channelPreempted; + private final String poolKey; public NettyConnectListener(AsyncHttpClientConfig config,// NettyResponseFuture future,// NettyAsyncHttpProvider provider,// ChannelManager channelManager,// - boolean channelPreempted) { + boolean channelPreempted,// + String poolKey) { this.config = config; this.future = future; this.nettyRequest = future.getNettyRequest(); this.provider = provider; this.channelManager = channelManager; this.channelPreempted = channelPreempted; + this.poolKey = poolKey; } public NettyResponseFuture future() { return future; } - private void abortChannelPreemption() { + private void abortChannelPreemption(String poolKey) { if (channelPreempted) - channelManager.abortChannelPreemption(); + channelManager.abortChannelPreemption(poolKey); } - private void writeRequest(Channel channel) { + private void writeRequest(Channel channel, String poolKey) { LOGGER.debug("\nNon cached request \n{}\n\nusing Channel \n{}\n", future.getNettyRequest(), channel); @@ -79,7 +82,7 @@ private void writeRequest(Channel channel) { provider.writeRequest(channel, config, future); } else { - abortChannelPreemption(); + abortChannelPreemption(poolKey); } } @@ -104,9 +107,9 @@ public void operationComplete(ChannelFuture handshakeFuture) throws Exception { LOGGER.debug("onFutureSuccess: session = {}, id = {}, isValid = {}, host = {}", session.toString(), Base64.encode(session.getId()), session.isValid(), host); if (hostnameVerifier.verify(host, session)) { - writeRequest(channel); + writeRequest(channel, poolKey); } else { - abortChannelPreemption(); + abortChannelPreemption(poolKey); ConnectException exception = new ConnectException("HostnameVerifier exception"); future.abort(exception); throw exception; @@ -115,11 +118,11 @@ public void operationComplete(ChannelFuture handshakeFuture) throws Exception { } }); } else { - writeRequest(f.getChannel()); + writeRequest(f.getChannel(), poolKey); } } else { - abortChannelPreemption(); + abortChannelPreemption(poolKey); Throwable cause = f.getCause(); boolean canRetry = future.canRetry(); diff --git a/src/main/java/com/ning/http/client/providers/netty/pool/ChannelManager.java b/src/main/java/com/ning/http/client/providers/netty/pool/ChannelManager.java index a8062446e9..347cd4be33 100644 --- a/src/main/java/com/ning/http/client/providers/netty/pool/ChannelManager.java +++ b/src/main/java/com/ning/http/client/providers/netty/pool/ChannelManager.java @@ -25,6 +25,7 @@ import com.ning.http.client.providers.netty.NettyAsyncHttpProvider; import com.ning.http.client.providers.netty.NettyResponseFuture; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Semaphore; public class ChannelManager { @@ -35,6 +36,10 @@ public class ChannelManager { private final boolean maxTotalConnectionsEnabled; private final Semaphore freeChannels; private final ChannelGroup openChannels; + private final int maxConnectionsPerHost; + private final boolean maxConnectionsPerHostEnabled; + private final ConcurrentHashMap freeChannelsPerHost; + private final ConcurrentHashMap channelId2KeyPool; public ChannelManager(AsyncHttpClientConfig config, ChannelPool channelPool) { this.channelPool = channelPool; @@ -46,8 +51,17 @@ public ChannelManager(AsyncHttpClientConfig config, ChannelPool channelPool) { @Override public boolean remove(Object o) { boolean removed = super.remove(o); - if (removed) + if (removed) { freeChannels.release(); + if (maxConnectionsPerHostEnabled) { + String poolKey = channelId2KeyPool.remove(Channel.class.cast(o).getId()); + if (poolKey != null) { + Semaphore freeChannelsForHost = freeChannelsPerHost.get(poolKey); + if (freeChannelsForHost != null) + freeChannelsForHost.release(); + } + } + } return removed; } }; @@ -56,18 +70,30 @@ public boolean remove(Object o) { openChannels = new CleanupChannelGroup("asyncHttpClient"); freeChannels = null; } + + maxConnectionsPerHost = config.getMaxConnectionPerHost(); + maxConnectionsPerHostEnabled = config.getMaxConnectionPerHost() > 0; + + if (maxConnectionsPerHostEnabled) { + freeChannelsPerHost = new ConcurrentHashMap(); + channelId2KeyPool = new ConcurrentHashMap(); + } else { + freeChannelsPerHost = null; + channelId2KeyPool = null; + } } - public final boolean tryToOfferChannelToPool(ChannelHandlerContext ctx, boolean keepAlive, String poolKey) { + public final void tryToOfferChannelToPool(ChannelHandlerContext ctx, boolean keepAlive, String poolKey) { Channel channel = ctx.getChannel(); - if (keepAlive && channel.isReadable() && channelPool.offer(poolKey, channel)) { + if (keepAlive && channel.isReadable()) { LOGGER.debug("Adding key: {} for channel {}", poolKey, channel); + channelPool.offer(channel, poolKey); + if (maxConnectionsPerHostEnabled) + channelId2KeyPool.putIfAbsent(channel.getId(), poolKey); Channels.setDiscard(ctx); - return true; } else { // not offered closeChannel(ctx); - return false; } } @@ -79,13 +105,34 @@ public boolean removeAll(Channel connection) { return channelPool.removeAll(connection); } - public boolean preemptChannel() { - return channelPool.isOpen() && (!maxTotalConnectionsEnabled || freeChannels.tryAcquire()); + private boolean tryAcquireGlobal() { + return !maxTotalConnectionsEnabled || freeChannels.tryAcquire(); + } + + private Semaphore getFreeConnectionsForHost(String poolKey) { + Semaphore freeConnections = freeChannelsPerHost.get(poolKey); + if (freeConnections == null) { + // lazy create the semaphore + Semaphore newFreeConnections = new Semaphore(maxConnectionsPerHost); + freeConnections = freeChannelsPerHost.putIfAbsent(poolKey, newFreeConnections); + if (freeConnections == null) + freeConnections = newFreeConnections; + } + return freeConnections; + } + + private boolean tryAcquirePerHost(String poolKey) { + return !maxConnectionsPerHostEnabled || getFreeConnectionsForHost(poolKey).tryAcquire(); + } + + public boolean preemptChannel(String poolKey) { + return channelPool.isOpen() && tryAcquireGlobal() && tryAcquirePerHost(poolKey); } public void destroy() { channelPool.destroy(); openChannels.close(); + for (Channel channel : openChannels) { ChannelHandlerContext ctx = channel.getPipeline().getContext(NettyAsyncHttpProvider.class); Object attachment = Channels.getAttachment(ctx); @@ -104,7 +151,6 @@ public void closeChannel(final ChannelHandlerContext ctx) { // The channel may have already been removed if a timeout occurred, and this method may be called just after. if (channel != null) { - // FIXME can the context channel really be null? LOGGER.debug("Closing Channel {} ", channel); try { channel.close(); @@ -115,10 +161,11 @@ public void closeChannel(final ChannelHandlerContext ctx) { } } - // temp - public void abortChannelPreemption() { + public void abortChannelPreemption(String poolKey) { if (maxTotalConnectionsEnabled) freeChannels.release(); + if (maxConnectionsPerHostEnabled) + getFreeConnectionsForHost(poolKey).release(); } public void registerOpenChannel(Channel channel) { diff --git a/src/main/java/com/ning/http/client/providers/netty/pool/ChannelPool.java b/src/main/java/com/ning/http/client/providers/netty/pool/ChannelPool.java index 51d3842854..b4eea24a53 100644 --- a/src/main/java/com/ning/http/client/providers/netty/pool/ChannelPool.java +++ b/src/main/java/com/ning/http/client/providers/netty/pool/ChannelPool.java @@ -26,11 +26,11 @@ public interface ChannelPool { /** * Add a connection to the pool * - * @param uri a uri used to retrieve the cached connection + * @param poolKey a key used to retrieve the cached connection * @param connection an I/O connection * @return true if added. */ - boolean offer(String uri, Channel connection); + boolean offer(Channel connection, String poolKey); /** * Remove the connection associated with the uri. diff --git a/src/main/java/com/ning/http/client/providers/netty/pool/DefaultChannelPool.java b/src/main/java/com/ning/http/client/providers/netty/pool/DefaultChannelPool.java index 9c576e4aaf..2616544faa 100644 --- a/src/main/java/com/ning/http/client/providers/netty/pool/DefaultChannelPool.java +++ b/src/main/java/com/ning/http/client/providers/netty/pool/DefaultChannelPool.java @@ -40,8 +40,8 @@ public final class DefaultChannelPool implements ChannelPool { private static final Logger LOGGER = LoggerFactory.getLogger(DefaultChannelPool.class); - private final ConcurrentHashMap> connectionsPool = new ConcurrentHashMap>(); - private final ConcurrentHashMap channel2Creation = new ConcurrentHashMap(); + private final ConcurrentHashMap> poolsPerKey = new ConcurrentHashMap>(); + private final ConcurrentHashMap channelId2Creation = new ConcurrentHashMap(); private final AtomicBoolean isClosed = new AtomicBoolean(false); private final Timer nettyTimer; private final boolean sslConnectionPoolEnabled; @@ -85,11 +85,11 @@ private void scheduleNewIdleChannelDetector(TimerTask task) { private static final class ChannelCreation { final long creationTime; - final String key; + final String poolKey; - ChannelCreation(long creationTime, String key) { + ChannelCreation(long creationTime, String poolKey) { this.creationTime = creationTime; - this.key = key; + this.poolKey = poolKey; } } @@ -120,7 +120,7 @@ private boolean isTTLExpired(Channel channel, long now) { if (maxConnectionTTLDisabled) return false; - ChannelCreation creation = channel2Creation.get(channel.getId()); + ChannelCreation creation = channelId2Creation.get(channel.getId()); return creation == null || now - creation.creationTime >= maxConnectionTTL; } @@ -192,23 +192,21 @@ public void run(Timeout timeout) throws Exception { return; try { - if (LOGGER.isDebugEnabled()) { - for (String key : connectionsPool.keySet()) { - LOGGER.debug("Entry count for : {} : {}", key, connectionsPool.get(key).size()); + if (LOGGER.isDebugEnabled()) + for (String key : poolsPerKey.keySet()) { + LOGGER.debug("Entry count for : {} : {}", key, poolsPerKey.get(key).size()); } - } long start = millisTime(); int closedCount = 0; int totalCount = 0; - for (ConcurrentLinkedQueue pool : connectionsPool.values()) { + for (ConcurrentLinkedQueue pool : poolsPerKey.values()) { // store in intermediate unsynchronized lists to minimize the impact on the ConcurrentLinkedQueue - if (LOGGER.isDebugEnabled()) { + if (LOGGER.isDebugEnabled()) totalCount += pool.size(); - } - List candidateExpiredChannels = expiredChannels(pool, start); - List closedChannels = closeChannels(candidateExpiredChannels); + + List closedChannels = closeChannels(expiredChannels(pool, start)); pool.removeAll(closedChannels); int poolClosedCount = closedChannels.size(); closedCount += poolClosedCount; @@ -226,11 +224,23 @@ public void run(Timeout timeout) throws Exception { } } + private ConcurrentLinkedQueue getPoolForKey(String key) { + ConcurrentLinkedQueue pool = poolsPerKey.get(key); + if (pool == null) { + // lazy init pool + ConcurrentLinkedQueue newPool = new ConcurrentLinkedQueue(); + pool = poolsPerKey.putIfAbsent(key, newPool); + if (pool == null) + pool = newPool; + } + return pool; + } + /** * {@inheritDoc} */ - public boolean offer(String key, Channel channel) { - if (isClosed.get() || (!sslConnectionPoolEnabled && key.startsWith("https"))) + public boolean offer(Channel channel, String poolKey) { + if (isClosed.get() || (!sslConnectionPoolEnabled && poolKey.startsWith("https"))) return false; long now = millisTime(); @@ -238,17 +248,9 @@ public boolean offer(String key, Channel channel) { if (isTTLExpired(channel, now)) return false; - ConcurrentLinkedQueue idleConnectionForKey = connectionsPool.get(key); - if (idleConnectionForKey == null) { - ConcurrentLinkedQueue newPool = new ConcurrentLinkedQueue(); - idleConnectionForKey = connectionsPool.putIfAbsent(key, newPool); - if (idleConnectionForKey == null) - idleConnectionForKey = newPool; - } - - boolean added = idleConnectionForKey.add(new IdleChannel(channel, now)); + boolean added = getPoolForKey(poolKey).add(new IdleChannel(channel, now)); if (added) - channel2Creation.putIfAbsent(channel.getId(), new ChannelCreation(now, key)); + channelId2Creation.putIfAbsent(channel.getId(), new ChannelCreation(now, poolKey)); return added; } @@ -256,12 +258,12 @@ public boolean offer(String key, Channel channel) { /** * {@inheritDoc} */ - public Channel poll(String key) { - if (!sslConnectionPoolEnabled && key.startsWith("https")) + public Channel poll(String poolKey) { + if (!sslConnectionPoolEnabled && poolKey.startsWith("https")) return null; IdleChannel idleChannel = null; - ConcurrentLinkedQueue pooledConnectionForKey = connectionsPool.get(key); + ConcurrentLinkedQueue pooledConnectionForKey = poolsPerKey.get(poolKey); if (pooledConnectionForKey != null) { while (idleChannel == null) { idleChannel = pooledConnectionForKey.poll(); @@ -282,8 +284,8 @@ else if (isRemotelyClosed(idleChannel.channel)) { * {@inheritDoc} */ public boolean removeAll(Channel channel) { - ChannelCreation creation = channel2Creation.remove(channel.getId()); - return !isClosed.get() && creation != null && connectionsPool.get(creation.key).remove(channel); + ChannelCreation creation = channelId2Creation.remove(channel.getId()); + return !isClosed.get() && creation != null && poolsPerKey.get(creation.poolKey).remove(channel); } /** @@ -300,20 +302,20 @@ public void destroy() { if (isClosed.getAndSet(true)) return; - for (ConcurrentLinkedQueue pool : connectionsPool.values()) { + for (ConcurrentLinkedQueue pool : poolsPerKey.values()) { for (IdleChannel idleChannel : pool) close(idleChannel.channel); } - connectionsPool.clear(); - channel2Creation.clear(); + poolsPerKey.clear(); + channelId2Creation.clear(); } private void close(Channel channel) { try { // FIXME pity to have to do this here Channels.setDiscard(channel); - channel2Creation.remove(channel.getId()); + channelId2Creation.remove(channel.getId()); channel.close(); } catch (Throwable t) { // noop diff --git a/src/main/java/com/ning/http/client/providers/netty/pool/NonChannelPool.java b/src/main/java/com/ning/http/client/providers/netty/pool/NonChannelPool.java index 5ff46b8a22..807ece6a2c 100644 --- a/src/main/java/com/ning/http/client/providers/netty/pool/NonChannelPool.java +++ b/src/main/java/com/ning/http/client/providers/netty/pool/NonChannelPool.java @@ -20,7 +20,7 @@ public class NonChannelPool implements ChannelPool { - public boolean offer(String uri, Channel connection) { + public boolean offer(Channel connection, String poolKey) { return false; } diff --git a/src/test/java/com/ning/http/client/async/netty/NettyConnectionPoolTest.java b/src/test/java/com/ning/http/client/async/netty/NettyConnectionPoolTest.java index 1ab5f1a833..b016971a72 100644 --- a/src/test/java/com/ning/http/client/async/netty/NettyConnectionPoolTest.java +++ b/src/test/java/com/ning/http/client/async/netty/NettyConnectionPoolTest.java @@ -44,7 +44,7 @@ public void testInvalidConnectionsPool() { ChannelPool cp = new ChannelPool() { - public boolean offer(String key, Channel connection) { + public boolean offer(Channel connection, String poolKey) { return false; } @@ -88,7 +88,7 @@ public void testValidConnectionsPool() { ChannelPool cp = new ChannelPool() { - public boolean offer(String key, Channel connection) { + public boolean offer(Channel connection, String poolKey) { return true; } From f04389bd06803778155341b091e6eba104c2d53d Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 16 Jul 2014 15:34:45 +0200 Subject: [PATCH 416/701] fix license headers --- .../providers/netty/pool/ChannelPool.java | 21 ++++++++----------- .../netty/pool/DefaultChannelPool.java | 5 +++-- .../providers/netty/pool/NonChannelPool.java | 21 ++++++++----------- .../http/client/uri/UriComponentsParser.java | 4 ++-- 4 files changed, 23 insertions(+), 28 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/pool/ChannelPool.java b/src/main/java/com/ning/http/client/providers/netty/pool/ChannelPool.java index b4eea24a53..5617e1fa31 100644 --- a/src/main/java/com/ning/http/client/providers/netty/pool/ChannelPool.java +++ b/src/main/java/com/ning/http/client/providers/netty/pool/ChannelPool.java @@ -1,18 +1,15 @@ /* - * Copyright 2010 Ning, Inc. + * Copyright (c) 2014 AsyncHttpClient Project. All rights reserved. * - * 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. + * 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.providers.netty.pool; diff --git a/src/main/java/com/ning/http/client/providers/netty/pool/DefaultChannelPool.java b/src/main/java/com/ning/http/client/providers/netty/pool/DefaultChannelPool.java index 2616544faa..4366aeaed4 100644 --- a/src/main/java/com/ning/http/client/providers/netty/pool/DefaultChannelPool.java +++ b/src/main/java/com/ning/http/client/providers/netty/pool/DefaultChannelPool.java @@ -1,9 +1,10 @@ /* - * Copyright (c) 2010-2012 Sonatype, Inc. All rights reserved. + * Copyright (c) 2014 AsyncHttpClient Project. 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. + * 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 diff --git a/src/main/java/com/ning/http/client/providers/netty/pool/NonChannelPool.java b/src/main/java/com/ning/http/client/providers/netty/pool/NonChannelPool.java index 807ece6a2c..7b282b0f24 100644 --- a/src/main/java/com/ning/http/client/providers/netty/pool/NonChannelPool.java +++ b/src/main/java/com/ning/http/client/providers/netty/pool/NonChannelPool.java @@ -1,18 +1,15 @@ /* - * Copyright 2010 Ning, Inc. + * Copyright (c) 2014 AsyncHttpClient Project. All rights reserved. * - * 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. + * 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.providers.netty.pool; diff --git a/src/main/java/com/ning/http/client/uri/UriComponentsParser.java b/src/main/java/com/ning/http/client/uri/UriComponentsParser.java index 2293b49ac8..54daefeeab 100644 --- a/src/main/java/com/ning/http/client/uri/UriComponentsParser.java +++ b/src/main/java/com/ning/http/client/uri/UriComponentsParser.java @@ -3,7 +3,8 @@ * * 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. + * 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 @@ -12,7 +13,6 @@ */ package com.ning.http.client.uri; - final class UriComponentsParser { public String scheme; From 88c7e381ed942b280fc30bf5e3433f015f0f459b Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 16 Jul 2014 15:35:13 +0200 Subject: [PATCH 417/701] Rename NonChannelPool into NoopChannelPool --- .../http/client/providers/netty/NettyAsyncHttpProvider.java | 4 ++-- .../netty/pool/{NonChannelPool.java => NoopChannelPool.java} | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) rename src/main/java/com/ning/http/client/providers/netty/pool/{NonChannelPool.java => NoopChannelPool.java} (95%) 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 9bb39d03d2..27753ded73 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,7 @@ import com.ning.http.client.providers.netty.pool.ChannelManager; import com.ning.http.client.providers.netty.pool.ChannelPool; import com.ning.http.client.providers.netty.pool.DefaultChannelPool; -import com.ning.http.client.providers.netty.pool.NonChannelPool; +import com.ning.http.client.providers.netty.pool.NoopChannelPool; import com.ning.http.client.providers.netty.spnego.SpnegoEngine; import com.ning.http.client.providers.netty.timeout.IdleConnectionTimeoutTimerTask; import com.ning.http.client.providers.netty.timeout.RequestTimeoutTimerTask; @@ -230,7 +230,7 @@ public NettyAsyncHttpProvider(AsyncHttpClientConfig config) { if (cp == null && config.isAllowPoolingConnection()) { cp = new DefaultChannelPool(config, nettyTimer); } else if (cp == null) { - cp = new NonChannelPool(); + cp = new NoopChannelPool(); } this.channelManager = new ChannelManager(config, cp); } diff --git a/src/main/java/com/ning/http/client/providers/netty/pool/NonChannelPool.java b/src/main/java/com/ning/http/client/providers/netty/pool/NoopChannelPool.java similarity index 95% rename from src/main/java/com/ning/http/client/providers/netty/pool/NonChannelPool.java rename to src/main/java/com/ning/http/client/providers/netty/pool/NoopChannelPool.java index 7b282b0f24..d9f3006f61 100644 --- a/src/main/java/com/ning/http/client/providers/netty/pool/NonChannelPool.java +++ b/src/main/java/com/ning/http/client/providers/netty/pool/NoopChannelPool.java @@ -15,7 +15,7 @@ import org.jboss.netty.channel.Channel; -public class NonChannelPool implements ChannelPool { +public class NoopChannelPool implements ChannelPool { public boolean offer(Channel connection, String poolKey) { return false; From ecece3d5452729742dadd99d896095e20a8c9228 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 16 Jul 2014 16:09:37 +0200 Subject: [PATCH 418/701] clean up: NettyResponseFuture.isDone involves isCancelled --- .../netty/NettyAsyncHttpProvider.java | 12 +++--- .../providers/netty/NettyConnectListener.java | 12 +++--- .../providers/netty/NettyResponseFuture.java | 4 +- .../netty/pool/DefaultChannelPool.java | 4 +- .../IdleConnectionTimeoutTimerTask.java | 39 ++++++++----------- .../timeout/RequestTimeoutTimerTask.java | 12 +++--- 6 files changed, 36 insertions(+), 47 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 27753ded73..dee6f84281 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 @@ -1247,13 +1247,11 @@ public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws Protocol p = (ctx.getPipeline().get(HttpClientCodec.class) != null ? httpProtocol : webSocketProtocol); p.onClose(ctx, e); - if (future != null && !future.isDone()) { - if (remotelyClosed(ctx.getChannel(), future)) { - abort(future, REMOTELY_CLOSED_EXCEPTION); - } - } else { + if (future == null || future.isDone()) channelManager.closeChannel(ctx); - } + + else if (remotelyClosed(ctx.getChannel(), future)) + abort(future, REMOTELY_CLOSED_EXCEPTION); } } @@ -2049,7 +2047,7 @@ private final class HttpProtocol implements Protocol { public void handle(final ChannelHandlerContext ctx, final MessageEvent e, final NettyResponseFuture future) throws Exception { // The connect timeout occurred. - if (future.isCancelled() || future.isDone()) { + if (future.isDone()) { channelManager.closeChannel(ctx); 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 4787abea99..0145531f7f 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 @@ -76,14 +76,14 @@ private void writeRequest(Channel channel, String poolKey) { LOGGER.debug("\nNon cached request \n{}\n\nusing Channel \n{}\n", future.getNettyRequest(), channel); - if (!future.isDone()) { - channelManager.registerOpenChannel(channel); - future.attachChannel(channel, false); - provider.writeRequest(channel, config, future); - - } else { + if (future.isDone()) { abortChannelPreemption(poolKey); + return; } + + channelManager.registerOpenChannel(channel); + future.attachChannel(channel, false); + provider.writeRequest(channel, config, future); } public final void operationComplete(ChannelFuture f) throws Exception { 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 ec6fd212f8..09fee154de 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 @@ -237,7 +237,7 @@ public void cancelTimeouts() { */ /* @Override */ public V get(long l, TimeUnit tu) throws InterruptedException, TimeoutException, ExecutionException { - if (!isDone() && !isCancelled()) { + if (!isDone()) { boolean expired = false; if (l == -1) { latch.await(); @@ -488,7 +488,7 @@ public void setRequest(Request request) { * @return true if that {@link Future} cannot be recovered. */ public boolean canBeReplay() { - return !isDone() && canRetry() && !isCancelled() && !(channel() != null && channel().isOpen() && uri.getScheme().compareToIgnoreCase("https") != 0) && !isInAuth(); + return !isDone() && canRetry() && !(channel != null && channel.isOpen() && uri.getScheme().compareToIgnoreCase("https") != 0) && !isInAuth(); } public long getStart() { diff --git a/src/main/java/com/ning/http/client/providers/netty/pool/DefaultChannelPool.java b/src/main/java/com/ning/http/client/providers/netty/pool/DefaultChannelPool.java index 4366aeaed4..a1b45ff6cf 100644 --- a/src/main/java/com/ning/http/client/providers/netty/pool/DefaultChannelPool.java +++ b/src/main/java/com/ning/http/client/providers/netty/pool/DefaultChannelPool.java @@ -152,12 +152,10 @@ private List expiredChannels(ConcurrentLinkedQueue poo } private boolean isChannelCloseable(Channel channel) { - boolean closeable = true; Object attachment = Channels.getAttachment(channel); if (attachment instanceof NettyResponseFuture) { NettyResponseFuture future = (NettyResponseFuture) attachment; - closeable = !future.isDone() || !future.isCancelled(); - if (!closeable) + if (!future.isDone()) LOGGER.error("Future not in appropriate state %s, not closing", future); } return true; diff --git a/src/main/java/com/ning/http/client/providers/netty/timeout/IdleConnectionTimeoutTimerTask.java b/src/main/java/com/ning/http/client/providers/netty/timeout/IdleConnectionTimeoutTimerTask.java index 66fac8e7d2..dbab00c72b 100644 --- a/src/main/java/com/ning/http/client/providers/netty/timeout/IdleConnectionTimeoutTimerTask.java +++ b/src/main/java/com/ning/http/client/providers/netty/timeout/IdleConnectionTimeoutTimerTask.java @@ -32,36 +32,31 @@ public IdleConnectionTimeoutTimerTask(NettyResponseFuture nettyResponseFuture } public void run(Timeout timeout) throws Exception { - if (provider.isClose()) { + + if (provider.isClose() || nettyResponseFuture.isDone()) { timeoutsHolder.cancel(); return; } - if (!nettyResponseFuture.isDone() && !nettyResponseFuture.isCancelled()) { - - long now = millisTime(); + long now = millisTime(); - long currentIdleConnectionTimeoutInstant = idleConnectionTimeout + nettyResponseFuture.getLastTouch(); - long durationBeforeCurrentIdleConnectionTimeout = currentIdleConnectionTimeoutInstant - now; + long currentIdleConnectionTimeoutInstant = idleConnectionTimeout + nettyResponseFuture.getLastTouch(); + long durationBeforeCurrentIdleConnectionTimeout = currentIdleConnectionTimeoutInstant - now; - if (durationBeforeCurrentIdleConnectionTimeout <= 0L) { - // idleConnectionTimeout reached - String message = "Idle connection timeout to " + nettyResponseFuture.getChannelRemoteAddress() + " of " + idleConnectionTimeout + " ms"; - long durationSinceLastTouch = now - nettyResponseFuture.getLastTouch(); - expire(message, durationSinceLastTouch); - nettyResponseFuture.setIdleConnectionTimeoutReached(); + if (durationBeforeCurrentIdleConnectionTimeout <= 0L) { + // idleConnectionTimeout reached + String message = "Idle connection timeout to " + nettyResponseFuture.getChannelRemoteAddress() + " of " + idleConnectionTimeout + " ms"; + long durationSinceLastTouch = now - nettyResponseFuture.getLastTouch(); + expire(message, durationSinceLastTouch); + nettyResponseFuture.setIdleConnectionTimeoutReached(); - } else if (currentIdleConnectionTimeoutInstant < requestTimeoutInstant) { - // reschedule - timeoutsHolder.idleConnectionTimeout = provider.newTimeoutInMs(this, durationBeforeCurrentIdleConnectionTimeout); - - } else { - // otherwise, no need to reschedule: requestTimeout will happen sooner - timeoutsHolder.idleConnectionTimeout = null; - } + } else if (currentIdleConnectionTimeoutInstant < requestTimeoutInstant) { + // reschedule + timeoutsHolder.idleConnectionTimeout = provider.newTimeoutInMs(this, durationBeforeCurrentIdleConnectionTimeout); } else { - timeoutsHolder.cancel(); + // otherwise, no need to reschedule: requestTimeout will happen sooner + timeoutsHolder.idleConnectionTimeout = null; } } -} \ No newline at end of file +} diff --git a/src/main/java/com/ning/http/client/providers/netty/timeout/RequestTimeoutTimerTask.java b/src/main/java/com/ning/http/client/providers/netty/timeout/RequestTimeoutTimerTask.java index ce7ea3bae8..236e8334f8 100644 --- a/src/main/java/com/ning/http/client/providers/netty/timeout/RequestTimeoutTimerTask.java +++ b/src/main/java/com/ning/http/client/providers/netty/timeout/RequestTimeoutTimerTask.java @@ -30,15 +30,13 @@ public void run(Timeout timeout) throws Exception { // in any case, cancel possible idleConnectionTimeout timeoutsHolder.cancel(); - if (provider.isClose()) { + if (provider.isClose() || nettyResponseFuture.isDone()) { return; } - if (!nettyResponseFuture.isDone() && !nettyResponseFuture.isCancelled()) { - String message = "Request timed out to " + nettyResponseFuture.getChannelRemoteAddress() + " of " + nettyResponseFuture.getRequestTimeoutInMs() + " ms"; - long age = millisTime() - nettyResponseFuture.getStart(); - expire(message, age); - nettyResponseFuture.setRequestTimeoutReached(); - } + String message = "Request timed out to " + nettyResponseFuture.getChannelRemoteAddress() + " of " + nettyResponseFuture.getRequestTimeoutInMs() + " ms"; + long age = millisTime() - nettyResponseFuture.getStart(); + expire(message, age); + nettyResponseFuture.setRequestTimeoutReached(); } } From 4d00c37a4f0cd3665f3f508f7e4d184ea7bedd0f Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 16 Jul 2014 23:11:14 +0200 Subject: [PATCH 419/701] Store attachements in the channel instead of the handler context --- .../http/client/providers/netty/Channels.java | 20 ++++++++----------- 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/Channels.java b/src/main/java/com/ning/http/client/providers/netty/Channels.java index c0d7474205..ec56cf9f76 100644 --- a/src/main/java/com/ning/http/client/providers/netty/Channels.java +++ b/src/main/java/com/ning/http/client/providers/netty/Channels.java @@ -23,28 +23,24 @@ public final class Channels { private Channels() { } - private static ChannelHandlerContext getAHCHandlerContext(Channel channel) { - return channel.getPipeline().getContext(NettyAsyncHttpProvider.class); + public static void setAttachment(ChannelHandlerContext ctx, Object attachment) { + setAttachment(ctx.getChannel(), attachment); } - public static Object getAttachment(ChannelHandlerContext ctx) { - return ctx.getAttachment(); + public static void setAttachment(Channel channel, Object attachment) { + channel.setAttachment(attachment); } - public static void setAttachment(ChannelHandlerContext ctx, Object attachment) { - ctx.setAttachment(attachment); + public static Object getAttachment(ChannelHandlerContext ctx) { + return getAttachment(ctx.getChannel()); } public static Object getAttachment(Channel channel) { - return getAHCHandlerContext(channel).getAttachment(); - } - - public static void setAttachment(Channel channel, Object attachment) { - setAttachment(getAHCHandlerContext(channel), attachment); + return channel.getAttachment(); } public static void setDiscard(ChannelHandlerContext ctx) { - ctx.setAttachment(DiscardEvent.INSTANCE); + setAttachment(ctx, DiscardEvent.INSTANCE); } public static void setDiscard(Channel channel) { From 820520d12c28eb8d0f2ffe909de8f6882ed1c47d Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 17 Jul 2014 00:01:21 +0200 Subject: [PATCH 420/701] Store attachments in channel instead of handler context --- .../http/client/providers/netty/Channels.java | 13 - .../netty/NettyAsyncHttpProvider.java | 344 ++++++++++-------- .../providers/netty/NettyConnectListener.java | 2 +- .../http/client/providers/netty/Protocol.java | 8 +- .../providers/netty/pool/ChannelManager.java | 20 +- 5 files changed, 200 insertions(+), 187 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/Channels.java b/src/main/java/com/ning/http/client/providers/netty/Channels.java index ec56cf9f76..7527d7a1b6 100644 --- a/src/main/java/com/ning/http/client/providers/netty/Channels.java +++ b/src/main/java/com/ning/http/client/providers/netty/Channels.java @@ -14,7 +14,6 @@ package com.ning.http.client.providers.netty; import org.jboss.netty.channel.Channel; -import org.jboss.netty.channel.ChannelHandlerContext; import com.ning.http.client.providers.netty.NettyAsyncHttpProvider.DiscardEvent; @@ -23,26 +22,14 @@ public final class Channels { private Channels() { } - public static void setAttachment(ChannelHandlerContext ctx, Object attachment) { - setAttachment(ctx.getChannel(), attachment); - } - public static void setAttachment(Channel channel, Object attachment) { channel.setAttachment(attachment); } - public static Object getAttachment(ChannelHandlerContext ctx) { - return getAttachment(ctx.getChannel()); - } - public static Object getAttachment(Channel channel) { return channel.getAttachment(); } - public static void setDiscard(ChannelHandlerContext ctx) { - setAttachment(ctx, DiscardEvent.INSTANCE); - } - public static void setDiscard(Channel channel) { setAttachment(channel, DiscardEvent.INSTANCE); } 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 dee6f84281..3774f76d66 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 @@ -157,7 +157,7 @@ public class NettyAsyncHttpProvider extends SimpleChannelUpstreamHandler impleme private static final String WEBSOCKET = "ws"; private static final String WEBSOCKET_SSL = "wss"; private static final Charset UTF8 = Charset.forName("UTF-8"); - + private final ClientBootstrap plainBootstrap; private final ClientBootstrap secureBootstrap; private final ClientBootstrap webSocketBootstrap; @@ -280,9 +280,10 @@ public ChannelPipeline getPipeline() throws Exception { SslHandler createSslHandler(String peerHost, int peerPort) throws GeneralSecurityException, IOException { SSLEngine sslEngine = SslUtils.getInstance().createClientSSLEngine(config, peerHost, peerPort); - return handshakeTimeoutInMillis > 0 ? new SslHandler(sslEngine, getDefaultBufferPool(), false, nettyTimer, handshakeTimeoutInMillis) : new SslHandler(sslEngine); + return handshakeTimeoutInMillis > 0 ? new SslHandler(sslEngine, getDefaultBufferPool(), false, nettyTimer, handshakeTimeoutInMillis) + : new SslHandler(sslEngine); } - + void constructSSLPipeline(final NettyConnectListener cl) { secureBootstrap.setPipelineFactory(new ChannelPipelineFactory() { @@ -461,7 +462,8 @@ protected final void writeRequest(final Channel channel, final AsyncHttpClie try { ChannelFuture writeFuture; if (disableZeroCopy || ssl) { - writeFuture = channel.write(new ChunkedFile(raf, 0, raf.length(), providerConfig.getChunkedFileChunkSize())); + writeFuture = channel + .write(new ChunkedFile(raf, 0, raf.length(), providerConfig.getChunkedFileChunkSize())); } else { final FileRegion region = new OptimizedFileRegion(raf, 0, raf.length()); writeFuture = channel.write(region); @@ -529,8 +531,8 @@ public void operationComplete(ChannelFuture cf) { int idleConnectionTimeoutInMs = config.getIdleConnectionTimeoutInMs(); if (idleConnectionTimeoutInMs != -1 && idleConnectionTimeoutInMs <= requestTimeoutInMs) { // no need for a idleConnectionTimeout that's less than the requestTimeoutInMs - Timeout idleConnectionTimeout = newTimeoutInMs(new IdleConnectionTimeoutTimerTask(future, this, timeoutsHolder, requestTimeoutInMs, idleConnectionTimeoutInMs), - idleConnectionTimeoutInMs); + Timeout idleConnectionTimeout = newTimeoutInMs(new IdleConnectionTimeoutTimerTask(future, this, timeoutsHolder, + requestTimeoutInMs, idleConnectionTimeoutInMs), idleConnectionTimeoutInMs); timeoutsHolder.idleConnectionTimeout = idleConnectionTimeout; } future.setTimeoutsHolder(timeoutsHolder); @@ -540,8 +542,8 @@ public void operationComplete(ChannelFuture cf) { } } - protected static final HttpRequest buildRequest(AsyncHttpClientConfig config, Request request, UriComponents uri, boolean allowConnect, ChannelBuffer buffer, ProxyServer proxyServer) - throws IOException { + protected static final HttpRequest buildRequest(AsyncHttpClientConfig config, Request request, UriComponents uri, boolean allowConnect, + ChannelBuffer buffer, ProxyServer proxyServer) throws IOException { String method = request.getMethod(); if (allowConnect && proxyServer != null && isSecure(uri)) { @@ -564,11 +566,12 @@ private static String computeNonConnectRequestPath(AsyncHttpClientConfig config, return uri.getQuery() != null ? path + "?" + uri.getQuery() : path; } } - - private static HttpRequest construct(AsyncHttpClientConfig config, Request request, HttpMethod m, UriComponents uri, ChannelBuffer buffer, ProxyServer proxyServer) throws IOException { + + private static HttpRequest construct(AsyncHttpClientConfig config, Request request, HttpMethod m, UriComponents uri, + ChannelBuffer buffer, ProxyServer proxyServer) throws IOException { HttpRequest nettyRequest; - + if (m.equals(HttpMethod.CONNECT)) { nettyRequest = new DefaultHttpRequest(HttpVersion.HTTP_1_0, m, AsyncHttpProviderUtils.getAuthority(uri)); } else { @@ -698,7 +701,8 @@ private static HttpRequest construct(AsyncHttpClientConfig config, Request reque } } } else { - nettyRequestHeaders.set(HttpHeaders.Names.PROXY_AUTHORIZATION, AuthenticatorUtils.computeBasicAuthentication(proxyServer)); + nettyRequestHeaders.set(HttpHeaders.Names.PROXY_AUTHORIZATION, + AuthenticatorUtils.computeBasicAuthentication(proxyServer)); } } } @@ -792,7 +796,8 @@ 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); } @@ -802,12 +807,14 @@ public ListenableFuture execute(Request request, final AsyncHandler as return doConnect(request, asyncHandler, null, true, false); } - private void execute(final Request request, final NettyResponseFuture f, boolean useCache, boolean reclaimCache) throws IOException { + private void execute(final Request request, final NettyResponseFuture f, boolean useCache, boolean reclaimCache) + throws IOException { doConnect(request, f.getAsyncHandler(), f, useCache, reclaimCache); } - private NettyResponseFuture buildNettyResponseFutureWithCachedChannel(Request request, AsyncHandler asyncHandler, NettyResponseFuture f, ProxyServer proxyServer, - UriComponents uri, ChannelBuffer bufferedBytes, int maxTry) throws IOException { + private NettyResponseFuture buildNettyResponseFutureWithCachedChannel(Request request, AsyncHandler asyncHandler, + NettyResponseFuture f, ProxyServer proxyServer, UriComponents uri, ChannelBuffer bufferedBytes, int maxTry) + throws IOException { for (int i = 0; i < maxTry; i++) { if (maxTry == 0) @@ -837,7 +844,7 @@ private NettyResponseFuture buildNettyResponseFutureWithCachedChannel(Req f.attachChannel(channel, false); if (channel.isOpen() && channel.isConnected()) { - f.channel().getPipeline().getContext(NettyAsyncHttpProvider.class).setAttachment(f); + Channels.setAttachment(channel, f); return f; } else // else, channel was closed by the server since we fetched it from the pool, starting over @@ -864,16 +871,16 @@ private NettyResponseFuture buildConnectListenerFuture(AsyncHttpClientCon return future; } } - - private ListenableFuture doConnect(final Request request, final AsyncHandler asyncHandler, NettyResponseFuture f, boolean useCache, - boolean reclaimCache) throws IOException { + + private ListenableFuture doConnect(final Request request, final AsyncHandler asyncHandler, NettyResponseFuture f, + boolean useCache, boolean reclaimCache) throws IOException { if (isClose()) { throw new IOException("Closed"); } UriComponents uri = request.getURI(); - + if (uri.getScheme().startsWith(WEBSOCKET) && !validateWebSocketRequest(request, asyncHandler)) { throw new IOException("WebSocket method must be a GET"); } @@ -884,7 +891,8 @@ private ListenableFuture doConnect(final Request request, final AsyncHand boolean useProxy = proxyServer != null && !resultOfAConnect; 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(); } @@ -892,7 +900,8 @@ private ListenableFuture doConnect(final Request request, final AsyncHand if (useCache) { // 3 tentatives - NettyResponseFuture connectedFuture = buildNettyResponseFutureWithCachedChannel(request, asyncHandler, f, proxyServer, uri, bufferedBytes, 3); + NettyResponseFuture connectedFuture = buildNettyResponseFutureWithCachedChannel(request, asyncHandler, f, proxyServer, uri, + bufferedBytes, 3); if (connectedFuture != null) { LOGGER.debug("\nUsing cached Channel {}\n for request \n{}\n", connectedFuture.channel(), connectedFuture.getNettyRequest()); @@ -919,7 +928,8 @@ private ListenableFuture doConnect(final Request request, final AsyncHand } } - NettyResponseFuture connectListenerFuture = buildConnectListenerFuture(config, request, asyncHandler, f, this, bufferedBytes, uri); + NettyResponseFuture connectListenerFuture = buildConnectListenerFuture(config, request, asyncHandler, f, this, bufferedBytes, + uri); boolean channelPreempted = false; String poolKey = null; @@ -930,7 +940,7 @@ private ListenableFuture doConnect(final Request request, final AsyncHand // only compute when maxConnectionPerHost is enabled // FIXME clean up if (config.getMaxConnectionPerHost() > 0) - poolKey = getPoolKey(connectListenerFuture); + poolKey = getPoolKey(connectListenerFuture); if (channelManager.preemptChannel(poolKey)) { channelPreempted = true; @@ -945,14 +955,15 @@ private ListenableFuture doConnect(final Request request, final AsyncHand } } - NettyConnectListener connectListener = new NettyConnectListener(config, connectListenerFuture, this, channelManager, channelPreempted, poolKey); + NettyConnectListener connectListener = new NettyConnectListener(config, connectListenerFuture, this, channelManager, + channelPreempted, poolKey); if (useSSl) constructSSLPipeline(connectListener); ChannelFuture channelFuture; - ClientBootstrap bootstrap = (request.getURI().getScheme().startsWith(WEBSOCKET) && !useProxy) ? (useSSl ? secureWebSocketBootstrap : webSocketBootstrap) : (useSSl ? secureBootstrap - : plainBootstrap); + ClientBootstrap bootstrap = (request.getURI().getScheme().startsWith(WEBSOCKET) && !useProxy) ? (useSSl ? secureWebSocketBootstrap + : webSocketBootstrap) : (useSSl ? secureBootstrap : plainBootstrap); bootstrap.setOption("connectTimeoutMillis", config.getConnectionTimeoutInMs()); try { @@ -988,7 +999,8 @@ public void messageReceived(final ChannelHandlerContext ctx, MessageEvent e) thr // call super to reset the read timeout super.messageReceived(ctx, e); - Object attachment = Channels.getAttachment(ctx); + Channel channel = ctx.getChannel(); + Object attachment = Channels.getAttachment(channel); if (attachment == null) LOGGER.debug("ChannelHandlerContext doesn't have any attachment"); @@ -1006,12 +1018,12 @@ public void messageReceived(final ChannelHandlerContext ctx, MessageEvent e) thr ac.call(); } else { ac.call(); - Channels.setDiscard(ctx); + Channels.setDiscard(channel); } } else if (attachment instanceof NettyResponseFuture) { Protocol p = (ctx.getPipeline().get(HTTP_PROCESSOR) != null ? httpProtocol : webSocketProtocol); - p.handle(ctx, e, NettyResponseFuture.class.cast(attachment)); + p.handle(channel, e, NettyResponseFuture.class.cast(attachment)); } else { // unhandled message @@ -1023,11 +1035,12 @@ public void messageReceived(final ChannelHandlerContext ctx, MessageEvent e) thr } } - private Realm kerberosChallenge(List proxyAuth, Request request, ProxyServer proxyServer, FluentCaseInsensitiveStringsMap headers, Realm realm, - NettyResponseFuture future, boolean proxyInd) throws NTLMEngineException { + private Realm kerberosChallenge(List proxyAuth, Request request, ProxyServer proxyServer, + FluentCaseInsensitiveStringsMap headers, Realm realm, NettyResponseFuture future, boolean proxyInd) + throws NTLMEngineException { UriComponents uri = request.getURI(); - String host = request.getVirtualHost() != null ? request.getVirtualHost(): uri.getHost(); + String host = request.getVirtualHost() != null ? request.getVirtualHost() : uri.getHost(); String server = proxyServer == null ? host : proxyServer.getHost(); try { String challengeHeader = getSpnegoEngine().generateToken(server); @@ -1050,15 +1063,15 @@ private Realm kerberosChallenge(List proxyAuth, Request request, ProxySe } private String authorizationHeaderName(boolean proxyInd) { - return proxyInd? HttpHeaders.Names.PROXY_AUTHORIZATION: HttpHeaders.Names.AUTHORIZATION; + return proxyInd ? HttpHeaders.Names.PROXY_AUTHORIZATION : HttpHeaders.Names.AUTHORIZATION; } - + private void addNTLMAuthorization(FluentCaseInsensitiveStringsMap headers, String challengeHeader, boolean proxyInd) { headers.add(authorizationHeaderName(proxyInd), "NTLM " + challengeHeader); } - private void addType3NTLMAuthorizationHeader(List auth, FluentCaseInsensitiveStringsMap headers, String username, String password, String domain, String workstation, boolean proxyInd) - throws NTLMEngineException { + private void addType3NTLMAuthorizationHeader(List auth, FluentCaseInsensitiveStringsMap headers, String username, + String password, String domain, String workstation, boolean proxyInd) throws NTLMEngineException { headers.remove(authorizationHeaderName(proxyInd)); // Beware of space!, see #462 @@ -1069,8 +1082,8 @@ private void addType3NTLMAuthorizationHeader(List auth, FluentCaseInsens } } - private Realm ntlmChallenge(List wwwAuth, Request request, ProxyServer proxyServer, FluentCaseInsensitiveStringsMap headers, Realm realm, NettyResponseFuture future, boolean proxyInd) - throws NTLMEngineException { + private Realm ntlmChallenge(List wwwAuth, Request request, ProxyServer proxyServer, FluentCaseInsensitiveStringsMap headers, + Realm realm, NettyResponseFuture future, boolean proxyInd) throws NTLMEngineException { boolean useRealm = (proxyServer == null && realm != null); @@ -1099,11 +1112,12 @@ private Realm ntlmChallenge(List wwwAuth, Request request, ProxyServer p return realmBuilder.setUri(uri).setMethodName(request.getMethod()).build(); } - 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); - addType3NTLMAuthorizationHeader(wwwAuth, headers, proxyServer.getPrincipal(), proxyServer.getPassword(), proxyServer.getNtlmDomain(), proxyServer.getHost(), true); + addType3NTLMAuthorizationHeader(wwwAuth, headers, proxyServer.getPrincipal(), proxyServer.getPassword(), + proxyServer.getNtlmDomain(), proxyServer.getHost(), true); Realm.RealmBuilder realmBuilder = new Realm.RealmBuilder(); if (realm != null) { @@ -1115,14 +1129,14 @@ private Realm ntlmProxyChallenge(List wwwAuth, Request request, ProxySer private String getPoolKey(NettyResponseFuture future) { return getPoolKey(future.getURI(), future.getProxyServer(), future.getConnectionPoolKeyStrategy()); } - + private String getPoolKey(UriComponents uri, ProxyServer proxy, ConnectionPoolKeyStrategy strategy) { String serverPart = strategy.getKey(uri); return proxy != null ? proxy.getUrl() + serverPart : serverPart; } - private void drainChannel(final ChannelHandlerContext ctx, final NettyResponseFuture future) { - ctx.setAttachment(newDrainCallable(future, ctx, future.getKeepAlive(), getPoolKey(future))); + private void drainChannel(final Channel channel, final NettyResponseFuture future) { + Channels.setAttachment(channel, newDrainCallable(future, channel, future.getKeepAlive(), getPoolKey(future))); } private FilterContext handleIoException(FilterContext fc, NettyResponseFuture future) { @@ -1139,7 +1153,7 @@ private FilterContext handleIoException(FilterContext fc, NettyResponseFut return fc; } - private void replayRequest(final NettyResponseFuture future, FilterContext fc, ChannelHandlerContext ctx) throws IOException { + private void replayRequest(final NettyResponseFuture future, FilterContext fc, Channel channel) throws IOException { if (future.getAsyncHandler() instanceof AsyncHandlerExtensions) { AsyncHandlerExtensions.class.cast(future.getAsyncHandler()).onRetry(); } @@ -1149,7 +1163,7 @@ private void replayRequest(final NettyResponseFuture future, FilterContext fc future.touch(); LOGGER.debug("\n\nReplaying Request {}\n for Future {}\n", newRequest, future); - drainChannel(ctx, future); + drainChannel(channel, future); nextRequest(newRequest, future); return; } @@ -1175,7 +1189,7 @@ private void nextRequest(final Request request, final NettyResponseFuture fut public void abort(NettyResponseFuture future, Throwable t) { Channel channel = future.channel(); if (channel != null) - channelManager.closeChannel(channel.getPipeline().getContext(NettyAsyncHttpProvider.class)); + channelManager.closeChannel(channel); if (!future.isDone()) { LOGGER.debug("Aborting Future {}\n", future); @@ -1213,7 +1227,8 @@ public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws return; } - channelManager.removeAll(ctx.getChannel()); + Channel channel = ctx.getChannel(); + channelManager.removeAll(channel); try { super.channelClosed(ctx, e); @@ -1221,12 +1236,12 @@ public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws LOGGER.trace("super.channelClosed", ex); } - Object attachment = Channels.getAttachment(ctx); - LOGGER.debug("Channel Closed: {} with attachment {}", e.getChannel(), attachment); + Object attachment = Channels.getAttachment(channel); + LOGGER.debug("Channel Closed: {} with attachment {}", channel, attachment); if (attachment instanceof AsyncCallable) { AsyncCallable ac = (AsyncCallable) attachment; - ctx.setAttachment(ac.future()); + Channels.setAttachment(channel, ac.future()); ac.call(); } else if (attachment instanceof NettyResponseFuture) { @@ -1234,21 +1249,21 @@ public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws future.touch(); if (!config.getIOExceptionFilters().isEmpty()) { - 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.canBeReplay()) { - replayRequest(future, fc, ctx); + replayRequest(future, fc, channel); return; } } Protocol p = (ctx.getPipeline().get(HttpClientCodec.class) != null ? httpProtocol : webSocketProtocol); - p.onClose(ctx, e); + p.onClose(channel, e); if (future == null || future.isDone()) - channelManager.closeChannel(ctx); + channelManager.closeChannel(channel); else if (remotelyClosed(ctx.getChannel(), future)) abort(future, REMOTELY_CLOSED_EXCEPTION); @@ -1283,14 +1298,14 @@ protected boolean remotelyClosed(Channel channel, NettyResponseFuture future) LOGGER.error("Remotely Closed, unable to recover", iox); return true; } - + } else { LOGGER.debug("Unable to recover future {}\n", future); return true; } } - private void markAsDone(final NettyResponseFuture future, final ChannelHandlerContext ctx) throws MalformedURLException { + private void markAsDone(final NettyResponseFuture future, final Channel channel) throws MalformedURLException { // We need to make sure everything is OK before adding the connection back to the pool. try { future.done(); @@ -1299,18 +1314,18 @@ private void markAsDone(final NettyResponseFuture future, final ChannelHandle LOGGER.debug(t.getMessage(), t); } - if (!future.getKeepAlive() || !ctx.getChannel().isReadable()) { - channelManager.closeChannel(ctx); + if (!future.getKeepAlive() || !channel.isReadable()) { + channelManager.closeChannel(channel); } } - private void finishUpdate(final NettyResponseFuture future, final ChannelHandlerContext ctx, boolean expectOtherChunks) throws IOException { + private void finishUpdate(final NettyResponseFuture future, Channel channel, boolean expectOtherChunks) throws IOException { boolean keepAlive = future.getKeepAlive(); if (expectOtherChunks && keepAlive) - drainChannel(ctx, future); + drainChannel(channel, future); else - channelManager.tryToOfferChannelToPool(ctx, keepAlive, getPoolKey(future)); - markAsDone(future, ctx); + channelManager.tryToOfferChannelToPool(channel, keepAlive, getPoolKey(future)); + markAsDone(future, channel); } private final boolean updateStatusAndInterrupt(AsyncHandler handler, HttpResponseStatus c) throws Exception { @@ -1321,7 +1336,8 @@ private final boolean updateHeadersAndInterrupt(AsyncHandler handler, HttpRes return handler.onHeadersReceived(c) != STATE.CONTINUE; } - private final boolean updateBodyAndInterrupt(final NettyResponseFuture future, AsyncHandler handler, HttpResponseBodyPart c) throws Exception { + private final boolean updateBodyAndInterrupt(final NettyResponseFuture future, AsyncHandler handler, HttpResponseBodyPart c) + throws Exception { boolean state = handler.onBodyPartReceived(c) != STATE.CONTINUE; if (c.closeUnderlyingConnection()) future.setKeepAlive(false); @@ -1336,7 +1352,7 @@ enum DiscardEvent { @Override public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { - Channel channel = e.getChannel(); + Channel channel = ctx.getChannel(); Throwable cause = e.getCause(); NettyResponseFuture future = null; @@ -1353,7 +1369,7 @@ public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws return; } - Object attachment = Channels.getAttachment(ctx); + Object attachment = Channels.getAttachment(channel); if (attachment instanceof NettyResponseFuture) { future = (NettyResponseFuture) attachment; future.attachChannel(null, false); @@ -1362,20 +1378,20 @@ public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws 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(); + FilterContext fc = new FilterContext.FilterContextBuilder().asyncHandler(future.getAsyncHandler()) + .request(future.getRequest()).ioException(new IOException("Channel Closed")).build(); fc = handleIoException(fc, future); if (fc.replayRequest()) { - replayRequest(future, fc, ctx); + replayRequest(future, fc, channel); return; } } else { // Close the channel so the recovering can occurs. try { - ctx.getChannel().close(); + channel.close(); } catch (Throwable t) { - ; // Swallow. + // Swallow. } return; } @@ -1401,10 +1417,10 @@ public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws } } - Protocol p = (ctx.getPipeline().get(HttpClientCodec.class) != null ? httpProtocol : webSocketProtocol); - p.onError(ctx, e); + Protocol p = channel.getPipeline().get(HttpClientCodec.class) != null ? httpProtocol : webSocketProtocol; + p.onError(channel, e); - channelManager.closeChannel(ctx); + channelManager.closeChannel(channel); ctx.sendUpstream(e); } @@ -1428,7 +1444,8 @@ 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; } } @@ -1472,8 +1489,8 @@ protected static boolean abortOnWriteCloseException(Throwable cause) { return false; } - public static NettyResponseFuture newFuture(UriComponents uri, Request request, AsyncHandler asyncHandler, HttpRequest nettyRequest, AsyncHttpClientConfig config, - NettyAsyncHttpProvider provider, ProxyServer proxyServer) { + public static NettyResponseFuture newFuture(UriComponents uri, Request request, AsyncHandler asyncHandler, + HttpRequest nettyRequest, AsyncHttpClientConfig config, NettyAsyncHttpProvider provider, ProxyServer proxyServer) { NettyResponseFuture f = new NettyResponseFuture(uri,// request,// @@ -1543,7 +1560,8 @@ public void operationComplete(ChannelFuture cf) { * 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(); + Realm realm = future.getRequest().getRealm() != null ? future.getRequest().getRealm() : NettyAsyncHttpProvider.this.getConfig() + .getRealm(); boolean startPublishing = future.isInAuth() || realm == null || realm.getUsePreemptiveAuth(); if (startPublishing && asyncHandler instanceof ProgressAsyncHandler) { @@ -1693,9 +1711,11 @@ private static final boolean validateWebSocketRequest(Request request, AsyncHand return true; } - private boolean exitAfterHandlingRedirect(ChannelHandlerContext ctx, NettyResponseFuture future, Request request, HttpResponse response, int statusCode) throws Exception { + private boolean exitAfterHandlingRedirect(Channel channel, NettyResponseFuture future, Request request, HttpResponse response, + int statusCode) throws Exception { - if (AsyncHttpProviderUtils.followRedirect(config, request) && (statusCode == 302 || statusCode == 301 || statusCode == 303 || statusCode == 307)) { + if (AsyncHttpProviderUtils.followRedirect(config, request) + && (statusCode == 302 || statusCode == 301 || statusCode == 303 || statusCode == 307)) { if (future.incrementAndGetCurrentRedirectCount() < config.getMaxRedirects()) { // allow 401 handling again @@ -1712,7 +1732,7 @@ private boolean exitAfterHandlingRedirect(ChannelHandlerContext ctx, NettyRespon nBuilder.resetQuery(); else nBuilder.addQueryParams(future.getRequest().getQueryParams()); - + if (!(statusCode < 302 || statusCode > 303) && !(statusCode == 302 && config.isStrict302Handling())) { nBuilder.setMethod("GET"); } @@ -1723,7 +1743,8 @@ private boolean exitAfterHandlingRedirect(ChannelHandlerContext ctx, NettyRespon String targetScheme = request.getURI().getScheme(); if (targetScheme.equals(WEBSOCKET)) { newURI = newURI.withNewScheme(WEBSOCKET); - }if (targetScheme.equals(WEBSOCKET_SSL)) { + } + if (targetScheme.equals(WEBSOCKET_SSL)) { newURI = newURI.withNewScheme(WEBSOCKET_SSL); } @@ -1737,11 +1758,11 @@ private boolean exitAfterHandlingRedirect(ChannelHandlerContext ctx, NettyRespon nBuilder.addOrReplaceCookie(CookieDecoder.decode(cookieStr)); } - AsyncCallable ac = newDrainCallable(future, ctx, initialConnectionKeepAlive, initialPoolKey); + AsyncCallable ac = newDrainCallable(future, channel, initialConnectionKeepAlive, initialPoolKey); if (response.isChunked()) { // We must make sure there is no bytes left before executing the next request. - ctx.setAttachment(ac); + Channels.setAttachment(channel, ac); } else { ac.call(); } @@ -1755,11 +1776,12 @@ private boolean exitAfterHandlingRedirect(ChannelHandlerContext ctx, NettyRespon return false; } - private final AsyncCallable newDrainCallable(final NettyResponseFuture future, final ChannelHandlerContext ctx, final boolean keepAlive, final String poolKey) { - + private final AsyncCallable newDrainCallable(final NettyResponseFuture future, final Channel channel, final boolean keepAlive, + final String poolKey) { + return new AsyncCallable(future) { public Object call() throws Exception { - channelManager.tryToOfferChannelToPool(ctx, keepAlive, poolKey); + channelManager.tryToOfferChannelToPool(channel, keepAlive, poolKey); return null; } }; @@ -1770,7 +1792,8 @@ private final void configureKeepAlive(NettyResponseFuture future, HttpRespons future.setKeepAlive(connectionHeader == null || connectionHeader.equalsIgnoreCase(HttpHeaders.Values.KEEP_ALIVE)); } - private final boolean exitAfterProcessingFilters(ChannelHandlerContext ctx, NettyResponseFuture future, HttpResponse response, AsyncHandler handler, Request request, HttpResponseStatus status, HttpResponseHeaders responseHeaders) throws IOException { + private final boolean exitAfterProcessingFilters(Channel channel, NettyResponseFuture future, HttpResponse response, + AsyncHandler handler, Request request, HttpResponseStatus status, HttpResponseHeaders responseHeaders) throws IOException { if (!config.getResponseFilters().isEmpty()) { FilterContext fc = new FilterContext.FilterContextBuilder().asyncHandler(handler).request(request).responseStatus(status) .responseHeaders(responseHeaders).build(); @@ -1791,7 +1814,7 @@ private final boolean exitAfterProcessingFilters(ChannelHandlerContext ctx, Nett // The request has changed if (fc.replayRequest()) { - replayRequest(future, fc, ctx); + replayRequest(future, fc, channel); return true; } } @@ -1799,7 +1822,7 @@ private final boolean exitAfterProcessingFilters(ChannelHandlerContext ctx, Nett } private final boolean exitAfterHandling401(// - final ChannelHandlerContext ctx,// + final Channel channel,// final NettyResponseFuture future,// HttpResponse response,// Request request,// @@ -1843,7 +1866,7 @@ private final boolean exitAfterHandling401(// AsyncCallable ac = new AsyncCallable(future) { public Object call() throws Exception { // not waiting for the channel to be drained, so we might ended up pooling the initial channel and creating a new one - drainChannel(ctx, future); + drainChannel(channel, future); nextRequest(nextRequest, future); return null; } @@ -1851,7 +1874,7 @@ public Object call() throws Exception { if (future.getKeepAlive() && response.isChunked()) // we must make sure there is no chunk left before executing the next request - ctx.setAttachment(ac); + Channels.setAttachment(channel, ac); else // FIXME couldn't we reuse the channel right now? ac.call(); @@ -1860,7 +1883,7 @@ public Object call() throws Exception { } return false; } - + private final boolean exitAfterHandling407(// NettyResponseFuture future,// HttpResponse response,// @@ -1907,18 +1930,17 @@ private final boolean exitAfterHandling407(// return false; } - - private boolean exitAfterHandling100(ChannelHandlerContext ctx, NettyResponseFuture future, int statusCode) { + private boolean exitAfterHandling100(Channel channel, NettyResponseFuture future, int statusCode) { if (statusCode == 100) { future.getAndSetWriteHeaders(false); future.getAndSetWriteBody(true); - writeRequest(ctx.getChannel(), config, future); + writeRequest(channel, config, future); return true; } return false; } - private boolean exitAfterHandlingConnect(ChannelHandlerContext ctx,// + private boolean exitAfterHandlingConnect(Channel channel,// NettyResponseFuture future,// Request request,// ProxyServer proxyServer,// @@ -1931,7 +1953,7 @@ private boolean exitAfterHandlingConnect(ChannelHandlerContext ctx,// LOGGER.debug("Connected to {}:{}", proxyServer.getHost(), proxyServer.getPort()); if (future.getKeepAlive()) { - future.attachChannel(ctx.getChannel(), true); + future.attachChannel(channel, true); } try { @@ -1941,7 +1963,7 @@ private boolean exitAfterHandlingConnect(ChannelHandlerContext ctx,// int port = AsyncHttpProviderUtils.getDefaultPort(requestURI); LOGGER.debug("Connecting to proxy {} for scheme {}", proxyServer, scheme); - upgradeProtocol(ctx.getChannel().getPipeline(), scheme, host, port); + upgradeProtocol(channel.getPipeline(), scheme, host, port); } catch (Throwable ex) { abort(future, ex); @@ -1954,48 +1976,53 @@ private boolean exitAfterHandlingConnect(ChannelHandlerContext ctx,// } return false; } - - private final boolean exitAfterHandlingStatus(ChannelHandlerContext ctx, NettyResponseFuture future, HttpResponse response, AsyncHandler handler, HttpResponseStatus status) throws IOException, Exception { + + private final boolean exitAfterHandlingStatus(Channel channel, NettyResponseFuture future, HttpResponse response, + AsyncHandler handler, HttpResponseStatus status) throws IOException, Exception { if (!future.getAndSetStatusReceived(true) && updateStatusAndInterrupt(handler, status)) { - finishUpdate(future, ctx, response.isChunked()); + finishUpdate(future, channel, response.isChunked()); return true; } return false; } - - private final boolean exitAfterHandlingHeaders(ChannelHandlerContext ctx, NettyResponseFuture future, HttpResponse response, AsyncHandler handler, HttpResponseHeaders responseHeaders) throws IOException, Exception { + + private final boolean exitAfterHandlingHeaders(Channel channel, NettyResponseFuture future, HttpResponse response, + AsyncHandler handler, HttpResponseHeaders responseHeaders) throws IOException, Exception { if (!response.headers().isEmpty() && updateHeadersAndInterrupt(handler, responseHeaders)) { - finishUpdate(future, ctx, response.isChunked()); + finishUpdate(future, channel, response.isChunked()); return true; } return false; } - - private final boolean exitAfterHandlingBody(ChannelHandlerContext ctx, NettyResponseFuture future, HttpResponse response, AsyncHandler handler) throws Exception { + + private final boolean exitAfterHandlingBody(Channel channel, NettyResponseFuture future, HttpResponse response, + AsyncHandler handler) throws Exception { if (!response.isChunked()) { updateBodyAndInterrupt(future, handler, new ResponseBodyPart(future.getURI(), response, NettyAsyncHttpProvider.this, true)); - finishUpdate(future, ctx, false); + finishUpdate(future, channel, false); return true; } return false; } - - private final boolean exitAfterHandlingHead(ChannelHandlerContext ctx, NettyResponseFuture future, HttpResponse response, AsyncHandler handler, HttpRequest nettyRequest) throws Exception { + + private final boolean exitAfterHandlingHead(Channel channel, NettyResponseFuture future, HttpResponse response, + AsyncHandler handler, HttpRequest nettyRequest) 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); + markAsDone(future, channel); + drainChannel(channel, future); } return false; } - - private final void handleHttpResponse(final HttpResponse response, final ChannelHandlerContext ctx, final NettyResponseFuture future, AsyncHandler handler) throws Exception { + + private final void handleHttpResponse(final HttpResponse response, final Channel channel, + final NettyResponseFuture future, AsyncHandler handler) throws Exception { HttpRequest nettyRequest = future.getNettyRequest(); Request request = future.getRequest(); ProxyServer proxyServer = future.getProxyServer(); LOGGER.debug("\n\nRequest {}\n\nResponse {}\n", nettyRequest, response); - + // Required if there is some trailing headers. future.setHttpResponse(response); @@ -2003,8 +2030,8 @@ private final void handleHttpResponse(final HttpResponse response, final Channel HttpResponseStatus status = new ResponseStatus(future.getURI(), response, NettyAsyncHttpProvider.this); HttpResponseHeaders responseHeaders = new ResponseHeaders(future.getURI(), response, NettyAsyncHttpProvider.this); - - if (exitAfterProcessingFilters(ctx, future, response, handler, request, status, responseHeaders)) + + if (exitAfterProcessingFilters(channel, future, response, handler, request, status, responseHeaders)) return; final RequestBuilder requestBuilder = new RequestBuilder(future.getRequest()); @@ -2014,20 +2041,21 @@ private final void handleHttpResponse(final HttpResponse response, final Channel int statusCode = response.getStatus().getCode(); // FIXME - if (exitAfterHandling401(ctx, future, response, request, statusCode, realm, proxyServer, requestBuilder) || // + if (exitAfterHandling401(channel, future, response, request, statusCode, realm, proxyServer, requestBuilder) || // exitAfterHandling407(future, response, request, statusCode, realm, proxyServer, requestBuilder) || // - exitAfterHandling100(ctx, future, statusCode) || // - exitAfterHandlingRedirect(ctx, future, request, response, statusCode) || // - exitAfterHandlingConnect(ctx, future, request, proxyServer, statusCode, requestBuilder, nettyRequest) || // - exitAfterHandlingStatus(ctx, future, response, handler, status) || // - exitAfterHandlingHeaders(ctx, future, response, handler, responseHeaders) || // - exitAfterHandlingBody(ctx, future, response, handler) || // - exitAfterHandlingHead(ctx, future, response, handler, nettyRequest)) { + exitAfterHandling100(channel, future, statusCode) || // + exitAfterHandlingRedirect(channel, future, request, response, statusCode) || // + exitAfterHandlingConnect(channel, future, request, proxyServer, statusCode, requestBuilder, nettyRequest) || // + exitAfterHandlingStatus(channel, future, response, handler, status) || // + exitAfterHandlingHeaders(channel, future, response, handler, responseHeaders) || // + exitAfterHandlingBody(channel, future, response, handler) || // + exitAfterHandlingHead(channel, future, response, handler, nettyRequest)) { return; } } - private final void handleChunk(final HttpChunk chunk, final ChannelHandlerContext ctx, final NettyResponseFuture future, final AsyncHandler handler) throws Exception { + private final void handleChunk(final HttpChunk chunk, final Channel channel, final NettyResponseFuture future, + final AsyncHandler handler) throws Exception { boolean last = chunk.isLast(); // we don't notify updateBodyAndInterrupt with the last chunk as it's empty if (last || updateBodyAndInterrupt(future, handler, new ResponseBodyPart(future.getURI(), null, this, chunk, last))) { @@ -2039,16 +2067,17 @@ private final void handleChunk(final HttpChunk chunk, final ChannelHandlerContex updateHeadersAndInterrupt(handler, responseHeaders); } } - finishUpdate(future, ctx, !chunk.isLast()); + finishUpdate(future, channel, !chunk.isLast()); } } + private final class HttpProtocol implements Protocol { - public void handle(final ChannelHandlerContext ctx, final MessageEvent e, final NettyResponseFuture future) throws Exception { + public void handle(final Channel channel, final MessageEvent e, final NettyResponseFuture future) throws Exception { // The connect timeout occurred. if (future.isDone()) { - channelManager.closeChannel(ctx); + channelManager.closeChannel(channel); return; } @@ -2058,10 +2087,10 @@ public void handle(final ChannelHandlerContext ctx, final MessageEvent e, final Object message = e.getMessage(); try { if (message instanceof HttpResponse) - handleHttpResponse((HttpResponse) message, ctx, future, handler); + handleHttpResponse((HttpResponse) message, channel, future, handler); else if (message instanceof HttpChunk) - handleChunk((HttpChunk) message, ctx, future, handler); + handleChunk((HttpChunk) message, channel, future, handler); } catch (Exception t) { if (t instanceof IOException && !config.getIOExceptionFilters().isEmpty()) { @@ -2070,7 +2099,7 @@ else if (message instanceof HttpChunk) fc = handleIoException(fc, future); if (fc.replayRequest()) { - replayRequest(future, fc, ctx); + replayRequest(future, fc, channel); return; } } @@ -2078,16 +2107,16 @@ else if (message instanceof HttpChunk) try { abort(future, t); } finally { - finishUpdate(future, ctx, false); + finishUpdate(future, channel, false); throw t; } } } - public void onError(ChannelHandlerContext ctx, ExceptionEvent e) { + public void onError(Channel channel, ExceptionEvent e) { } - public void onClose(ChannelHandlerContext ctx, ChannelStateEvent e) { + public void onClose(Channel channel, ChannelStateEvent e) { } } @@ -2098,10 +2127,10 @@ private final class WebSocketProtocol implements Protocol { private static final byte OPCODE_UNKNOWN = -1; // We don't need to synchronize as replacing the "ws-decoder" will process using the same thread. - private void invokeOnSucces(ChannelHandlerContext ctx, WebSocketUpgradeHandler h) { + private void invokeOnSucces(Channel channel, WebSocketUpgradeHandler h) { if (!h.touchSuccess()) { try { - h.onSuccess(new NettyWebSocket(ctx.getChannel())); + h.onSuccess(new NettyWebSocket(channel)); } catch (Exception ex) { NettyAsyncHttpProvider.this.LOGGER.warn("onSuccess unexexpected exception", ex); } @@ -2109,7 +2138,7 @@ private void invokeOnSucces(ChannelHandlerContext ctx, WebSocketUpgradeHandler h } // @Override - public void handle(ChannelHandlerContext ctx, MessageEvent e, final NettyResponseFuture future) throws Exception { + public void handle(Channel channel, MessageEvent e, final NettyResponseFuture future) throws Exception { WebSocketUpgradeHandler wsUpgradeHandler = (WebSocketUpgradeHandler) future.getAsyncHandler(); Request request = future.getRequest(); @@ -2120,7 +2149,8 @@ public void handle(ChannelHandlerContext ctx, MessageEvent e, final NettyRespons HttpResponseStatus s = new ResponseStatus(future.getURI(), response, NettyAsyncHttpProvider.this); HttpResponseHeaders responseHeaders = new ResponseHeaders(future.getURI(), response, NettyAsyncHttpProvider.this); - FilterContext fc = new FilterContext.FilterContextBuilder().asyncHandler(wsUpgradeHandler).request(request).responseStatus(s).responseHeaders(responseHeaders).build(); + FilterContext fc = new FilterContext.FilterContextBuilder().asyncHandler(wsUpgradeHandler).request(request) + .responseStatus(s).responseHeaders(responseHeaders).build(); for (ResponseFilter asyncFilter : config.getResponseFilters()) { try { fc = asyncFilter.filter(fc); @@ -2137,15 +2167,16 @@ public void handle(ChannelHandlerContext ctx, MessageEvent e, final NettyRespons // The request has changed if (fc.replayRequest()) { - replayRequest(future, fc, ctx); + replayRequest(future, fc, channel); return; } future.setHttpResponse(response); - if (exitAfterHandlingRedirect(ctx, future, request, response, response.getStatus().getCode())) + if (exitAfterHandlingRedirect(channel, future, request, response, response.getStatus().getCode())) 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 = nettyResponseHeaders.contains(HttpHeaders.Names.UPGRADE); @@ -2181,14 +2212,14 @@ public void handle(ChannelHandlerContext ctx, MessageEvent e, final NettyRespons return; } - ctx.getPipeline().replace(HTTP_HANDLER, "ws-encoder", new WebSocket08FrameEncoder(true)); - ctx.getPipeline().addBefore(WS_PROCESSOR, "ws-decoder", new WebSocket08FrameDecoder(false, false)); + channel.getPipeline().replace(HTTP_HANDLER, "ws-encoder", new WebSocket08FrameEncoder(true)); + channel.getPipeline().addBefore(WS_PROCESSOR, "ws-decoder", new WebSocket08FrameDecoder(false, false)); - invokeOnSucces(ctx, wsUpgradeHandler); + invokeOnSucces(channel, wsUpgradeHandler); future.done(); } else if (e.getMessage() instanceof WebSocketFrame) { - invokeOnSucces(ctx, wsUpgradeHandler); + invokeOnSucces(channel, wsUpgradeHandler); final WebSocketFrame frame = (WebSocketFrame) e.getMessage(); @@ -2234,8 +2265,9 @@ public void setContent(ChannelBuffer content) { if (frame instanceof CloseWebSocketFrame) { try { - Channels.setDiscard(ctx); - webSocket.onClose(CloseWebSocketFrame.class.cast(frame).getStatusCode(), CloseWebSocketFrame.class.cast(frame).getReasonText()); + Channels.setDiscard(channel); + webSocket.onClose(CloseWebSocketFrame.class.cast(frame).getStatusCode(), + CloseWebSocketFrame.class.cast(frame).getReasonText()); } finally { wsUpgradeHandler.resetSuccess(); } @@ -2250,9 +2282,9 @@ public void setContent(ChannelBuffer content) { } // @Override - public void onError(ChannelHandlerContext ctx, ExceptionEvent e) { + public void onError(Channel channel, ExceptionEvent e) { try { - Object attachment = Channels.getAttachment(ctx); + Object attachment = Channels.getAttachment(channel); LOGGER.warn("onError {}", e); if (!(attachment instanceof NettyResponseFuture)) { return; @@ -2272,10 +2304,10 @@ public void onError(ChannelHandlerContext ctx, ExceptionEvent e) { } // @Override - public void onClose(ChannelHandlerContext ctx, ChannelStateEvent e) { + public void onClose(Channel channel, ChannelStateEvent e) { LOGGER.trace("onClose {}", e); - - Object attachment = Channels.getAttachment(ctx); + + Object attachment = Channels.getAttachment(channel); if (attachment instanceof NettyResponseFuture) { try { NettyResponseFuture nettyResponse = (NettyResponseFuture) attachment; 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 0145531f7f..1401e4ecd3 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 @@ -89,7 +89,7 @@ private void writeRequest(Channel channel, String poolKey) { public final void operationComplete(ChannelFuture f) throws Exception { Channel channel = f.getChannel(); if (f.isSuccess()) { - channel.getPipeline().getContext(NettyAsyncHttpProvider.class).setAttachment(future); + Channels.setAttachment(channel, future); final SslHandler sslHandler = (SslHandler) channel.getPipeline().get(NettyAsyncHttpProvider.SSL_HANDLER); final HostnameVerifier hostnameVerifier = config.getHostnameVerifier(); diff --git a/src/main/java/com/ning/http/client/providers/netty/Protocol.java b/src/main/java/com/ning/http/client/providers/netty/Protocol.java index edf62a96cb..76bb54c548 100644 --- a/src/main/java/com/ning/http/client/providers/netty/Protocol.java +++ b/src/main/java/com/ning/http/client/providers/netty/Protocol.java @@ -12,16 +12,16 @@ */ package com.ning.http.client.providers.netty; -import org.jboss.netty.channel.ChannelHandlerContext; +import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.MessageEvent; public interface Protocol { - void handle(ChannelHandlerContext ctx, MessageEvent e, NettyResponseFuture future) throws Exception; + void handle(Channel channel, MessageEvent e, NettyResponseFuture future) throws Exception; - void onError(ChannelHandlerContext ctx, ExceptionEvent e); + void onError(Channel channel, ExceptionEvent e); - void onClose(ChannelHandlerContext ctx, ChannelStateEvent e); + void onClose(Channel channel, ChannelStateEvent e); } diff --git a/src/main/java/com/ning/http/client/providers/netty/pool/ChannelManager.java b/src/main/java/com/ning/http/client/providers/netty/pool/ChannelManager.java index 347cd4be33..2c881c77b0 100644 --- a/src/main/java/com/ning/http/client/providers/netty/pool/ChannelManager.java +++ b/src/main/java/com/ning/http/client/providers/netty/pool/ChannelManager.java @@ -14,7 +14,6 @@ package com.ning.http.client.providers.netty.pool; import org.jboss.netty.channel.Channel; -import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.group.ChannelGroup; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -22,7 +21,6 @@ import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.providers.netty.Channels; import com.ning.http.client.providers.netty.CleanupChannelGroup; -import com.ning.http.client.providers.netty.NettyAsyncHttpProvider; import com.ning.http.client.providers.netty.NettyResponseFuture; import java.util.concurrent.ConcurrentHashMap; @@ -83,17 +81,16 @@ public boolean remove(Object o) { } } - public final void tryToOfferChannelToPool(ChannelHandlerContext ctx, boolean keepAlive, String poolKey) { - Channel channel = ctx.getChannel(); + public final void tryToOfferChannelToPool(Channel channel, boolean keepAlive, String poolKey) { if (keepAlive && channel.isReadable()) { LOGGER.debug("Adding key: {} for channel {}", poolKey, channel); channelPool.offer(channel, poolKey); if (maxConnectionsPerHostEnabled) channelId2KeyPool.putIfAbsent(channel.getId(), poolKey); - Channels.setDiscard(ctx); + Channels.setDiscard(channel); } else { // not offered - closeChannel(ctx); + closeChannel(channel); } } @@ -134,8 +131,7 @@ public void destroy() { openChannels.close(); for (Channel channel : openChannels) { - ChannelHandlerContext ctx = channel.getPipeline().getContext(NettyAsyncHttpProvider.class); - Object attachment = Channels.getAttachment(ctx); + Object attachment = Channels.getAttachment(channel); if (attachment instanceof NettyResponseFuture) { NettyResponseFuture future = (NettyResponseFuture) attachment; future.cancelTimeouts(); @@ -143,11 +139,9 @@ public void destroy() { } } - public void closeChannel(final ChannelHandlerContext ctx) { - removeAll(ctx.getChannel()); - Channels.setDiscard(ctx); - - Channel channel = ctx.getChannel(); + public void closeChannel(Channel channel) { + removeAll(channel); + Channels.setDiscard(channel); // The channel may have already been removed if a timeout occurred, and this method may be called just after. if (channel != null) { From 9f3f26083a4bde66bb831d337ff13498d2121aa0 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 17 Jul 2014 00:03:45 +0200 Subject: [PATCH 421/701] Rename NettyResponseFuture.getKeepAlive into isKeepAlive --- .../providers/netty/NettyAsyncHttpProvider.java | 12 ++++++------ .../client/providers/netty/NettyResponseFuture.java | 2 +- 2 files changed, 7 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 3774f76d66..f6bb42e261 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 @@ -1136,7 +1136,7 @@ private String getPoolKey(UriComponents uri, ProxyServer proxy, ConnectionPoolKe } private void drainChannel(final Channel channel, final NettyResponseFuture future) { - Channels.setAttachment(channel, newDrainCallable(future, channel, future.getKeepAlive(), getPoolKey(future))); + Channels.setAttachment(channel, newDrainCallable(future, channel, future.isKeepAlive(), getPoolKey(future))); } private FilterContext handleIoException(FilterContext fc, NettyResponseFuture future) { @@ -1314,13 +1314,13 @@ private void markAsDone(final NettyResponseFuture future, final Channel chann LOGGER.debug(t.getMessage(), t); } - if (!future.getKeepAlive() || !channel.isReadable()) { + if (!future.isKeepAlive() || !channel.isReadable()) { channelManager.closeChannel(channel); } } private void finishUpdate(final NettyResponseFuture future, Channel channel, boolean expectOtherChunks) throws IOException { - boolean keepAlive = future.getKeepAlive(); + boolean keepAlive = future.isKeepAlive(); if (expectOtherChunks && keepAlive) drainChannel(channel, future); else @@ -1736,7 +1736,7 @@ private boolean exitAfterHandlingRedirect(Channel channel, NettyResponseFuture 303) && !(statusCode == 302 && config.isStrict302Handling())) { nBuilder.setMethod("GET"); } - final boolean initialConnectionKeepAlive = future.getKeepAlive(); + final boolean initialConnectionKeepAlive = future.isKeepAlive(); final String initialPoolKey = getPoolKey(future); future.setURI(uri); UriComponents newURI = uri; @@ -1872,7 +1872,7 @@ public Object call() throws Exception { } }; - if (future.getKeepAlive() && response.isChunked()) + if (future.isKeepAlive() && response.isChunked()) // we must make sure there is no chunk left before executing the next request Channels.setAttachment(channel, ac); else @@ -1952,7 +1952,7 @@ private boolean exitAfterHandlingConnect(Channel channel,// LOGGER.debug("Connected to {}:{}", proxyServer.getHost(), proxyServer.getPort()); - if (future.getKeepAlive()) { + if (future.isKeepAlive()) { future.attachChannel(channel, true); } 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 09fee154de..4453b7bd43 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 @@ -369,7 +369,7 @@ protected final AsyncHandler getAsyncHandler() { return asyncHandler; } - protected final boolean getKeepAlive() { + protected final boolean isKeepAlive() { return keepAlive; } From 38aab02a19185ea8934b2b0acd4dafee2eeaab3e Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 17 Jul 2014 00:06:18 +0200 Subject: [PATCH 422/701] Rename remotelyClosed into retry and invert returned boolean --- .../providers/netty/NettyAsyncHttpProvider.java | 12 ++++++------ .../client/providers/netty/NettyConnectListener.java | 3 +-- 2 files changed, 7 insertions(+), 8 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 f6bb42e261..e19327e79b 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 @@ -1265,15 +1265,15 @@ public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws if (future == null || future.isDone()) channelManager.closeChannel(channel); - else if (remotelyClosed(ctx.getChannel(), future)) + else if (!retry(ctx.getChannel(), future)) abort(future, REMOTELY_CLOSED_EXCEPTION); } } - protected boolean remotelyClosed(Channel channel, NettyResponseFuture future) { + protected boolean retry(Channel channel, NettyResponseFuture future) { if (isClose()) - return true; + return false; if (future == null) { Object attachment = Channels.getAttachment(channel); @@ -1290,18 +1290,18 @@ protected boolean remotelyClosed(Channel channel, NettyResponseFuture future) try { nextRequest(future.getRequest(), future); - return false; + return true; } catch (IOException iox) { future.setState(NettyResponseFuture.STATE.CLOSED); future.abort(iox); LOGGER.error("Remotely Closed, unable to recover", iox); - return true; + return false; } } else { LOGGER.debug("Unable to recover future {}\n", future); - return true; + return false; } } 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 1401e4ecd3..6eb82e76ae 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 @@ -133,9 +133,8 @@ public void operationComplete(ChannelFuture handshakeFuture) throws Exception { .getState() != NettyResponseFuture.STATE.NEW)) { LOGGER.debug("Retrying {} ", nettyRequest); - if (provider.remotelyClosed(channel, future)) { + if (!provider.retry(channel, future)) return; - } } LOGGER.debug("Failed to recover from exception: {} with channel {}", cause, f.getChannel()); From a5f36f976ef1112b20ba84f9e34330b8160b5484 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 17 Jul 2014 00:55:48 +0200 Subject: [PATCH 423/701] Make sure all test clients are properly CLOSED!!! + minor clean up --- .../client/async/AsyncProvidersBasicTest.java | 2 +- .../client/async/AsyncStreamHandlerTest.java | 60 +-- .../async/AsyncStreamLifecycleTest.java | 2 - .../http/client/async/AuthTimeoutTest.java | 36 +- .../ning/http/client/async/BasicAuthTest.java | 17 +- .../http/client/async/BasicHttpsTest.java | 36 +- .../client/async/ByteBufferCapacityTest.java | 6 +- .../ning/http/client/async/ChunkingTest.java | 28 +- .../http/client/async/ComplexClientTest.java | 14 +- .../http/client/async/ConnectionPoolTest.java | 16 +- .../ning/http/client/async/EmptyBodyTest.java | 12 +- .../ning/http/client/async/FilterTest.java | 24 +- .../client/async/FollowingThreadTest.java | 9 +- .../client/async/HttpToHttpsRedirectTest.java | 24 +- .../client/async/IdleStateHandlerTest.java | 6 +- .../http/client/async/InputStreamTest.java | 6 +- .../client/async/ListenableFutureTest.java | 6 +- .../client/async/MultipartUploadTest.java | 12 +- .../http/client/async/MultipleHeaderTest.java | 12 +- .../async/NonAsciiContentLengthTest.java | 1 - .../async/PerRequestRelative302Test.java | 24 +- .../client/async/PostRedirectGetTest.java | 12 +- .../com/ning/http/client/async/ProxyTest.java | 1 - .../client/async/ProxyTunnellingTest.java | 12 +- .../client/async/QueryParametersTest.java | 13 +- .../com/ning/http/client/async/RC10KTest.java | 6 +- .../async/RedirectConnectionUsageTest.java | 25 +- .../http/client/async/Relative302Test.java | 24 +- .../http/client/async/RemoteSiteTest.java | 80 ++-- .../client/async/RetryNonBlockingIssue.java | 86 ++-- .../http/client/async/RetryRequestTest.java | 6 +- .../async/SimpleAsyncHttpClientTest.java | 8 +- .../client/async/TransferListenerTest.java | 18 +- .../http/client/async/WebDavBasicTest.java | 36 +- .../GrizzlyAsyncProviderBasicTest.java | 3 +- .../GrizzlyBodyDeferringAsyncHandlerTest.java | 4 +- .../GrizzlyByteBufferCapacityTest.java | 1 + .../GrizzlyFeedableBodyGeneratorTest.java | 367 +++++++++--------- .../GrizzlyUnexpectingTimeoutTest.java | 5 +- .../netty/NettyAsyncHttpProviderTest.java | 13 +- .../NettyRequestThrottleTimeoutTest.java | 94 ++--- .../client/websocket/ByteMessageTest.java | 24 +- .../websocket/CloseCodeReasonMessageTest.java | 24 +- .../client/websocket/ProxyTunnellingTest.java | 6 +- .../http/client/websocket/RedirectTest.java | 6 +- .../client/websocket/TextMessageTest.java | 62 ++- 46 files changed, 627 insertions(+), 662 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 4e026fec02..35c6121093 100755 --- a/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java +++ b/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java @@ -356,7 +356,7 @@ public Response onCompleted(Response response) throws Exception { } } - // TODO: fix test + // FIXME: fix test @Test(groups = { "standalone", "default_provider", "async" }, enabled = false) public void asyncStatusHEADContentLenghtTest() throws Throwable { AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeoutInMs(120 * 1000).build()); 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 17d93e1252..4072be94a3 100644 --- a/src/test/java/com/ning/http/client/async/AsyncStreamHandlerTest.java +++ b/src/test/java/com/ning/http/client/async/AsyncStreamHandlerTest.java @@ -51,11 +51,11 @@ private String jetty8ContentTypeMadness(String saneValue) { @Test(groups = { "standalone", "default_provider" }) public void asyncStreamGETTest() throws Exception { final CountDownLatch l = new CountDownLatch(1); - AsyncHttpClient c = getAsyncHttpClient(null); + AsyncHttpClient client = getAsyncHttpClient(null); final AtomicReference responseHeaders = new AtomicReference(); final AtomicReference throwable = new AtomicReference(); try { - c.prepareGet(getTargetUrl()).execute(new AsyncHandlerAdapter() { + client.prepareGet(getTargetUrl()).execute(new AsyncHandlerAdapter() { @Override public STATE onHeadersReceived(HttpResponseHeaders content) throws Exception { @@ -87,7 +87,7 @@ public void onThrowable(Throwable t) { assertNull(throwable.get(), "Unexpected exception"); } finally { - c.close(); + client.close(); } } @@ -96,9 +96,9 @@ public void asyncStreamPOSTTest() throws Exception { final AtomicReference responseHeaders = new AtomicReference(); - AsyncHttpClient c = getAsyncHttpClient(null); + AsyncHttpClient client = getAsyncHttpClient(null); try { - Future f = c.preparePost(getTargetUrl())// + Future f = client.preparePost(getTargetUrl())// .setHeader("Content-Type", "application/x-www-form-urlencoded")// .addFormParam("param_1", "value_1")// .execute(new AsyncHandlerAdapter() { @@ -129,7 +129,7 @@ public String onCompleted() throws Exception { assertEquals(responseBody, RESPONSE); } finally { - c.close(); + client.close(); } } @@ -137,13 +137,13 @@ public String onCompleted() throws Exception { public void asyncStreamInterruptTest() throws Exception { final CountDownLatch l = new CountDownLatch(1); - AsyncHttpClient c = getAsyncHttpClient(null); + AsyncHttpClient client = getAsyncHttpClient(null); final AtomicReference responseHeaders = new AtomicReference(); final AtomicBoolean bodyReceived = new AtomicBoolean(false); final AtomicReference throwable = new AtomicReference(); try { - c.preparePost(getTargetUrl())// + client.preparePost(getTargetUrl())// .setHeader("Content-Type", "application/x-www-form-urlencoded")// .addFormParam("param_1", "value_1")// .execute(new AsyncHandlerAdapter() { @@ -175,17 +175,17 @@ public void onThrowable(Throwable t) { assertNull(throwable.get(), "Should get an exception"); } finally { - c.close(); + client.close(); } } @Test(groups = { "standalone", "default_provider" }) public void asyncStreamFutureTest() throws Exception { - AsyncHttpClient c = getAsyncHttpClient(null); + AsyncHttpClient client = getAsyncHttpClient(null); final AtomicReference responseHeaders = new AtomicReference(); final AtomicReference throwable = new AtomicReference(); try { - Future f = c.preparePost(getTargetUrl()).addFormParam("param_1", "value_1").execute(new AsyncHandlerAdapter() { + Future f = client.preparePost(getTargetUrl()).addFormParam("param_1", "value_1").execute(new AsyncHandlerAdapter() { private StringBuilder builder = new StringBuilder(); @Override @@ -220,7 +220,7 @@ public void onThrowable(Throwable t) { assertNull(throwable.get(), "Unexpected exception"); } finally { - c.close(); + client.close(); } } @@ -228,9 +228,9 @@ public void onThrowable(Throwable t) { public void asyncStreamThrowableRefusedTest() throws Exception { final CountDownLatch l = new CountDownLatch(1); - AsyncHttpClient c = getAsyncHttpClient(null); + AsyncHttpClient client = getAsyncHttpClient(null); try { - c.prepareGet(getTargetUrl()).execute(new AsyncHandlerAdapter() { + client.prepareGet(getTargetUrl()).execute(new AsyncHandlerAdapter() { @Override public STATE onHeadersReceived(HttpResponseHeaders content) throws Exception { @@ -253,17 +253,17 @@ public void onThrowable(Throwable t) { fail("Timed out"); } } finally { - c.close(); + client.close(); } } @Test(groups = { "standalone", "default_provider" }) public void asyncStreamReusePOSTTest() throws Exception { - AsyncHttpClient c = getAsyncHttpClient(null); + AsyncHttpClient client = getAsyncHttpClient(null); final AtomicReference responseHeaders = new AtomicReference(); try { - BoundRequestBuilder rb = c.preparePost(getTargetUrl())// + BoundRequestBuilder rb = client.preparePost(getTargetUrl())// .setHeader("Content-Type", "application/x-www-form-urlencoded") .addFormParam("param_1", "value_1"); @@ -326,17 +326,17 @@ public String onCompleted() throws Exception { assertNotNull(r, "No response body"); assertEquals(r.trim(), RESPONSE, "Unexpected response body"); } finally { - c.close(); + client.close(); } } @Test(groups = { "online", "default_provider" }) public void asyncStream302WithBody() throws Exception { - AsyncHttpClient c = getAsyncHttpClient(null); + AsyncHttpClient client = getAsyncHttpClient(null); final AtomicReference statusCode = new AtomicReference(0); final AtomicReference headers = new AtomicReference(); try { - Future f = c.prepareGet("http://google.com/").execute(new AsyncHandlerAdapter() { + Future f = client.prepareGet("http://google.com/").execute(new AsyncHandlerAdapter() { public STATE onStatusReceived(HttpResponseStatus status) throws Exception { statusCode.set(status.getStatusCode()); @@ -367,17 +367,17 @@ public String onCompleted() throws Exception { assertEquals(h.getJoinedValue("content-type", ", ").toLowerCase(Locale.ENGLISH), TEXT_HTML_CONTENT_TYPE_WITH_UTF_8_CHARSET.toLowerCase(Locale.ENGLISH)); } finally { - c.close(); + client.close(); } } @Test(groups = { "online", "default_provider" }) public void asyncStream302RedirectWithBody() throws Exception { - AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setFollowRedirect(true).build()); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setFollowRedirect(true).build()); final AtomicReference statusCode = new AtomicReference(0); final AtomicReference responseHeaders = new AtomicReference(); try { - Future f = c.prepareGet("http://google.com/").execute(new AsyncHandlerAdapter() { + Future f = client.prepareGet("http://google.com/").execute(new AsyncHandlerAdapter() { public STATE onStatusReceived(HttpResponseStatus status) throws Exception { statusCode.set(status.getStatusCode()); @@ -410,7 +410,7 @@ public String onCompleted() throws Exception { // // assertEquals(h.getJoinedValue("content-type", ", "), "text/html; charset=ISO-8859-1"); } finally { - c.close(); + client.close(); } } @@ -480,12 +480,12 @@ public Integer onCompleted() throws Exception { @Test(groups = { "online", "default_provider" }) public void asyncOptionsTest() throws Exception { - AsyncHttpClient c = getAsyncHttpClient(null); + AsyncHttpClient client = getAsyncHttpClient(null); final AtomicReference responseHeaders = new AtomicReference(); try { final String[] expected = { "GET", "HEAD", "OPTIONS", "POST", "TRACE" }; - Future f = c.prepareOptions("http://www.apache.org/").execute(new AsyncHandlerAdapter() { + Future f = client.prepareOptions("http://www.apache.org/").execute(new AsyncHandlerAdapter() { @Override public STATE onHeadersReceived(HttpResponseHeaders content) throws Exception { @@ -509,15 +509,15 @@ public String onCompleted() throws Exception { assertEquals(values, expected); } finally { - c.close(); + client.close(); } } @Test(groups = { "standalone", "default_provider" }) public void closeConnectionTest() throws Exception { - AsyncHttpClient c = getAsyncHttpClient(null); + AsyncHttpClient client = getAsyncHttpClient(null); try { - Response r = c.prepareGet(getTargetUrl()).execute(new AsyncHandler() { + Response r = client.prepareGet(getTargetUrl()).execute(new AsyncHandler() { private Response.ResponseBuilder builder = new Response.ResponseBuilder(); @@ -552,7 +552,7 @@ public Response onCompleted() throws Exception { assertNotNull(r); assertEquals(r.getStatusCode(), 200); } finally { - c.close(); + 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 d12e647e58..f7042958fc 100644 --- a/src/test/java/com/ning/http/client/async/AsyncStreamLifecycleTest.java +++ b/src/test/java/com/ning/http/client/async/AsyncStreamLifecycleTest.java @@ -99,8 +99,6 @@ public void run() { }; } - // TODO Netty only. - @Test(groups = { "standalone", "default_provider" }) public void testStream() throws IOException { AsyncHttpClient client = getAsyncHttpClient(null); 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 b5a4c99618..6ef33a3ef4 100644 --- a/src/test/java/com/ning/http/client/async/AuthTimeoutTest.java +++ b/src/test/java/com/ning/http/client/async/AuthTimeoutTest.java @@ -55,8 +55,6 @@ public abstract class AuthTimeoutTest extends AbstractBasicTest { private final static String admin = "admin"; - protected AsyncHttpClient client; - public void setUpServer(String auth) throws Exception { server = new Server(); Logger root = Logger.getRootLogger(); @@ -127,8 +125,10 @@ public void handle(String s, Request r, HttpServletRequest request, HttpServletR @Test(groups = { "standalone", "default_provider" }, enabled = false) public void basicAuthTimeoutTest() throws Exception { setUpServer(Constraint.__BASIC_AUTH); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setIdleConnectionInPoolTimeoutInMs(2000).setConnectionTimeoutInMs(20000).setRequestTimeoutInMs(2000).build()); + try { - Future f = execute(false); + Future f = execute(client, false); try { f.get(); fail("expected timeout"); @@ -143,8 +143,10 @@ public void basicAuthTimeoutTest() throws Exception { @Test(groups = { "standalone", "default_provider" }, enabled = false) public void basicPreemptiveAuthTimeoutTest() throws Exception { setUpServer(Constraint.__BASIC_AUTH); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setIdleConnectionInPoolTimeoutInMs(2000).setConnectionTimeoutInMs(20000).setRequestTimeoutInMs(2000).build()); + try { - Future f = execute(true); + Future f = execute(client, true); try { f.get(); fail("expected timeout"); @@ -159,8 +161,10 @@ public void basicPreemptiveAuthTimeoutTest() throws Exception { @Test(groups = { "standalone", "default_provider" }, enabled = false) public void digestAuthTimeoutTest() throws Exception { setUpServer(Constraint.__DIGEST_AUTH); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setIdleConnectionInPoolTimeoutInMs(2000).setConnectionTimeoutInMs(20000).setRequestTimeoutInMs(2000).build()); + try { - Future f = execute(false); + Future f = execute(client, false); try { f.get(); fail("expected timeout"); @@ -175,9 +179,10 @@ public void digestAuthTimeoutTest() throws Exception { @Test(groups = { "standalone", "default_provider" }, enabled = false) public void digestPreemptiveAuthTimeoutTest() throws Exception { setUpServer(Constraint.__DIGEST_AUTH); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setIdleConnectionInPoolTimeoutInMs(2000).setConnectionTimeoutInMs(20000).setRequestTimeoutInMs(2000).build()); try { - Future f = execute(true); + Future f = execute(client, true); f.get(); fail("expected timeout"); } catch (Exception e) { @@ -190,8 +195,10 @@ public void digestPreemptiveAuthTimeoutTest() throws Exception { @Test(groups = { "standalone", "default_provider" }, enabled = false) public void basicFutureAuthTimeoutTest() throws Exception { setUpServer(Constraint.__BASIC_AUTH); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setIdleConnectionInPoolTimeoutInMs(2000).setConnectionTimeoutInMs(20000).setRequestTimeoutInMs(2000).build()); + try { - Future f = execute(false); + Future f = execute(client, false); f.get(1, TimeUnit.SECONDS); fail("expected timeout"); } catch (Exception e) { @@ -204,8 +211,10 @@ public void basicFutureAuthTimeoutTest() throws Exception { @Test(groups = { "standalone", "default_provider" }, enabled = false) public void basicFuturePreemptiveAuthTimeoutTest() throws Exception { setUpServer(Constraint.__BASIC_AUTH); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setIdleConnectionInPoolTimeoutInMs(2000).setConnectionTimeoutInMs(20000).setRequestTimeoutInMs(2000).build()); + try { - Future f = execute(true); + Future f = execute(client, true); f.get(1, TimeUnit.SECONDS); fail("expected timeout"); } catch (Exception e) { @@ -218,8 +227,10 @@ public void basicFuturePreemptiveAuthTimeoutTest() throws Exception { @Test(groups = { "standalone", "default_provider" }, enabled = false) public void digestFutureAuthTimeoutTest() throws Exception { setUpServer(Constraint.__DIGEST_AUTH); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setIdleConnectionInPoolTimeoutInMs(2000).setConnectionTimeoutInMs(20000).setRequestTimeoutInMs(2000).build()); + try { - Future f = execute(false); + Future f = execute(client, false); f.get(1, TimeUnit.SECONDS); fail("expected timeout"); } catch (Exception e) { @@ -232,9 +243,10 @@ public void digestFutureAuthTimeoutTest() throws Exception { @Test(groups = { "standalone", "default_provider" }, enabled = false) public void digestFuturePreemptiveAuthTimeoutTest() throws Exception { setUpServer(Constraint.__DIGEST_AUTH); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setIdleConnectionInPoolTimeoutInMs(2000).setConnectionTimeoutInMs(20000).setRequestTimeoutInMs(2000).build()); try { - Future f = execute(true); + Future f = execute(client, true); f.get(1, TimeUnit.SECONDS); fail("expected timeout"); } catch (Exception e) { @@ -250,11 +262,9 @@ protected void inspectException(Throwable t) { 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()); + protected Future execute(AsyncHttpClient client, boolean preemptive) throws IOException { AsyncHttpClient.BoundRequestBuilder r = client.prepareGet(getTargetUrl()).setRealm(realm(preemptive)).setHeader("X-Content", "Test"); Future f = r.execute(); return f; 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 0ff695ca41..c2016fc136 100644 --- a/src/test/java/com/ning/http/client/async/BasicAuthTest.java +++ b/src/test/java/com/ning/http/client/async/BasicAuthTest.java @@ -147,7 +147,6 @@ private String getFileContent(final File file) { } } } - } private void setUpSecondServer() throws Exception { @@ -298,10 +297,9 @@ public void basicAuthTest() throws IOException, ExecutionException, TimeoutExcep @Test(groups = { "standalone", "default_provider" }) public void redirectAndBasicAuthTest() throws Exception, ExecutionException, TimeoutException, InterruptedException { - AsyncHttpClient client = null; + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setFollowRedirect(true).setMaximumNumberOfRedirects(10).build()); try { setUpSecondServer(); - client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setFollowRedirect(true).setMaximumNumberOfRedirects(10).build()); AsyncHttpClient.BoundRequestBuilder r = client.prepareGet(getTargetUrl2()) // .setHeader( "X-302", "/bla" ) .setRealm((new Realm.RealmBuilder()).setPrincipal(user).setPassword(admin).build()); @@ -313,8 +311,7 @@ public void redirectAndBasicAuthTest() throws Exception, ExecutionException, Tim assertNotNull(resp.getHeader("X-Auth"), "X-Auth shouldn't be null"); } finally { - if (client != null) - client.close(); + client.close(); stopSecondServer(); } } @@ -332,6 +329,11 @@ protected String getTargetUrlNoAuth() { return "http://127.0.0.1:" + portNoAuth + "/"; } + @Override + public AbstractHandler configureHandler() throws Exception { + return new SimpleHandler(); + } + @Test(groups = { "standalone", "default_provider" }) public void basic401Test() throws IOException, ExecutionException, TimeoutException, InterruptedException { AsyncHttpClient client = getAsyncHttpClient(null); @@ -497,11 +499,6 @@ public void basicAuthFileNoKeepAliveTest() throws Throwable { } } - @Override - public AbstractHandler configureHandler() throws Exception { - return new SimpleHandler(); - } - @Test(groups = { "standalone", "default_provider" }) public void stringBuilderBodyConsumerTest() throws Throwable { AsyncHttpClient client = getAsyncHttpClient(null); 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 bea352f9ec..a1afa3b81f 100644 --- a/src/test/java/com/ning/http/client/async/BasicHttpsTest.java +++ b/src/test/java/com/ning/http/client/async/BasicHttpsTest.java @@ -71,7 +71,6 @@ 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 { httpResponse.setContentType("text/html; charset=utf-8"); @@ -253,18 +252,18 @@ public void multipleSSLRequestsTest() throws Throwable { @Test(groups = { "standalone", "default_provider" }) public void multipleSSLWithoutCacheTest() throws Throwable { - final AsyncHttpClient c = getAsyncHttpClient(new Builder().setSSLContext(createSSLContext(new AtomicBoolean(true))).setAllowSslConnectionPool(false).build()); + final AsyncHttpClient client = getAsyncHttpClient(new Builder().setSSLContext(createSSLContext(new AtomicBoolean(true))).setAllowSslConnectionPool(false).build()); try { String body = "hello there"; - c.preparePost(getTargetUrl()).setBody(body).setHeader("Content-Type", "text/html").execute(); + client.preparePost(getTargetUrl()).setBody(body).setHeader("Content-Type", "text/html").execute(); - c.preparePost(getTargetUrl()).setBody(body).setHeader("Content-Type", "text/html").execute(); + client.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 = client.preparePost(getTargetUrl()).setBody(body).setHeader("Content-Type", "text/html").execute().get(); assertEquals(response.getResponseBody(), body); } finally { - c.close(); + client.close(); } } @@ -272,14 +271,14 @@ public void multipleSSLWithoutCacheTest() throws Throwable { public void reconnectsAfterFailedCertificationPath() throws Exception { AtomicBoolean trust = new AtomicBoolean(false); - AsyncHttpClient c = getAsyncHttpClient(new Builder().setSSLContext(createSSLContext(trust)).build()); + AsyncHttpClient client = getAsyncHttpClient(new Builder().setSSLContext(createSSLContext(trust)).build()); try { String body = "hello there"; // first request fails because server certificate is rejected Throwable cause = null; try { - c.preparePost(getTargetUrl()).setBody(body).setHeader("Content-Type", "text/html").execute().get(TIMEOUT, TimeUnit.SECONDS); + client.preparePost(getTargetUrl()).setBody(body).setHeader("Content-Type", "text/html").execute().get(TIMEOUT, TimeUnit.SECONDS); } catch (final ExecutionException e) { cause = e.getCause(); if (cause instanceof ConnectException) { @@ -293,28 +292,26 @@ public void reconnectsAfterFailedCertificationPath() throws Exception { // second request should succeed trust.set(true); - Response response = c.preparePost(getTargetUrl()).setBody(body).setHeader("Content-Type", "text/html").execute().get(TIMEOUT, TimeUnit.SECONDS); + Response response = client.preparePost(getTargetUrl()).setBody(body).setHeader("Content-Type", "text/html").execute().get(TIMEOUT, TimeUnit.SECONDS); assertEquals(response.getResponseBody(), body); } finally { - c.close(); + client.close(); } } @Test(timeOut = 5000) public void failInstantlyIfHostNamesDiffer() throws Exception { - AsyncHttpClient client = null; - try { - final Builder builder = new Builder().setHostnameVerifier(new HostnameVerifier() { - - public boolean verify(String arg0, SSLSession arg1) { - return false; - } - }).setRequestTimeoutInMs(20000); + HostnameVerifier hostnameVerifier = new HostnameVerifier() { + public boolean verify(String arg0, SSLSession arg1) { + return false; + } + }; - client = getAsyncHttpClient(builder.build()); + AsyncHttpClient client = getAsyncHttpClient(new Builder().setHostnameVerifier(hostnameVerifier).setRequestTimeoutInMs(20000).build()); + try { try { client.prepareGet("https://github.com/AsyncHttpClient/async-http-client/issues/355").execute().get(TIMEOUT, TimeUnit.SECONDS); @@ -406,6 +403,5 @@ public X509Certificate[] getAcceptedIssuers() { private static TrustManager dummyTrustManager(final AtomicBoolean trust, final X509TrustManager tm) { return new DummyTrustManager(trust, tm); - } } 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 b32caf72ce..1b36abc4e1 100644 --- a/src/test/java/com/ning/http/client/async/ByteBufferCapacityTest.java +++ b/src/test/java/com/ning/http/client/async/ByteBufferCapacityTest.java @@ -77,7 +77,7 @@ public AbstractHandler configureHandler() throws Exception { @Test(groups = { "standalone", "default_provider" }) public void basicByteBufferTest() throws Throwable { - AsyncHttpClient c = getAsyncHttpClient(null); + AsyncHttpClient client = getAsyncHttpClient(null); try { byte[] bytes = "RatherLargeFileRatherLargeFileRatherLargeFileRatherLargeFile".getBytes("UTF-16"); long repeats = (1024 * 100 * 10 / bytes.length) + 1; @@ -85,7 +85,7 @@ public void basicByteBufferTest() throws Throwable { final AtomicInteger byteReceived = new AtomicInteger(); try { - Response response = c.preparePut(getTargetUrl()).setBody(largeFile).execute(new AsyncCompletionHandlerAdapter() { + Response response = client.preparePut(getTargetUrl()).setBody(largeFile).execute(new AsyncCompletionHandlerAdapter() { /* @Override */ public STATE onBodyPartReceived(final HttpResponseBodyPart content) throws Exception { byteReceived.addAndGet(content.getBodyByteBuffer().capacity()); @@ -103,7 +103,7 @@ public STATE onBodyPartReceived(final HttpResponseBodyPart content) throws Excep fail("Should have timed out"); } } finally { - c.close(); + client.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 db355edaff..391fc0aefb 100644 --- a/src/test/java/com/ning/http/client/async/ChunkingTest.java +++ b/src/test/java/com/ning/http/client/async/ChunkingTest.java @@ -74,19 +74,16 @@ public void testCustomChunking() throws Throwable { } private void doTest(boolean customChunkedInputStream) throws Exception { - AsyncHttpClient c = null; + AsyncHttpClientConfig.Builder bc = new AsyncHttpClientConfig.Builder()// + .setAllowPoolingConnection(true)// + .setMaximumConnectionsPerHost(1)// + .setMaximumConnectionsTotal(1)// + .setConnectionTimeoutInMs(1000)// + .setRequestTimeoutInMs(1000)// + .setFollowRedirect(true); + + AsyncHttpClient client = getAsyncHttpClient(bc.build()); try { - AsyncHttpClientConfig.Builder bc = new AsyncHttpClientConfig.Builder(); - - bc.setAllowPoolingConnection(true); - bc.setMaximumConnectionsPerHost(1); - bc.setMaximumConnectionsTotal(1); - bc.setConnectionTimeoutInMs(1000); - bc.setRequestTimeoutInMs(1000); - bc.setFollowRedirect(true); - - c = getAsyncHttpClient(bc.build()); - RequestBuilder builder = new RequestBuilder("POST"); builder.setUrl(getTargetUrl()); if (customChunkedInputStream) { @@ -100,7 +97,7 @@ private void doTest(boolean customChunkedInputStream) throws Exception { Response res = null; try { - ListenableFuture response = c.executeRequest(r); + ListenableFuture response = client.executeRequest(r); res = response.get(); assertNotNull(res.getResponseBodyAsStream()); if (500 == res.getStatusCode()) { @@ -120,8 +117,8 @@ private void doTest(boolean customChunkedInputStream) throws Exception { fail("Exception Thrown:" + e.getMessage()); } } finally { - if (c != null) - c.close(); + if (client != null) + client.close(); } } @@ -163,5 +160,4 @@ private static File getTestFile() { return testResource1File; } - } 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 b52e9431b9..d7d8015509 100644 --- a/src/test/java/com/ning/http/client/async/ComplexClientTest.java +++ b/src/test/java/com/ning/http/client/async/ComplexClientTest.java @@ -27,36 +27,36 @@ public abstract class ComplexClientTest extends AbstractBasicTest { @Test(groups = { "standalone", "default_provider" }) public void multipleRequestsTest() throws Throwable { - AsyncHttpClient c = getAsyncHttpClient(null); + AsyncHttpClient client = getAsyncHttpClient(null); try { String body = "hello there"; // once - Response response = c.preparePost(getTargetUrl()).setBody(body).setHeader("Content-Type", "text/html").execute().get(TIMEOUT, TimeUnit.SECONDS); + Response response = client.preparePost(getTargetUrl()).setBody(body).setHeader("Content-Type", "text/html").execute().get(TIMEOUT, TimeUnit.SECONDS); assertEquals(response.getResponseBody(), body); // twice - response = c.preparePost(getTargetUrl()).setBody(body).setHeader("Content-Type", "text/html").execute().get(TIMEOUT, TimeUnit.SECONDS); + response = client.preparePost(getTargetUrl()).setBody(body).setHeader("Content-Type", "text/html").execute().get(TIMEOUT, TimeUnit.SECONDS); assertEquals(response.getResponseBody(), body); } finally { - c.close(); + client.close(); } } @Test(groups = { "standalone", "default_provider" }) public void urlWithoutSlashTest() throws Throwable { - AsyncHttpClient c = getAsyncHttpClient(null); + AsyncHttpClient client = getAsyncHttpClient(null); try { 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); + Response response = client.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); } finally { - c.close(); + client.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 1870cb38b2..d779f2e920 100644 --- a/src/test/java/com/ning/http/client/async/ConnectionPoolTest.java +++ b/src/test/java/com/ning/http/client/async/ConnectionPoolTest.java @@ -135,19 +135,19 @@ public Response onCompleted(Response response) throws Exception { @Test(groups = { "standalone", "default_provider" }) public void multipleMaxConnectionOpenTest() throws Throwable { AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setAllowPoolingConnection(true).setConnectionTimeoutInMs(5000).setMaximumConnectionsTotal(1).build(); - AsyncHttpClient c = getAsyncHttpClient(cg); + AsyncHttpClient client = getAsyncHttpClient(cg); try { String body = "hello there"; // once - Response response = c.preparePost(getTargetUrl()).setBody(body).execute().get(TIMEOUT, TimeUnit.SECONDS); + Response response = client.preparePost(getTargetUrl()).setBody(body).execute().get(TIMEOUT, TimeUnit.SECONDS); 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); + client.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(); @@ -156,26 +156,26 @@ public void multipleMaxConnectionOpenTest() throws Throwable { assertNotNull(exception); assertEquals(exception.getMessage(), "Too many connections 1"); } finally { - c.close(); + client.close(); } } @Test(groups = { "standalone", "default_provider" }) public void multipleMaxConnectionOpenTestWithQuery() throws Throwable { AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setAllowPoolingConnection(true).setConnectionTimeoutInMs(5000).setMaximumConnectionsTotal(1).build(); - AsyncHttpClient c = getAsyncHttpClient(cg); + AsyncHttpClient client = getAsyncHttpClient(cg); try { String body = "hello there"; // once - Response response = c.preparePost(getTargetUrl() + "?foo=bar").setBody(body).execute().get(TIMEOUT, TimeUnit.SECONDS); + Response response = client.preparePost(getTargetUrl() + "?foo=bar").setBody(body).execute().get(TIMEOUT, TimeUnit.SECONDS); assertEquals(response.getResponseBody(), "foo_" + body); // twice Exception exception = null; try { - response = c.preparePost(getTargetUrl()).setBody(body).execute().get(TIMEOUT, TimeUnit.SECONDS); + response = client.preparePost(getTargetUrl()).setBody(body).execute().get(TIMEOUT, TimeUnit.SECONDS); } catch (Exception ex) { ex.printStackTrace(); exception = ex; @@ -184,7 +184,7 @@ public void multipleMaxConnectionOpenTestWithQuery() throws Throwable { assertNotNull(response); assertEquals(response.getStatusCode(), 200); } finally { - c.close(); + client.close(); } } 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 4583a70e4d..6a3a4bda7b 100644 --- a/src/test/java/com/ning/http/client/async/EmptyBodyTest.java +++ b/src/test/java/com/ning/http/client/async/EmptyBodyTest.java @@ -69,14 +69,14 @@ public AbstractHandler configureHandler() throws Exception { @Test(groups = { "standalone", "default_provider" }) public void testEmptyBody() throws IOException { - AsyncHttpClient ahc = getAsyncHttpClient(null); + 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); - ahc.executeRequest(ahc.prepareGet(getTargetUrl()).build(), new AsyncHandler() { + client.executeRequest(client.prepareGet(getTargetUrl()).build(), new AsyncHandler() { public void onThrowable(Throwable t) { fail("Got throwable.", t); err.set(true); @@ -122,15 +122,15 @@ public Object onCompleted() throws Exception { assertTrue(status.get()); assertEquals(headers.get(), 1); } finally { - ahc.close(); + client.close(); } } @Test(groups = { "standalone", "default_provider" }) public void testPutEmptyBody() throws Throwable { - AsyncHttpClient ahc = getAsyncHttpClient(null); + AsyncHttpClient client = getAsyncHttpClient(null); try { - Response response = ahc.preparePut(getTargetUrl()).setBody("String").execute().get(); + Response response = client.preparePut(getTargetUrl()).setBody("String").execute().get(); assertNotNull(response); assertEquals(response.getStatusCode(), 204); @@ -139,7 +139,7 @@ public void testPutEmptyBody() throws Throwable { assertEquals(response.getResponseBodyAsStream().read(), -1); } finally { - ahc.close(); + client.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 99b21033f2..43367d962c 100644 --- a/src/test/java/com/ning/http/client/async/FilterTest.java +++ b/src/test/java/com/ning/http/client/async/FilterTest.java @@ -67,13 +67,13 @@ public void basicTest() throws Throwable { AsyncHttpClientConfig.Builder b = new AsyncHttpClientConfig.Builder(); b.addRequestFilter(new ThrottleRequestFilter(100)); - AsyncHttpClient c = getAsyncHttpClient(b.build()); + AsyncHttpClient client = getAsyncHttpClient(b.build()); try { - Response response = c.preparePost(getTargetUrl()).execute().get(); + Response response = client.preparePost(getTargetUrl()).execute().get(); assertNotNull(response); assertEquals(response.getStatusCode(), 200); } finally { - c.close(); + client.close(); } } @@ -82,11 +82,11 @@ public void loadThrottleTest() throws Throwable { AsyncHttpClientConfig.Builder b = new AsyncHttpClientConfig.Builder(); b.addRequestFilter(new ThrottleRequestFilter(10)); - AsyncHttpClient c = getAsyncHttpClient(b.build()); + AsyncHttpClient client = getAsyncHttpClient(b.build()); try { List> futures = new ArrayList>(); for (int i = 0; i < 200; i++) { - futures.add(c.preparePost(getTargetUrl()).execute()); + futures.add(client.preparePost(getTargetUrl()).execute()); } for (Future f : futures) { @@ -95,7 +95,7 @@ public void loadThrottleTest() throws Throwable { assertEquals(r.getStatusCode(), 200); } } finally { - c.close(); + client.close(); } } @@ -103,16 +103,16 @@ public void loadThrottleTest() throws Throwable { public void maxConnectionsText() throws Throwable { AsyncHttpClientConfig.Builder b = new AsyncHttpClientConfig.Builder(); b.addRequestFilter(new ThrottleRequestFilter(0, 1000)); - AsyncHttpClient c = getAsyncHttpClient(b.build()); + AsyncHttpClient client = getAsyncHttpClient(b.build()); try { - c.preparePost(getTargetUrl()).execute().get(); + client.preparePost(getTargetUrl()).execute().get(); fail("Should have timed out"); } catch (IOException ex) { assertNotNull(ex); assertEquals(ex.getCause().getClass(), FilterException.class); } finally { - c.close(); + client.close(); } } @@ -130,17 +130,17 @@ public FilterContext filter(FilterContext ctx) throws FilterException { } }); - AsyncHttpClient c = getAsyncHttpClient(b.build()); + AsyncHttpClient client = getAsyncHttpClient(b.build()); try { - Response response = c.preparePost(getTargetUrl()).execute().get(); + Response response = client.preparePost(getTargetUrl()).execute().get(); assertNotNull(response); assertEquals(response.getStatusCode(), 200); } catch (IOException ex) { fail("Should have timed out"); } finally { - c.close(); + client.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 ff16c5e909..a094a7a742 100644 --- a/src/test/java/com/ning/http/client/async/FollowingThreadTest.java +++ b/src/test/java/com/ning/http/client/async/FollowingThreadTest.java @@ -50,9 +50,9 @@ public void testFollowRedirect() throws IOException, ExecutionException, Timeout public void run() { final CountDownLatch l = new CountDownLatch(1); - final AsyncHttpClient ahc = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setFollowRedirect(true).build()); + final AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setFollowRedirect(true).build()); try { - ahc.prepareGet("http://www.google.com/").execute(new AsyncHandler() { + client.prepareGet("http://www.google.com/").execute(new AsyncHandler() { public void onThrowable(Throwable t) { t.printStackTrace(); @@ -83,7 +83,7 @@ public Integer onCompleted() throws Exception { } catch (Exception e) { e.printStackTrace(); } finally { - ahc.close(); + client.close(); countDown.countDown(); } } @@ -94,5 +94,4 @@ public Integer onCompleted() throws Exception { pool.shutdown(); } } - -} \ No newline at end of file +} 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 a757e41eff..a568740d83 100644 --- a/src/test/java/com/ning/http/client/async/HttpToHttpsRedirectTest.java +++ b/src/test/java/com/ning/http/client/async/HttpToHttpsRedirectTest.java @@ -32,7 +32,6 @@ import javax.servlet.http.HttpServletResponse; import java.io.File; import java.io.IOException; -import java.net.URI; import java.net.URL; import java.util.Enumeration; import java.util.concurrent.atomic.AtomicBoolean; @@ -125,13 +124,16 @@ public void httpToHttpsRedirect() throws Throwable { .setFollowRedirect(true)// .setAcceptAnyCertificate(true)// .build(); - AsyncHttpClient c = getAsyncHttpClient(cg); + AsyncHttpClient client = getAsyncHttpClient(cg); - Response response = c.prepareGet(getTargetUrl()).setHeader("X-redirect", getTargetUrl2()).execute().get(); + try { + Response response = client.prepareGet(getTargetUrl()).setHeader("X-redirect", getTargetUrl2()).execute().get(); assertNotNull(response); assertEquals(response.getStatusCode(), 200); assertEquals(response.getHeader("X-httpToHttps"), "PASS"); - c.close(); + } finally { + client.close(); + } } public String getTargetUrl2() { @@ -147,20 +149,20 @@ public void httpToHttpsProperConfig() throws Throwable { .setFollowRedirect(true)// .setAcceptAnyCertificate(true)// .build(); - AsyncHttpClient c = getAsyncHttpClient(cg); + AsyncHttpClient client = getAsyncHttpClient(cg); try { - Response response = c.prepareGet(getTargetUrl()).setHeader("X-redirect", getTargetUrl2() + "/test2").execute().get(); + Response response = client.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(); + response = client.prepareGet(getTargetUrl()).setHeader("X-redirect", getTargetUrl2() + "/foo2").execute().get(); assertNotNull(response); assertEquals(response.getStatusCode(), 200); assertEquals(response.getHeader("X-httpToHttps"), "PASS"); } finally { - c.close(); + client.close(); } } @@ -173,14 +175,14 @@ public void relativeLocationUrl() throws Throwable { .setFollowRedirect(true)// .setAcceptAnyCertificate(true)// .build(); - AsyncHttpClient c = getAsyncHttpClient(cg); + AsyncHttpClient client = getAsyncHttpClient(cg); try { - Response response = c.prepareGet(getTargetUrl()).setHeader("X-redirect", "/foo/test").execute().get(); + Response response = client.prepareGet(getTargetUrl()).setHeader("X-redirect", "/foo/test").execute().get(); assertNotNull(response); assertEquals(response.getStatusCode(), 302); assertEquals(response.getUri().toString(), getTargetUrl()); } finally { - c.close(); + client.close(); } } } diff --git a/src/test/java/com/ning/http/client/async/IdleStateHandlerTest.java b/src/test/java/com/ning/http/client/async/IdleStateHandlerTest.java index 2ccd40e2d6..c34015c725 100644 --- a/src/test/java/com/ning/http/client/async/IdleStateHandlerTest.java +++ b/src/test/java/com/ning/http/client/async/IdleStateHandlerTest.java @@ -76,14 +76,14 @@ public void setUpGlobal() throws Exception { public void idleStateTest() throws Throwable { isSet.getAndSet(false); AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setIdleConnectionInPoolTimeoutInMs(10 * 1000).build(); - AsyncHttpClient c = getAsyncHttpClient(cg); + AsyncHttpClient client = getAsyncHttpClient(cg); try { - c.prepareGet(getTargetUrl()).execute().get(); + client.prepareGet(getTargetUrl()).execute().get(); } catch (ExecutionException e) { fail("Should allow to finish processing request.", e); } finally { - c.close(); + client.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 f6d8c395ae..845ae85eac 100644 --- a/src/test/java/com/ning/http/client/async/InputStreamTest.java +++ b/src/test/java/com/ning/http/client/async/InputStreamTest.java @@ -54,7 +54,7 @@ public void handle(String s, Request r, HttpServletRequest request, HttpServletR @Test(groups = { "standalone", "default_provider" }) public void testInvalidInputStream() throws IOException, ExecutionException, TimeoutException, InterruptedException { - AsyncHttpClient c = getAsyncHttpClient(null); + AsyncHttpClient client = getAsyncHttpClient(null); try { FluentCaseInsensitiveStringsMap h = new FluentCaseInsensitiveStringsMap(); h.add("Content-Type", "application/x-www-form-urlencoded"); @@ -84,12 +84,12 @@ public int read() throws IOException { } }; - Response resp = c.preparePost(getTargetUrl()).setHeaders(h).setBody(is).execute().get(); + Response resp = client.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(); + client.close(); } } 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 f80168bc50..f020b8158a 100644 --- a/src/test/java/com/ning/http/client/async/ListenableFutureTest.java +++ b/src/test/java/com/ning/http/client/async/ListenableFutureTest.java @@ -30,10 +30,10 @@ public abstract class ListenableFutureTest extends AbstractBasicTest { @Test(groups = { "standalone", "default_provider" }) public void testListenableFuture() throws Throwable { final AtomicInteger statusCode = new AtomicInteger(500); - AsyncHttpClient ahc = getAsyncHttpClient(null); + AsyncHttpClient client = getAsyncHttpClient(null); try { final CountDownLatch latch = new CountDownLatch(1); - final ListenableFuture future = ahc.prepareGet(getTargetUrl()).execute(); + final ListenableFuture future = client.prepareGet(getTargetUrl()).execute(); future.addListener(new Runnable() { public void run() { @@ -51,7 +51,7 @@ public void run() { latch.await(10, TimeUnit.SECONDS); assertEquals(statusCode.get(), 200); } finally { - ahc.close(); + 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 9dc51102c5..6e647f6336 100644 --- a/src/test/java/com/ning/http/client/async/MultipartUploadTest.java +++ b/src/test/java/com/ning/http/client/async/MultipartUploadTest.java @@ -130,7 +130,7 @@ private File getClasspathFile(String file) throws FileNotFoundException { /** * Tests that the streaming of a file works. */ - @Test(enabled = true) + @Test public void testSendingSmallFilesAndByteArray() { String expectedContents = "filecontent: hello"; String expectedContents2 = "gzipcontent: hello"; @@ -211,10 +211,9 @@ public void testSendingSmallFilesAndByteArray() { bc.setFollowRedirect(true); - AsyncHttpClient c = new AsyncHttpClient(bc.build()); + AsyncHttpClient client = new AsyncHttpClient(bc.build()); try { - RequestBuilder builder = new RequestBuilder("POST"); builder.setUrl(servletEndpointRedirectUrl + "/upload/bob"); builder.addBodyPart(new FilePart("file1", testResource1File, "text/plain", "UTF-8")); @@ -230,7 +229,7 @@ public void testSendingSmallFilesAndByteArray() { com.ning.http.client.Request r = builder.build(); - Response res = c.executeRequest(r).get(); + Response res = client.executeRequest(r).get(); assertEquals(200, res.getStatusCode()); @@ -240,7 +239,7 @@ public void testSendingSmallFilesAndByteArray() { e.printStackTrace(); fail("Download Exception"); } finally { - c.close(); + client.close(); FileUtils.deleteQuietly(tmpFile); } } @@ -460,9 +459,6 @@ public void service(HttpServletRequest request, HttpServletResponse response) th w.write("||"); w.close(); } - } - } - } 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 1e13f6ecc5..448abdb868 100644 --- a/src/test/java/com/ning/http/client/async/MultipleHeaderTest.java +++ b/src/test/java/com/ning/http/client/async/MultipleHeaderTest.java @@ -52,11 +52,11 @@ public abstract class MultipleHeaderTest extends AbstractBasicTest { public void testMultipleOtherHeaders() throws IOException, ExecutionException, TimeoutException, InterruptedException { final String[] xffHeaders = new String[] { null, null }; - AsyncHttpClient ahc = getAsyncHttpClient(null); + AsyncHttpClient client = getAsyncHttpClient(null); try { Request req = new RequestBuilder("GET").setUrl("http://localhost:" + port1 + "/MultiOther").build(); final CountDownLatch latch = new CountDownLatch(1); - ahc.executeRequest(req, new AsyncHandler() { + client.executeRequest(req, new AsyncHandler() { public void onThrowable(Throwable t) { t.printStackTrace(System.out); } @@ -96,7 +96,7 @@ public Void onCompleted() throws Exception { Assert.assertEquals(xffHeaders[0], "def"); } } finally { - ahc.close(); + client.close(); } } @@ -104,11 +104,11 @@ public Void onCompleted() throws Exception { public void testMultipleEntityHeaders() throws IOException, ExecutionException, TimeoutException, InterruptedException { final String[] clHeaders = new String[] { null, null }; - AsyncHttpClient ahc = getAsyncHttpClient(null); + AsyncHttpClient client = getAsyncHttpClient(null); try { Request req = new RequestBuilder("GET").setUrl("http://localhost:" + port1 + "/MultiEnt").build(); final CountDownLatch latch = new CountDownLatch(1); - ahc.executeRequest(req, new AsyncHandler() { + client.executeRequest(req, new AsyncHandler() { public void onThrowable(Throwable t) { t.printStackTrace(System.out); } @@ -153,7 +153,7 @@ public Void onCompleted() throws Exception { Assert.assertEquals(clHeaders[1], "2"); } } finally { - ahc.close(); + client.close(); } } 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 b8401491d5..b7ff48ac3f 100644 --- a/src/test/java/com/ning/http/client/async/NonAsciiContentLengthTest.java +++ b/src/test/java/com/ning/http/client/async/NonAsciiContentLengthTest.java @@ -92,5 +92,4 @@ protected void execute(String body) throws IOException, InterruptedException, Ex client.close(); } } - } 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 6beb81d8f5..6992cd3118 100644 --- a/src/test/java/com/ning/http/client/async/PerRequestRelative302Test.java +++ b/src/test/java/com/ning/http/client/async/PerRequestRelative302Test.java @@ -90,11 +90,11 @@ public void setUpGlobal() throws Exception { @Test(groups = { "online", "default_provider" }) public void redirected302Test() throws Throwable { isSet.getAndSet(false); - AsyncHttpClient c = getAsyncHttpClient(null); + AsyncHttpClient client = getAsyncHttpClient(null); try { // once - Response response = c.prepareGet(getTargetUrl()).setFollowRedirects(true).setHeader("X-redirect", "http://www.microsoft.com/").execute().get(); + Response response = client.prepareGet(getTargetUrl()).setFollowRedirects(true).setHeader("X-redirect", "http://www.microsoft.com/").execute().get(); assertNotNull(response); assertEquals(response.getStatusCode(), 200); @@ -104,7 +104,7 @@ public void redirected302Test() throws Throwable { assertTrue(baseUrl.matches(anyMicrosoftPage), "response does not show redirection to " + anyMicrosoftPage); } finally { - c.close(); + client.close(); } } @@ -112,15 +112,15 @@ public void redirected302Test() throws Throwable { public void notRedirected302Test() throws Throwable { isSet.getAndSet(false); AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setFollowRedirect(true).build(); - AsyncHttpClient c = getAsyncHttpClient(cg); + AsyncHttpClient client = getAsyncHttpClient(cg); try { // once - Response response = c.prepareGet(getTargetUrl()).setFollowRedirects(false).setHeader("X-redirect", "http://www.microsoft.com/").execute().get(); + Response response = client.prepareGet(getTargetUrl()).setFollowRedirects(false).setHeader("X-redirect", "http://www.microsoft.com/").execute().get(); assertNotNull(response); assertEquals(response.getStatusCode(), 302); } finally { - c.close(); + client.close(); } } @@ -144,18 +144,18 @@ private static int getPort(UriComponents uri) { @Test(groups = { "standalone", "default_provider" }) public void redirected302InvalidTest() throws Throwable { isSet.getAndSet(false); - AsyncHttpClient c = getAsyncHttpClient(null); + AsyncHttpClient client = getAsyncHttpClient(null); // 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 = client.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(); + client.close(); } } @@ -163,14 +163,14 @@ public void redirected302InvalidTest() throws Throwable { public void relativeLocationUrl() throws Throwable { isSet.getAndSet(false); - AsyncHttpClient c = getAsyncHttpClient(null); + AsyncHttpClient client = getAsyncHttpClient(null); try { - Response response = c.preparePost(getTargetUrl()).setFollowRedirects(true).setHeader("X-redirect", "/foo/test").execute().get(); + Response response = client.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(); + 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 017b63b7a9..bfdfa552be 100644 --- a/src/test/java/com/ning/http/client/async/PostRedirectGetTest.java +++ b/src/test/java/com/ning/http/client/async/PostRedirectGetTest.java @@ -72,7 +72,7 @@ public void postRedirectGet307Test() throws Exception { // --------------------------------------------------------- Private Methods private void doTestNegative(final int status, boolean strict) throws Exception { - AsyncHttpClient p = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setFollowRedirect(true).setStrict302Handling(strict).addResponseFilter(new ResponseFilter() { + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setFollowRedirect(true).setStrict302Handling(strict).addResponseFilter(new ResponseFilter() { public FilterContext filter(FilterContext ctx) throws FilterException { // pass on the x-expect-get and remove the x-redirect // headers if found in the response @@ -84,7 +84,7 @@ public FilterContext filter(FilterContext ctx) throws FilterException { }).build()); try { Request request = new RequestBuilder("POST").setUrl(getTargetUrl()).addFormParam("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() { + Future responseFuture = client.executeRequest(request, new AsyncCompletionHandler() { @Override public Integer onCompleted(Response response) throws Exception { @@ -101,12 +101,12 @@ public void onThrowable(Throwable t) { int statusCode = responseFuture.get(); Assert.assertEquals(statusCode, 200); } finally { - p.close(); + client.close(); } } private void doTestPositive(final int status) throws Exception { - AsyncHttpClient p = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setFollowRedirect(true).addResponseFilter(new ResponseFilter() { + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setFollowRedirect(true).addResponseFilter(new ResponseFilter() { public FilterContext filter(FilterContext ctx) throws FilterException { // pass on the x-expect-get and remove the x-redirect // headers if found in the response @@ -118,7 +118,7 @@ public FilterContext filter(FilterContext ctx) throws FilterException { }).build()); try { Request request = new RequestBuilder("POST").setUrl(getTargetUrl()).addFormParam("q", "a b").addHeader("x-redirect", +status + "@" + "http://localhost:" + port1 + "/foo/bar/baz").build(); - Future responseFuture = p.executeRequest(request, new AsyncCompletionHandler() { + Future responseFuture = client.executeRequest(request, new AsyncCompletionHandler() { @Override public Integer onCompleted(Response response) throws Exception { @@ -135,7 +135,7 @@ public void onThrowable(Throwable t) { int statusCode = responseFuture.get(); Assert.assertEquals(statusCode, 200); } finally { - p.close(); + client.close(); } } 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 e827ec41fe..3f6196a200 100644 --- a/src/test/java/com/ning/http/client/async/ProxyTest.java +++ b/src/test/java/com/ning/http/client/async/ProxyTest.java @@ -329,5 +329,4 @@ public void connectFailed(URI uri, SocketAddress sa, IOException ioe) { ProxySelector.setDefault(originalProxySelector); } } - } diff --git a/src/test/java/com/ning/http/client/async/ProxyTunnellingTest.java b/src/test/java/com/ning/http/client/async/ProxyTunnellingTest.java index 56b775c51b..01b6ee0876 100644 --- a/src/test/java/com/ning/http/client/async/ProxyTunnellingTest.java +++ b/src/test/java/com/ning/http/client/async/ProxyTunnellingTest.java @@ -98,10 +98,10 @@ public void testRequestProxy() throws IOException, InterruptedException, Executi .setAcceptAnyCertificate(true)// .build(); - AsyncHttpClient asyncHttpClient = getAsyncHttpClient(config); + AsyncHttpClient client = getAsyncHttpClient(config); try { RequestBuilder rb = new RequestBuilder("GET").setProxyServer(ps).setUrl(getTargetUrl2()); - Future responseFuture = asyncHttpClient.executeRequest(rb.build(), new AsyncCompletionHandlerBase() { + Future responseFuture = client.executeRequest(rb.build(), new AsyncCompletionHandlerBase() { public void onThrowable(Throwable t) { t.printStackTrace(); @@ -118,7 +118,7 @@ public Response onCompleted(Response response) throws Exception { assertEquals(r.getHeader("X-Proxy-Connection"), "keep-alive"); } finally { - asyncHttpClient.close(); + client.close(); } } @@ -130,10 +130,10 @@ public void testConfigProxy() throws IOException, InterruptedException, Executio .setFollowRedirect(true)// .build(); - AsyncHttpClient asyncHttpClient = getAsyncHttpClient(config); + AsyncHttpClient client = getAsyncHttpClient(config); try { RequestBuilder rb = new RequestBuilder("GET").setUrl(getTargetUrl2()); - Future responseFuture = asyncHttpClient.executeRequest(rb.build(), new AsyncCompletionHandlerBase() { + Future responseFuture = client.executeRequest(rb.build(), new AsyncCompletionHandlerBase() { public void onThrowable(Throwable t) { t.printStackTrace(); @@ -149,7 +149,7 @@ public Response onCompleted(Response response) throws Exception { assertEquals(r.getStatusCode(), 200); assertEquals(r.getHeader("X-Proxy-Connection"), "keep-alive"); } finally { - asyncHttpClient.close(); + client.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 6511880a90..e428242bb9 100644 --- a/src/test/java/com/ning/http/client/async/QueryParametersTest.java +++ b/src/test/java/com/ning/http/client/async/QueryParametersTest.java @@ -103,29 +103,28 @@ public void testUrlRequestParametersEncoding() throws IOException, ExecutionExce @Test(groups = { "standalone", "default_provider" }) public void urlWithColonTest_Netty() throws Throwable { - AsyncHttpClient c = getAsyncHttpClient(null); + AsyncHttpClient client = 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); + Response response = client.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")); } finally { - c.close(); + client.close(); } } @Test(groups = { "standalone", "default_provider" }) public void urlWithColonTest_JDK() throws Throwable { - AsyncHttpClient c = getAsyncHttpClient(null); + AsyncHttpClient client = 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); + Response response = client.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")); } finally { - c.close(); + client.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 53ae5d4000..f178e98c07 100644 --- a/src/test/java/com/ning/http/client/async/RC10KTest.java +++ b/src/test/java/com/ning/http/client/async/RC10KTest.java @@ -102,12 +102,12 @@ 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()); + AsyncHttpClient client = 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++))); + resps.add(client.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) { @@ -116,7 +116,7 @@ public void rc10kProblem() throws IOException, ExecutionException, TimeoutExcept assertEquals(resp.intValue(), i++); } } finally { - ahc.close(); + client.close(); } } 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 8bac8c82b5..6b490822f5 100644 --- a/src/test/java/com/ning/http/client/async/RedirectConnectionUsageTest.java +++ b/src/test/java/com/ning/http/client/async/RedirectConnectionUsageTest.java @@ -103,19 +103,16 @@ public void tearDown() { @Test public void testGetRedirectFinalUrl() { - AsyncHttpClient c = null; + AsyncHttpClientConfig.Builder bc = new AsyncHttpClientConfig.Builder()// + .setAllowPoolingConnection(true)// + .setMaximumConnectionsPerHost(1)// + .setMaximumConnectionsTotal(1)// + .setConnectionTimeoutInMs(1000)// + .setRequestTimeoutInMs(1000)// + .setFollowRedirect(true); + + AsyncHttpClient client = getAsyncHttpClient(bc.build()); try { - AsyncHttpClientConfig.Builder bc = - new AsyncHttpClientConfig.Builder(); - - bc.setAllowPoolingConnection(true); - bc.setMaximumConnectionsPerHost(1); - bc.setMaximumConnectionsTotal(1); - bc.setConnectionTimeoutInMs(1000); - bc.setRequestTimeoutInMs(1000); - bc.setFollowRedirect(true); - - c = getAsyncHttpClient(bc.build()); RequestBuilder builder = new RequestBuilder("GET"); builder.setUrl(servletEndpointRedirectUrl); @@ -123,7 +120,7 @@ public void testGetRedirectFinalUrl() { com.ning.http.client.Request r = builder.build(); try { - ListenableFuture response = c.executeRequest(r); + ListenableFuture response = client.executeRequest(r); Response res = null; res = response.get(); assertNotNull(res.getResponseBody()); @@ -141,7 +138,7 @@ public void testGetRedirectFinalUrl() { } finally { // can hang here - if (c != null) c.close(); + if (client != null) client.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 cb21a880fb..8f1264df54 100644 --- a/src/test/java/com/ning/http/client/async/Relative302Test.java +++ b/src/test/java/com/ning/http/client/async/Relative302Test.java @@ -92,10 +92,10 @@ public void setUpGlobal() throws Exception { public void redirected302Test() throws Throwable { isSet.getAndSet(false); AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setFollowRedirect(true).build(); - AsyncHttpClient c = getAsyncHttpClient(cg); + AsyncHttpClient client = getAsyncHttpClient(cg); try { // once - Response response = c.prepareGet(getTargetUrl()).setHeader("X-redirect", "http://www.google.com/").execute().get(); + Response response = client.prepareGet(getTargetUrl()).setHeader("X-redirect", "http://www.google.com/").execute().get(); assertNotNull(response); assertEquals(response.getStatusCode(), 200); @@ -104,7 +104,7 @@ public void redirected302Test() throws Throwable { assertTrue(baseUrl.startsWith("http://www.google."), "response does not show redirection to a google subdomain, got " + baseUrl); } finally { - c.close(); + client.close(); } } @@ -129,18 +129,18 @@ private static int getPort(UriComponents uri) { public void redirected302InvalidTest() throws Throwable { isSet.getAndSet(false); AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setFollowRedirect(true).build(); - AsyncHttpClient c = getAsyncHttpClient(cg); + AsyncHttpClient client = getAsyncHttpClient(cg); // 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 = client.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(); + client.close(); } } @@ -149,19 +149,19 @@ public void absolutePathRedirectTest() throws Throwable { isSet.getAndSet(false); AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setFollowRedirect(true).build(); - AsyncHttpClient c = getAsyncHttpClient(cg); + AsyncHttpClient client = 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(); + Response response = client.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(); + client.close(); } } @@ -170,19 +170,19 @@ public void relativePathRedirectTest() throws Throwable { isSet.getAndSet(false); AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setFollowRedirect(true).build(); - AsyncHttpClient c = getAsyncHttpClient(cg); + AsyncHttpClient client = getAsyncHttpClient(cg); try { String redirectTarget = "bar/test1"; String destinationUrl = new URI(getTargetUrl()).resolve(redirectTarget).toString(); - Response response = c.prepareGet(getTargetUrl()).setHeader("X-redirect", redirectTarget).execute().get(); + Response response = client.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(); + client.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 7505655372..b9393a52ac 100644 --- a/src/test/java/com/ning/http/client/async/RemoteSiteTest.java +++ b/src/test/java/com/ning/http/client/async/RemoteSiteTest.java @@ -53,83 +53,83 @@ public abstract class RemoteSiteTest extends AbstractBasicTest { @Test(groups = { "online", "default_provider" }) public void testGoogleCom() throws Throwable { - AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeoutInMs(10000).build()); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeoutInMs(10000).build()); try { - Response response = c.prepareGet("http://www.google.com/").execute().get(10, TimeUnit.SECONDS); + Response response = client.prepareGet("http://www.google.com/").execute().get(10, TimeUnit.SECONDS); assertNotNull(response); } finally { - c.close(); + client.close(); } } @Test(groups = { "online", "default_provider" }) public void testMailGoogleCom() throws Throwable { - AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeoutInMs(10000).build()); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeoutInMs(10000).build()); try { - Response response = c.prepareGet("http://mail.google.com/").execute().get(10, TimeUnit.SECONDS); + Response response = client.prepareGet("http://mail.google.com/").execute().get(10, TimeUnit.SECONDS); assertNotNull(response); assertEquals(response.getStatusCode(), 200); } finally { - c.close(); + client.close(); } } @Test(groups = { "online", "default_provider" }, enabled = false) public void testMicrosoftCom() throws Throwable { - AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeoutInMs(10000).build()); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeoutInMs(10000).build()); try { - Response response = c.prepareGet("http://microsoft.com/").execute().get(10, TimeUnit.SECONDS); + Response response = client.prepareGet("http://microsoft.com/").execute().get(10, TimeUnit.SECONDS); assertNotNull(response); assertEquals(response.getStatusCode(), 301); } finally { - c.close(); + client.close(); } } @Test(groups = { "online", "default_provider" }, enabled = false) public void testWwwMicrosoftCom() throws Throwable { - AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeoutInMs(10000).build()); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeoutInMs(10000).build()); try { - Response response = c.prepareGet("http://www.microsoft.com/").execute().get(10, TimeUnit.SECONDS); + Response response = client.prepareGet("http://www.microsoft.com/").execute().get(10, TimeUnit.SECONDS); assertNotNull(response); assertEquals(response.getStatusCode(), 302); } finally { - c.close(); + client.close(); } } @Test(groups = { "online", "default_provider" }, enabled = false) public void testUpdateMicrosoftCom() throws Throwable { - AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeoutInMs(10000).build()); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeoutInMs(10000).build()); try { - Response response = c.prepareGet("http://update.microsoft.com/").execute().get(10, TimeUnit.SECONDS); + Response response = client.prepareGet("http://update.microsoft.com/").execute().get(10, TimeUnit.SECONDS); assertNotNull(response); assertEquals(response.getStatusCode(), 302); } finally { - c.close(); + client.close(); } } @Test(groups = { "online", "default_provider" }) public void testGoogleComWithTimeout() throws Throwable { - AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeoutInMs(10000).build()); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeoutInMs(10000).build()); try { - Response response = c.prepareGet("http://google.com/").execute().get(10, TimeUnit.SECONDS); + Response response = client.prepareGet("http://google.com/").execute().get(10, TimeUnit.SECONDS); assertNotNull(response); assertEquals(response.getStatusCode(), 302); } finally { - c.close(); + client.close(); } } @Test(groups = { "online", "default_provider" }) public void asyncStatusHEADContentLenghtTest() throws Throwable { - AsyncHttpClient p = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setFollowRedirect(true).build()); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setFollowRedirect(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() { + client.executeRequest(request, new AsyncCompletionHandlerAdapter() { @Override public Response onCompleted(Response response) throws Exception { Assert.assertEquals(response.getStatusCode(), 200); @@ -142,7 +142,7 @@ public Response onCompleted(Response response) throws Exception { Assert.fail("Timeout out"); } } finally { - p.close(); + client.close(); } } @@ -150,9 +150,9 @@ public Response onCompleted(Response response) throws Exception { public void invalidStreamTest2() throws Throwable { AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder().setRequestTimeoutInMs(10000).setFollowRedirect(true).setAllowPoolingConnection(false).setMaximumNumberOfRedirects(6).build(); - AsyncHttpClient c = getAsyncHttpClient(config); + AsyncHttpClient client = getAsyncHttpClient(config); try { - Response response = c.prepareGet("http://bit.ly/aUjTtG").execute().get(); + Response response = client.prepareGet("http://bit.ly/aUjTtG").execute().get(); if (response != null) { System.out.println(response); } @@ -161,7 +161,7 @@ public void invalidStreamTest2() throws Throwable { assertNotNull(t.getCause()); assertEquals(t.getCause().getMessage(), "invalid version format: ICY"); } finally { - c.close(); + client.close(); } } @@ -216,34 +216,36 @@ public void testAHC60() throws Throwable { public void stripQueryStringTest() throws Throwable { AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setFollowRedirect(true).build(); - AsyncHttpClient c = getAsyncHttpClient(cg); + AsyncHttpClient client = getAsyncHttpClient(cg); - Response response = c.prepareGet("http://www.freakonomics.com/?p=55846").execute().get(); - - assertNotNull(response); - assertEquals(response.getStatusCode(), 200); + try { + Response response = client.prepareGet("http://www.freakonomics.com/?p=55846").execute().get(); - c.close(); + assertNotNull(response); + assertEquals(response.getStatusCode(), 200); + } finally { + client.close(); + } } @Test(groups = { "online", "default_provider" }) public void stripQueryStringNegativeTest() throws Throwable { AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setRemoveQueryParamsOnRedirect(false).setFollowRedirect(true).build(); - AsyncHttpClient c = getAsyncHttpClient(cg); + AsyncHttpClient client = getAsyncHttpClient(cg); try { - Response response = c.prepareGet("http://www.freakonomics.com/?p=55846").execute().get(); + Response response = client.prepareGet("http://www.freakonomics.com/?p=55846").execute().get(); assertNotNull(response); assertEquals(response.getStatusCode(), 301); } finally { - c.close(); + client.close(); } } @Test(groups = { "online", "default_provider" }) public void evilCoookieTest() throws Throwable { - AsyncHttpClient c = getAsyncHttpClient(null); + AsyncHttpClient client = getAsyncHttpClient(null); try { RequestBuilder builder2 = new RequestBuilder("GET"); builder2.setFollowRedirects(true); @@ -251,20 +253,20 @@ public void evilCoookieTest() throws Throwable { builder2.addHeader("Content-Type", "text/plain"); builder2.addCookie(new Cookie("evilcookie", "test", "test", ".google.com", "/", -1L, 10, false, false)); com.ning.http.client.Request request2 = builder2.build(); - Response response = c.executeRequest(request2).get(); + Response response = client.executeRequest(request2).get(); assertNotNull(response); assertEquals(response.getStatusCode(), 200); } finally { - c.close(); + client.close(); } } @Test(groups = { "online", "default_provider" }, enabled = false) public void testAHC62Com() throws Throwable { - AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setFollowRedirect(true).build()); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setFollowRedirect(true).build()); try { - Response response = c.prepareGet("http://api.crunchbase.com/v/1/financial-organization/kinsey-hills-group.js").execute(new AsyncHandler() { + Response response = client.prepareGet("http://api.crunchbase.com/v/1/financial-organization/kinsey-hills-group.js").execute(new AsyncHandler() { private Response.ResponseBuilder builder = new Response.ResponseBuilder(); @@ -296,7 +298,7 @@ public Response onCompleted() throws Exception { assertNotNull(response); assertTrue(response.getResponseBody().length() >= 3870); } finally { - c.close(); + client.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 ca2316fbb5..b2fd6839ab 100644 --- a/src/test/java/com/ning/http/client/async/RetryNonBlockingIssue.java +++ b/src/test/java/com/ning/http/client/async/RetryNonBlockingIssue.java @@ -127,26 +127,17 @@ private ListenableFuture testMethodRequest(AsyncHttpClient @Test public void testRetryNonBlocking() throws IOException, InterruptedException, ExecutionException { - AsyncHttpClient c = null; - List> res = new - ArrayList>(); + AsyncHttpClientConfig.Builder bc = new AsyncHttpClientConfig.Builder()// + .setAllowPoolingConnection(true)// + .setMaximumConnectionsTotal(100)// + .setConnectionTimeoutInMs(60000)// + .setRequestTimeoutInMs(30000); + + AsyncHttpClient client = new AsyncHttpClient(bc.build()); + List> res = new ArrayList>(); try { - AsyncHttpClientConfig.Builder bc = - new AsyncHttpClientConfig.Builder(); - - bc.setAllowPoolingConnection(true); - bc.setMaximumConnectionsTotal(100); - bc.setConnectionTimeoutInMs(60000); - bc.setRequestTimeoutInMs(30000); - - NettyAsyncHttpProviderConfig config = new - NettyAsyncHttpProviderConfig(); - - bc.setAsyncHttpClientProviderConfig(config); - c = new AsyncHttpClient(bc.build()); - for (int i = 0; i < 32; i++) { - res.add(testMethodRequest(c, 3, "servlet", UUID.randomUUID().toString())); + res.add(testMethodRequest(client, 3, "servlet", UUID.randomUUID().toString())); } StringBuilder b = new StringBuilder(); @@ -162,31 +153,24 @@ public void testRetryNonBlocking() throws IOException, InterruptedException, System.out.println(b.toString()); System.out.flush(); - } - finally { - if (c != null) c.close(); + } finally { + client.close(); } } @Test public void testRetryNonBlockingAsyncConnect() throws IOException, InterruptedException, ExecutionException { - AsyncHttpClient c = null; - List> res = new - ArrayList>(); + AsyncHttpClientConfig.Builder bc = new AsyncHttpClientConfig.Builder()// + .setAllowPoolingConnection(true)// + .setMaximumConnectionsTotal(100)// + .setConnectionTimeoutInMs(60000)// + .setRequestTimeoutInMs(30000); + AsyncHttpClient client = new AsyncHttpClient(bc.build()); + List> res = new ArrayList>(); try { - AsyncHttpClientConfig.Builder bc = - new AsyncHttpClientConfig.Builder(); - - bc.setAllowPoolingConnection(true); - bc.setMaximumConnectionsTotal(100); - bc.setConnectionTimeoutInMs(60000); - bc.setRequestTimeoutInMs(30000); - - c = new AsyncHttpClient(bc.build()); - for (int i = 0; i < 32; i++) { - res.add(testMethodRequest(c, 3, "servlet", UUID.randomUUID().toString())); + res.add(testMethodRequest(client, 3, "servlet", UUID.randomUUID().toString())); } StringBuilder b = new StringBuilder(); @@ -202,31 +186,25 @@ public void testRetryNonBlockingAsyncConnect() throws IOException, InterruptedEx System.out.println(b.toString()); System.out.flush(); - } - finally { - if (c != null) c.close(); + }finally { + client.close(); } } @Test public void testRetryBlocking() throws IOException, InterruptedException, ExecutionException { - AsyncHttpClient c = null; + AsyncHttpClientConfig.Builder bc = new AsyncHttpClientConfig.Builder()// + .setAllowPoolingConnection(true)// + .setMaximumConnectionsTotal(100)// + .setConnectionTimeoutInMs(30000)// + .setRequestTimeoutInMs(30000); + AsyncHttpClient client = new AsyncHttpClient(bc.build()); List> res = new ArrayList>(); try { - AsyncHttpClientConfig.Builder bc = - new AsyncHttpClientConfig.Builder(); - - bc.setAllowPoolingConnection(true); - bc.setMaximumConnectionsTotal(100); - bc.setConnectionTimeoutInMs(30000); - bc.setRequestTimeoutInMs(30000); - - c = new AsyncHttpClient(bc.build()); - for (int i = 0; i < 32; i++) { - res.add(testMethodRequest(c, 3, "servlet", UUID.randomUUID().toString())); + res.add(testMethodRequest(client, 3, "servlet", UUID.randomUUID().toString())); } StringBuilder b = new StringBuilder(); @@ -243,17 +221,15 @@ public void testRetryBlocking() throws IOException, InterruptedException, System.out.println(b.toString()); System.out.flush(); - } - finally { - if (c != null) c.close(); + } finally { + client.close(); } } @SuppressWarnings("serial") public class MockExceptionServlet extends HttpServlet { - private Map requests = new - ConcurrentHashMap(); + private Map requests = new ConcurrentHashMap(); private synchronized int increment(String id) { int val = 0; 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 6b6ccd86bd..f1c870d74b 100644 --- a/src/test/java/com/ning/http/client/async/RetryRequestTest.java +++ b/src/test/java/com/ning/http/client/async/RetryRequestTest.java @@ -69,9 +69,9 @@ public AbstractHandler configureHandler() throws Exception { @Test(groups = { "standalone", "default_provider" }) public void testMaxRetry() throws Throwable { - AsyncHttpClient ahc = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setMaxRequestRetry(0).build()); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setMaxRequestRetry(0).build()); try { - ahc.executeRequest(ahc.prepareGet(getTargetUrl()).build()).get(); + client.executeRequest(client.prepareGet(getTargetUrl()).build()).get(); fail(); } catch (Exception t) { assertNotNull(t.getCause()); @@ -80,7 +80,7 @@ public void testMaxRetry() throws Throwable { fail(); } } finally { - ahc.close(); + client.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 73c306aadc..21cfefbb6f 100644 --- a/src/test/java/com/ning/http/client/async/SimpleAsyncHttpClientTest.java +++ b/src/test/java/com/ning/http/client/async/SimpleAsyncHttpClientTest.java @@ -218,11 +218,11 @@ public void onBytesReceived(UriComponents uri, long amount, long current, long t @Test(groups = { "standalone", "default_provider" }) public void testNullUrl() throws Exception { - SimpleAsyncHttpClient c = new SimpleAsyncHttpClient.Builder().setProviderClass(getProviderClass()).build().derive().build(); + SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setProviderClass(getProviderClass()).build().derive().build(); try { assertTrue(true); } finally { - c.close(); + client.close(); } } @@ -255,6 +255,9 @@ 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() + } finally { + client.close(); + derived.close(); } } @@ -305,5 +308,4 @@ public void testMultiPartPost() throws Exception { 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 894f1150dd..2497027dae 100644 --- a/src/test/java/com/ning/http/client/async/TransferListenerTest.java +++ b/src/test/java/com/ning/http/client/async/TransferListenerTest.java @@ -109,9 +109,9 @@ public void onThrowable(Throwable t) { } }); - AsyncHttpClient c = getAsyncHttpClient(null); + AsyncHttpClient client = getAsyncHttpClient(null); try { - Response response = c.prepareGet(getTargetUrl()).execute(tl).get(); + Response response = client.prepareGet(getTargetUrl()).execute(tl).get(); assertNotNull(response); assertEquals(response.getStatusCode(), 200); @@ -122,7 +122,7 @@ public void onThrowable(Throwable t) { } catch (IOException ex) { fail("Should have timed out"); } finally { - c.close(); + client.close(); } } @@ -169,9 +169,9 @@ public void onThrowable(Throwable t) { } }); - AsyncHttpClient c = getAsyncHttpClient(null); + AsyncHttpClient client = getAsyncHttpClient(null); try { - Response response = c.preparePut(getTargetUrl()).setBody(largeFile).execute(tl).get(); + Response response = client.preparePut(getTargetUrl()).setBody(largeFile).execute(tl).get(); assertNotNull(response); assertEquals(response.getStatusCode(), 200); @@ -182,7 +182,7 @@ public void onThrowable(Throwable t) { } catch (IOException ex) { fail("Should have timed out"); } finally { - c.close(); + client.close(); } } @@ -229,9 +229,9 @@ public void onThrowable(Throwable t) { } }); - AsyncHttpClient c = getAsyncHttpClient(null); + AsyncHttpClient client = getAsyncHttpClient(null); try { - Response response = c.preparePut(getTargetUrl()).setBody(new FileBodyGenerator(largeFile)).execute(tl).get(); + Response response = client.preparePut(getTargetUrl()).setBody(new FileBodyGenerator(largeFile)).execute(tl).get(); assertNotNull(response); assertEquals(response.getStatusCode(), 200); @@ -242,7 +242,7 @@ public void onThrowable(Throwable t) { } catch (IOException ex) { fail("Should have timed out"); } finally { - c.close(); + client.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 720cd5adb5..ed4b2c573c 100644 --- a/src/test/java/com/ning/http/client/async/WebDavBasicTest.java +++ b/src/test/java/com/ning/http/client/async/WebDavBasicTest.java @@ -96,78 +96,78 @@ public void tearDownGlobal() throws InterruptedException, Exception { @Test(groups = { "standalone", "default_provider" }) public void mkcolWebDavTest1() throws InterruptedException, IOException, ExecutionException { - AsyncHttpClient c = getAsyncHttpClient(null); + AsyncHttpClient client = getAsyncHttpClient(null); try { Request mkcolRequest = new RequestBuilder("MKCOL").setUrl(getTargetUrl()).build(); - Response response = c.executeRequest(mkcolRequest).get(); + Response response = client.executeRequest(mkcolRequest).get(); assertEquals(response.getStatusCode(), 201); } finally { - c.close(); + client.close(); } } @Test(groups = { "standalone", "default_provider" }) public void mkcolWebDavTest2() throws InterruptedException, IOException, ExecutionException { - AsyncHttpClient c = getAsyncHttpClient(null); + AsyncHttpClient client = getAsyncHttpClient(null); try { Request mkcolRequest = new RequestBuilder("MKCOL").setUrl(getTargetUrl() + "/folder2").build(); - Response response = c.executeRequest(mkcolRequest).get(); + Response response = client.executeRequest(mkcolRequest).get(); assertEquals(response.getStatusCode(), 409); } finally { - c.close(); + client.close(); } } @Test(groups = { "standalone", "default_provider" }) public void basicPropFindWebDavTest() throws InterruptedException, IOException, ExecutionException { - AsyncHttpClient c = getAsyncHttpClient(null); + AsyncHttpClient client = getAsyncHttpClient(null); try { Request propFindRequest = new RequestBuilder("PROPFIND").setUrl(getTargetUrl()).build(); - Response response = c.executeRequest(propFindRequest).get(); + Response response = client.executeRequest(propFindRequest).get(); assertEquals(response.getStatusCode(), 404); } finally { - c.close(); + client.close(); } } @Test(groups = { "standalone", "default_provider" }) public void propFindWebDavTest() throws InterruptedException, IOException, ExecutionException { - AsyncHttpClient c = getAsyncHttpClient(null); + AsyncHttpClient client = getAsyncHttpClient(null); try { Request mkcolRequest = new RequestBuilder("MKCOL").setUrl(getTargetUrl()).build(); - Response response = c.executeRequest(mkcolRequest).get(); + Response response = client.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(); + response = client.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(); + response = client.executeRequest(propFindRequest).get(); assertEquals(response.getStatusCode(), 207); assertTrue(response.getResponseBody().contains("HTTP/1.1 200 OK")); } finally { - c.close(); + client.close(); } } @Test(groups = { "standalone", "default_provider" }) public void propFindCompletionHandlerWebDavTest() throws InterruptedException, IOException, ExecutionException { - AsyncHttpClient c = getAsyncHttpClient(null); + AsyncHttpClient client = getAsyncHttpClient(null); try { Request mkcolRequest = new RequestBuilder("MKCOL").setUrl(getTargetUrl()).build(); - Response response = c.executeRequest(mkcolRequest).get(); + Response response = client.executeRequest(mkcolRequest).get(); assertEquals(response.getStatusCode(), 201); Request propFindRequest = new RequestBuilder("PROPFIND").setUrl(getTargetUrl()).build(); - WebDavResponse webDavResponse = c.executeRequest(propFindRequest, new WebDavCompletionHandlerBase() { + WebDavResponse webDavResponse = client.executeRequest(propFindRequest, new WebDavCompletionHandlerBase() { /** * {@inheritDoc} */ @@ -186,7 +186,7 @@ public WebDavResponse onCompleted(WebDavResponse response) throws Exception { assertNotNull(webDavResponse); assertEquals(webDavResponse.getStatusCode(), 200); } finally { - c.close(); + 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 4b8ae23d1c..ff472421c3 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 @@ -54,12 +54,13 @@ public void customize(TCPNIOTransport transport, FilterChainBuilder builder) { return config; } + // FIXME why disabled? @Test(groups = { "standalone", "default_provider", "async" }, enabled = false) public void asyncDoPostBasicGZIPTest() throws Throwable { } + // FIXME server replies with a foo=bar cookie and yet Grizzly decodes it into foo=value; domain=/; path=/ @Test(groups = { "standalone", "default_provider", "async" }, enabled = false) public void asyncDoGetCookieTest() throws Throwable { - // FIXME server replies with a foo=bar cookie and yet Grizzly decodes it into foo=value; domain=/; path=/ } } 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 1945a7bda7..62dd30eeb3 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 @@ -31,16 +31,18 @@ public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { return ProviderUtil.grizzlyProvider(config); } + // FIXME @Test(enabled = false) public void deferredInputStreamTrick() throws IOException, ExecutionException, TimeoutException, InterruptedException { } + // FIXME @Test(enabled = false) public void deferredSimple() throws IOException, ExecutionException, TimeoutException, InterruptedException { } + // FIXME @Test(enabled = false) public void deferredInputStreamTrickWithFailure() throws IOException, ExecutionException, TimeoutException, InterruptedException { } - } 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 d3522541b2..9ee102bb9c 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 @@ -27,6 +27,7 @@ public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { return ProviderUtil.grizzlyProvider(config); } + // FIXME @Test(groups = { "standalone", "default_provider" }, enabled = false) public void basicByteBufferTest() throws Throwable { } 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 0b89f7709a..7bbd665b3a 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 @@ -141,96 +141,90 @@ private void doSimpleFeeder(final boolean secure) { .setMaximumConnectionsTotal(60) .setAcceptAnyCertificate(true) .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) { - } - } + final AsyncHttpClient client = new AsyncHttpClient(new GrizzlyAsyncHttpProvider(config), config); + try { + 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); } - } - }; - 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 { + feed(Buffers.EMPTY_BUFFER, true); + } finally { + if (in != null) { try { - totalsReceived[idx] = Integer.parseInt(response.getHeader("x-total")); - } catch (Exception e) { - errors[idx] = e; + in.close(); + } catch (IOException ignored) { } - statusCodes[idx] = response.getStatusCode(); - latch.countDown(); - return response; } - - @Override - public void onThrowable(Throwable t) { - errors[idx] = t; - t.printStackTrace(); - latch.countDown(); + } + } + }; + 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; } - }); - } catch (IOException e) { - errors[idx] = e; - latch.countDown(); + 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"); - } finally { - service.shutdownNow(); - } + try { + latch.await(1, TimeUnit.MINUTES); + } catch (InterruptedException e) { + fail("Latch interrupted"); + } finally { + service.shutdownNow(); + } - for (int i = 0; i < threadCount; i++) { - assertEquals(200, statusCodes[i]); - assertNull(errors[i]); - assertEquals(tempFile.length(), totalsReceived[i]); + for (int i = 0; i < threadCount; i++) { + assertEquals(200, statusCodes[i]); + assertNull(errors[i]); + assertEquals(tempFile.length(), totalsReceived[i]); + } + } finally { + client.close(); } } @@ -246,128 +240,121 @@ private void doNonBlockingFeeder(final boolean secure) { .setMaximumConnectionsTotal(60) .setAcceptAnyCertificate(true) .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.NonBlockingFeeder nonBlockingFeeder = - new FeedableBodyGenerator.NonBlockingFeeder(generator) { - private final Random r = new Random(); - private final InputStream in; - private final byte[] bytesIn = new byte[2048]; - private boolean isDone; - - { - try { - in = new FileInputStream(tempFile); - } catch (IOException e) { - throw new IllegalStateException(e); - } + final AsyncHttpClient client = new AsyncHttpClient(new GrizzlyAsyncHttpProvider(config), config); + try { + 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.NonBlockingFeeder nonBlockingFeeder = new FeedableBodyGenerator.NonBlockingFeeder(generator) { + private final Random r = new Random(); + private final InputStream in; + private final byte[] bytesIn = new byte[2048]; + private boolean isDone; + + { + try { + in = new FileInputStream(tempFile); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + + @Override + public void canFeed() throws IOException { + final int read = in.read(bytesIn); + if (read == -1) { + isDone = true; + feed(Buffers.EMPTY_BUFFER, true); + return; } - @Override - public void canFeed() throws IOException { - final int read = in.read(bytesIn); - if (read == -1) { - isDone = true; - feed(Buffers.EMPTY_BUFFER, true); - return; - } + final Buffer b = Buffers.wrap(DEFAULT_MEMORY_MANAGER, bytesIn, 0, read); + feed(b, false); + } - final Buffer b = - Buffers.wrap( - DEFAULT_MEMORY_MANAGER, - bytesIn, - 0, - read); - feed(b, false); - } + @Override + public boolean isDone() { + return isDone; + } - @Override - public boolean isDone() { - return isDone; - } + @Override + public boolean isReady() { + // simulate real-life usecase, where data could not be ready + return r.nextInt(100) < 80; + } - @Override - public boolean isReady() { - // simulate real-life usecase, where data could not be ready - return r.nextInt(100) < 80; - } + @Override + public void notifyReadyToFeed(final NonBlockingFeeder.ReadyToFeedListener listener) { + service.execute(new Runnable() { - @Override - public void notifyReadyToFeed( - final NonBlockingFeeder.ReadyToFeedListener listener) { - service.execute(new Runnable() { - - public void run() { - try { - Thread.sleep(2); - } catch (InterruptedException e) { - } - - listener.ready(); - } - - }); - } - }; - generator.setFeeder(nonBlockingFeeder); - 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 { + public void run() { try { - totalsReceived[idx] = Integer.parseInt(response.getHeader("x-total")); - } catch (Exception e) { - errors[idx] = e; + Thread.sleep(2); + } catch (InterruptedException e) { } - statusCodes[idx] = response.getStatusCode(); - latch.countDown(); - return response; + + listener.ready(); } - @Override - public void onThrowable(Throwable t) { - errors[idx] = t; - t.printStackTrace(); - latch.countDown(); + }); + } + }; + generator.setFeeder(nonBlockingFeeder); + 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; } - }); - } catch (IOException e) { - errors[idx] = e; - latch.countDown(); + 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"); - } finally { - service.shutdownNow(); - } + try { + latch.await(1, TimeUnit.MINUTES); + } catch (InterruptedException e) { + fail("Latch interrupted"); + } finally { + service.shutdownNow(); + } - for (int i = 0; i < threadCount; i++) { - assertEquals(200, statusCodes[i]); - assertNull(errors[i]); - assertEquals(tempFile.length(), totalsReceived[i]); + for (int i = 0; i < threadCount; i++) { + assertEquals(200, statusCodes[i]); + assertNull(errors[i]); + assertEquals(tempFile.length(), totalsReceived[i]); + } + } finally { + client.close(); } } 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 index 9fc1f1d09c..e4d92c2c48 100644 --- a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyUnexpectingTimeoutTest.java +++ b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyUnexpectingTimeoutTest.java @@ -85,6 +85,7 @@ public void unexpectedTimeoutTest() throws IOException { final int timeout = 100; final AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeoutInMs(timeout).build()); + try { Future responseFuture = client.prepareGet(getTargetUrl()).execute(new AsyncCompletionHandler() { @Override @@ -118,6 +119,8 @@ public void onThrowable(Throwable t) { } // the result should be either onCompleted or onThrowable. assertEquals(1, counts.get(), "result should be one"); - client.close(); + } finally { + client.close(); + } } } diff --git a/src/test/java/com/ning/http/client/async/netty/NettyAsyncHttpProviderTest.java b/src/test/java/com/ning/http/client/async/netty/NettyAsyncHttpProviderTest.java index b7073c42ef..4100670de3 100644 --- a/src/test/java/com/ning/http/client/async/netty/NettyAsyncHttpProviderTest.java +++ b/src/test/java/com/ning/http/client/async/netty/NettyAsyncHttpProviderTest.java @@ -32,13 +32,16 @@ public void bossThreadPoolExecutor() throws Throwable { conf.setBossExecutorService(Executors.newSingleThreadExecutor()); AsyncHttpClientConfig cf = new AsyncHttpClientConfig.Builder().setAsyncHttpClientProviderConfig(conf).build(); - AsyncHttpClient c = getAsyncHttpClient(cf); - - Response r = c.prepareGet(getTargetUrl()).execute().get(); - assertEquals(r.getStatusCode(), 200); + AsyncHttpClient client = getAsyncHttpClient(cf); + + try { + Response response = client.prepareGet(getTargetUrl()).execute().get(); + assertEquals(response.getStatusCode(), 200); + } finally { + client.close(); + } } - @Override public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { return ProviderUtil.nettyProvider(config); 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 index c47b0e76e5..f6240ad3e6 100644 --- a/src/test/java/com/ning/http/client/async/netty/NettyRequestThrottleTimeoutTest.java +++ b/src/test/java/com/ning/http/client/async/netty/NettyRequestThrottleTimeoutTest.java @@ -46,7 +46,8 @@ public AbstractHandler configureHandler() throws Exception { } private class SlowHandler extends AbstractHandler { - public void handle(String target, Request baseRequest, HttpServletRequest request, final HttpServletResponse response) throws IOException, ServletException { + 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(); @@ -68,65 +69,66 @@ public void run() { } } - @Test(groups = {"standalone", "netty_provider"}) + @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 AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setCompressionEnabled(true) + .setAllowPoolingConnection(true).setMaximumConnectionsTotal(1).build()); - final CountDownLatch latch = new CountDownLatch(2); + try { + final CountDownLatch latch = new CountDownLatch(2); - final List tooManyConnections = new ArrayList(2); - for(int i=0;i<2;i++) { - new Thread(new Runnable() { + final List tooManyConnections = new ArrayList(2); + for (int i = 0; i < 2; i++) { + new Thread(new Runnable() { - public void run() { - try { - requestThrottle.acquire(); - Future responseFuture = null; + public void run() { try { - responseFuture = - client.prepareGet(getTargetUrl()).setRequestTimeoutInMs(SLEEPTIME_MS/2).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); + requestThrottle.acquire(); + Future responseFuture = null; + try { + responseFuture = client.prepareGet(getTargetUrl()).setRequestTimeoutInMs(SLEEPTIME_MS / 2) + .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(); } - if(responseFuture!=null) - responseFuture.get(); - } catch (Exception e) { - } finally { - latch.countDown(); } + }).start(); - } - }).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"); - try { - latch.await(30,TimeUnit.SECONDS); - } catch (Exception e) { - fail("failed to wait for requests to complete"); + } finally { + client.close(); } - - 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 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 4ed5706707..fa173a7143 100644 --- a/src/test/java/com/ning/http/client/websocket/ByteMessageTest.java +++ b/src/test/java/com/ning/http/client/websocket/ByteMessageTest.java @@ -65,12 +65,12 @@ public org.eclipse.jetty.websocket.WebSocket doWebSocketConnect(HttpServletReque @Test public void echoByte() throws Throwable { - AsyncHttpClient c = getAsyncHttpClient(null); + AsyncHttpClient client = getAsyncHttpClient(null); 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 = client.prepareGet(getTargetUrl()).execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(new WebSocketByteListener() { @Override public void onOpen(WebSocket websocket) { @@ -103,18 +103,18 @@ public void onFragment(byte[] fragment, boolean last) { latch.await(); assertEquals(text.get(), "ECHO".getBytes()); } finally { - c.close(); + client.close(); } } @Test public void echoTwoMessagesTest() throws Throwable { - AsyncHttpClient c = getAsyncHttpClient(null); + AsyncHttpClient client = getAsyncHttpClient(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 = client.prepareGet(getTargetUrl()).execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(new WebSocketByteListener() { @Override public void onOpen(WebSocket websocket) { @@ -154,18 +154,18 @@ public void onFragment(byte[] fragment, boolean last) { latch.await(); assertEquals(text.get(), "ECHOECHO".getBytes()); } finally { - c.close(); + client.close(); } } @Test public void echoOnOpenMessagesTest() throws Throwable { - AsyncHttpClient c = getAsyncHttpClient(null); + AsyncHttpClient client = getAsyncHttpClient(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 = client.prepareGet(getTargetUrl()).execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(new WebSocketByteListener() { @Override public void onOpen(WebSocket websocket) { @@ -204,17 +204,17 @@ public void onFragment(byte[] fragment, boolean last) { latch.await(); assertEquals(text.get(), "ECHOECHO".getBytes()); } finally { - c.close(); + client.close(); } } public void echoFragments() throws Exception { - AsyncHttpClient c = getAsyncHttpClient(null); + AsyncHttpClient client = getAsyncHttpClient(null); 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() { + WebSocket websocket = client.prepareGet(getTargetUrl()).execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(new WebSocketByteListener() { @Override public void onOpen(WebSocket websocket) { @@ -253,7 +253,7 @@ public void onFragment(byte[] fragment, boolean last) { latch.await(); assertEquals(text.get(), "ECHOECHO".getBytes()); } finally { - c.close(); + client.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 412bc8392a..8b4e618bd4 100644 --- a/src/test/java/com/ning/http/client/websocket/CloseCodeReasonMessageTest.java +++ b/src/test/java/com/ning/http/client/websocket/CloseCodeReasonMessageTest.java @@ -26,30 +26,30 @@ public abstract class CloseCodeReasonMessageTest extends TextMessageTest { @Test(timeOut = 60000) public void onCloseWithCode() throws Throwable { - AsyncHttpClient c = getAsyncHttpClient(null); + AsyncHttpClient client = getAsyncHttpClient(null); 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 = client.prepareGet(getTargetUrl()).execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(new Listener(latch, text)).build()).get(); websocket.close(); latch.await(); assertTrue(text.get().startsWith("1000")); } finally { - c.close(); + client.close(); } } @Test(timeOut = 60000) public void onCloseWithCodeServerClose() throws Throwable { - AsyncHttpClient c = getAsyncHttpClient(null); + AsyncHttpClient client = getAsyncHttpClient(null); 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(); + client.prepareGet(getTargetUrl()).execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(new Listener(latch, text)).build()).get(); latch.await(); final String[] parts = text.get().split(" "); @@ -60,7 +60,7 @@ public void onCloseWithCodeServerClose() throws Throwable { assertEquals(parts[3], ">"); assertEquals(parts[4], "10000ms"); } finally { - c.close(); + client.close(); } } @@ -96,12 +96,12 @@ public void onError(Throwable t) { @Test(timeOut = 60000) public void wrongStatusCode() throws Throwable { - AsyncHttpClient c = getAsyncHttpClient(null); + AsyncHttpClient client = getAsyncHttpClient(null); try { final CountDownLatch latch = new CountDownLatch(1); final AtomicReference throwable = new AtomicReference(); - WebSocket websocket = c.prepareGet("http://apache.org").execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(new WebSocketTextListener() { + WebSocket websocket = client.prepareGet("http://apache.org").execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(new WebSocketTextListener() { @Override public void onMessage(String message) { @@ -130,18 +130,18 @@ public void onError(Throwable t) { assertNotNull(throwable.get()); assertEquals(throwable.get().getClass(), IllegalStateException.class); } finally { - c.close(); + client.close(); } } @Test(timeOut = 60000) public void wrongProtocolCode() throws Throwable { - AsyncHttpClient c = getAsyncHttpClient(null); + AsyncHttpClient client = getAsyncHttpClient(null); try { final CountDownLatch latch = new CountDownLatch(1); final AtomicReference throwable = new AtomicReference(); - WebSocket websocket = c.prepareGet("ws://www.google.com/").execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(new WebSocketTextListener() { + WebSocket websocket = client.prepareGet("ws://www.google.com/").execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(new WebSocketTextListener() { @Override public void onMessage(String message) { @@ -170,7 +170,7 @@ public void onError(Throwable t) { assertNotNull(throwable.get()); assertEquals(throwable.get().getClass(), IllegalStateException.class); } finally { - c.close(); + client.close(); } } } diff --git a/src/test/java/com/ning/http/client/websocket/ProxyTunnellingTest.java b/src/test/java/com/ning/http/client/websocket/ProxyTunnellingTest.java index 324a5321d4..79906e20fa 100644 --- a/src/test/java/com/ning/http/client/websocket/ProxyTunnellingTest.java +++ b/src/test/java/com/ning/http/client/websocket/ProxyTunnellingTest.java @@ -103,12 +103,12 @@ public void echoText() throws Exception { ProxyServer ps = new ProxyServer(ProxyServer.Protocol.HTTPS, "127.0.0.1", port1); AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder().setProxyServer(ps).setAcceptAnyCertificate(true).build(); - AsyncHttpClient asyncHttpClient = getAsyncHttpClient(config); + AsyncHttpClient client = getAsyncHttpClient(config); try { final CountDownLatch latch = new CountDownLatch(1); final AtomicReference text = new AtomicReference(""); - WebSocket websocket = asyncHttpClient.prepareGet(getTargetUrl()).execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(new WebSocketTextListener() { + WebSocket websocket = client.prepareGet(getTargetUrl()).execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(new WebSocketTextListener() { @Override public void onMessage(String message) { @@ -141,7 +141,7 @@ public void onError(Throwable t) { latch.await(); assertEquals(text.get(), "ECHO"); } finally { - asyncHttpClient.close(); + client.close(); } } } 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 d02549c251..2117624cbf 100644 --- a/src/test/java/com/ning/http/client/websocket/RedirectTest.java +++ b/src/test/java/com/ning/http/client/websocket/RedirectTest.java @@ -84,12 +84,12 @@ public org.eclipse.jetty.websocket.WebSocket doWebSocketConnect(HttpServletReque @Test(timeOut = 60000) public void testRedirectToWSResource() throws Exception { - AsyncHttpClient c = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setFollowRedirect(true).build()); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setFollowRedirect(true).build()); try { final CountDownLatch latch = new CountDownLatch(1); final AtomicReference text = new AtomicReference(""); - WebSocket websocket = c.prepareGet(getRedirectURL()).execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(new WebSocketListener() { + WebSocket websocket = client.prepareGet(getRedirectURL()).execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(new WebSocketListener() { @Override public void onOpen(com.ning.http.client.websocket.WebSocket websocket) { @@ -112,7 +112,7 @@ public void onError(Throwable t) { assertEquals(text.get(), "OnOpen"); websocket.close(); } finally { - c.close(); + client.close(); } } 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 dab785b593..74d9b56bd3 100644 --- a/src/test/java/com/ning/http/client/websocket/TextMessageTest.java +++ b/src/test/java/com/ning/http/client/websocket/TextMessageTest.java @@ -21,7 +21,6 @@ import java.util.concurrent.atomic.AtomicReference; import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertTrue; import static org.testng.Assert.fail; @@ -71,12 +70,12 @@ public org.eclipse.jetty.websocket.WebSocket doWebSocketConnect(HttpServletReque @Test(timeOut = 60000) public void onOpen() throws Throwable { - AsyncHttpClient c = getAsyncHttpClient(null); + AsyncHttpClient client = getAsyncHttpClient(null); 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 = client.prepareGet(getTargetUrl()).execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(new WebSocketListener() { @Override public void onOpen(com.ning.http.client.websocket.WebSocket websocket) { @@ -98,50 +97,50 @@ public void onError(Throwable t) { latch.await(); assertEquals(text.get(), "OnOpen"); } finally { - c.close(); + client.close(); } } @Test(timeOut = 60000) public void onEmptyListenerTest() throws Throwable { - AsyncHttpClient c = getAsyncHttpClient(null); + AsyncHttpClient client = getAsyncHttpClient(null); try { WebSocket websocket = null; try { - websocket = c.prepareGet(getTargetUrl()).execute(new WebSocketUpgradeHandler.Builder().build()).get(); + websocket = client.prepareGet(getTargetUrl()).execute(new WebSocketUpgradeHandler.Builder().build()).get(); } catch (Throwable t) { fail(); } assertTrue(websocket != null); } finally { - c.close(); + client.close(); } } @Test(timeOut = 60000) public void onFailureTest() throws Throwable { - AsyncHttpClient c = getAsyncHttpClient(null); + AsyncHttpClient client = getAsyncHttpClient(null); try { Throwable t = null; try { - c.prepareGet("ws://abcdefg").execute(new WebSocketUpgradeHandler.Builder().build()).get(); + client.prepareGet("ws://abcdefg").execute(new WebSocketUpgradeHandler.Builder().build()).get(); } catch (Throwable t2) { t = t2; } assertTrue(t != null); } finally { - c.close(); + client.close(); } } @Test(timeOut = 60000) public void onTimeoutCloseTest() throws Throwable { - AsyncHttpClient c = getAsyncHttpClient(null); + AsyncHttpClient client = getAsyncHttpClient(null); try { final CountDownLatch latch = new CountDownLatch(1); final AtomicReference text = new AtomicReference(""); - c.prepareGet(getTargetUrl()).execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(new WebSocketListener() { + client.prepareGet(getTargetUrl()).execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(new WebSocketListener() { @Override public void onOpen(com.ning.http.client.websocket.WebSocket websocket) { @@ -163,18 +162,18 @@ public void onError(Throwable t) { latch.await(); assertEquals(text.get(), "OnClose"); } finally { - c.close(); + client.close(); } } @Test(timeOut = 60000) public void onClose() throws Throwable { - AsyncHttpClient c = getAsyncHttpClient(null); + AsyncHttpClient client = getAsyncHttpClient(null); 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 = client.prepareGet(getTargetUrl()).execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(new WebSocketListener() { @Override public void onOpen(com.ning.http.client.websocket.WebSocket websocket) { @@ -198,18 +197,18 @@ public void onError(Throwable t) { latch.await(); assertEquals(text.get(), "OnClose"); } finally { - c.close(); + client.close(); } } @Test(timeOut = 60000) public void echoText() throws Throwable { - AsyncHttpClient c = getAsyncHttpClient(null); + AsyncHttpClient client = getAsyncHttpClient(null); try { final CountDownLatch latch = new CountDownLatch(1); final AtomicReference text = new AtomicReference(""); - WebSocket websocket = c.prepareGet(getTargetUrl()).execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(new WebSocketTextListener() { + WebSocket websocket = client.prepareGet(getTargetUrl()).execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(new WebSocketTextListener() { @Override public void onMessage(String message) { @@ -242,18 +241,18 @@ public void onError(Throwable t) { latch.await(); assertEquals(text.get(), "ECHO"); } finally { - c.close(); + client.close(); } } @Test(timeOut = 60000) public void echoDoubleListenerText() throws Throwable { - AsyncHttpClient c = getAsyncHttpClient(null); + AsyncHttpClient client = getAsyncHttpClient(null); try { final CountDownLatch latch = new CountDownLatch(2); final AtomicReference text = new AtomicReference(""); - WebSocket websocket = c.prepareGet(getTargetUrl()).execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(new WebSocketTextListener() { + WebSocket websocket = client.prepareGet(getTargetUrl()).execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(new WebSocketTextListener() { @Override public void onMessage(String message) { @@ -312,18 +311,18 @@ public void onError(Throwable t) { latch.await(); assertEquals(text.get(), "ECHOECHO"); } finally { - c.close(); + client.close(); } } @Test public void echoTwoMessagesTest() throws Throwable { - AsyncHttpClient c = getAsyncHttpClient(null); + AsyncHttpClient client = getAsyncHttpClient(null); try { final CountDownLatch latch = new CountDownLatch(2); final AtomicReference text = new AtomicReference(""); - WebSocket websocket = c.prepareGet(getTargetUrl()).execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(new WebSocketTextListener() { + WebSocket websocket = client.prepareGet(getTargetUrl()).execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(new WebSocketTextListener() { @Override public void onMessage(String message) { @@ -357,17 +356,17 @@ public void onError(Throwable t) { latch.await(); assertEquals(text.get(), "ECHOECHO"); } finally { - c.close(); + client.close(); } } public void echoFragments() throws Throwable { - AsyncHttpClient c = getAsyncHttpClient(null); + AsyncHttpClient client = getAsyncHttpClient(null); try { final CountDownLatch latch = new CountDownLatch(1); final AtomicReference text = new AtomicReference(""); - WebSocket websocket = c.prepareGet(getTargetUrl()).execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(new WebSocketTextListener() { + WebSocket websocket = client.prepareGet(getTargetUrl()).execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(new WebSocketTextListener() { @Override public void onMessage(String message) { @@ -401,19 +400,19 @@ public void onError(Throwable t) { latch.await(); assertEquals(text.get(), "ECHOECHO"); } finally { - c.close(); + client.close(); } } @Test(timeOut = 60000) public void echoTextAndThenClose() throws Throwable { - AsyncHttpClient c = getAsyncHttpClient(null); + AsyncHttpClient client = getAsyncHttpClient(null); try { final CountDownLatch textLatch = new CountDownLatch(1); final CountDownLatch closeLatch = new CountDownLatch(1); final AtomicReference text = new AtomicReference(""); - final WebSocket websocket = c.prepareGet(getTargetUrl()).execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(new WebSocketTextListener() { + final WebSocket websocket = client.prepareGet(getTargetUrl()).execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(new WebSocketTextListener() { @Override public void onMessage(String message) { @@ -449,8 +448,7 @@ public void onError(Throwable t) { assertEquals(text.get(), "ECHO"); } finally { - c.close(); + client.close(); } } - } From c595aabb7435acaf735e327e87622db8b79e021a Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 17 Jul 2014 01:33:12 +0200 Subject: [PATCH 424/701] Properly compute Realm URI, close #626 --- src/main/java/com/ning/http/util/AuthenticatorUtils.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/ning/http/util/AuthenticatorUtils.java b/src/main/java/com/ning/http/util/AuthenticatorUtils.java index d15425b4c5..7e491acff5 100644 --- a/src/main/java/com/ning/http/util/AuthenticatorUtils.java +++ b/src/main/java/com/ning/http/util/AuthenticatorUtils.java @@ -39,12 +39,11 @@ private static String computeRealmURI(Realm realm) { if (realm.isTargetProxy()) { return "/"; } else { - boolean omitQuery = realm.isOmitQuery() && MiscUtils.isNonEmpty(uri.getQuery()); if (realm.isUseAbsoluteURI()) { - return omitQuery ? uri.withNewQuery(null).toUrl() : uri.toUrl(); + return realm.isOmitQuery() && MiscUtils.isNonEmpty(uri.getQuery()) ? uri.withNewQuery(null).toUrl() : uri.toUrl(); } else { String path = getNonEmptyPath(uri); - return omitQuery ? path : path + "?" + uri.getQuery(); + return realm.isOmitQuery() || !MiscUtils.isNonEmpty(uri.getQuery()) ? path : path + "?" + uri.getQuery(); } } } From 857bdd195f7af88ed9c21e7e323afc9b30816cb4 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 17 Jul 2014 02:04:15 +0200 Subject: [PATCH 425/701] Make ThrottleRequestFilter properly release Semaphore, close #567 --- .../client/extra/ThrottleRequestFilter.java | 34 +++++++++++-------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/ning/http/client/extra/ThrottleRequestFilter.java b/src/main/java/com/ning/http/client/extra/ThrottleRequestFilter.java index 6289d2f284..ea885223c5 100644 --- a/src/main/java/com/ning/http/client/extra/ThrottleRequestFilter.java +++ b/src/main/java/com/ning/http/client/extra/ThrottleRequestFilter.java @@ -19,11 +19,13 @@ import com.ning.http.client.filter.FilterContext; import com.ning.http.client.filter.FilterException; import com.ning.http.client.filter.RequestFilter; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; /** * A {@link com.ning.http.client.filter.RequestFilter} throttles requests and block when the number of permits is reached, waiting for @@ -31,18 +33,14 @@ */ public class ThrottleRequestFilter implements RequestFilter { private final static Logger logger = LoggerFactory.getLogger(ThrottleRequestFilter.class); - private final int maxConnections; private final Semaphore available; private final int maxWait; public ThrottleRequestFilter(int maxConnections) { - this.maxConnections = maxConnections; - this.maxWait = Integer.MAX_VALUE; - available = new Semaphore(maxConnections, true); + this(maxConnections, Integer.MAX_VALUE); } public ThrottleRequestFilter(int maxConnections, int maxWait) { - this.maxConnections = maxConnections; this.maxWait = maxWait; available = new Semaphore(maxConnections, true); } @@ -62,7 +60,6 @@ public FilterContext filter(FilterContext ctx) throws FilterException { String.format("No slot available for processing Request %s with AsyncHandler %s", ctx.getRequest(), ctx.getAsyncHandler())); } - ; } catch (InterruptedException e) { throw new FilterException( String.format("Interrupted Request %s with AsyncHandler %s", ctx.getRequest(), ctx.getAsyncHandler())); @@ -71,7 +68,9 @@ public FilterContext filter(FilterContext ctx) throws FilterException { return new FilterContext.FilterContextBuilder(ctx).asyncHandler(new AsyncHandlerWrapper(ctx.getAsyncHandler())).build(); } - private class AsyncHandlerWrapper implements AsyncHandler { + private class AsyncHandlerWrapper implements AsyncHandler { + + private AtomicBoolean complete = new AtomicBoolean(false); private final AsyncHandler asyncHandler; @@ -79,6 +78,14 @@ public AsyncHandlerWrapper(AsyncHandler asyncHandler) { this.asyncHandler = asyncHandler; } + private void complete() { + if (complete.compareAndSet(false, true)) + available.release(); + if (logger.isDebugEnabled()) { + logger.debug("Current Throttling Status after onThrowable {}", available.availablePermits()); + } + } + /** * {@inheritDoc} */ @@ -87,10 +94,7 @@ public void onThrowable(Throwable t) { try { asyncHandler.onThrowable(t); } finally { - available.release(); - if (logger.isDebugEnabled()) { - logger.debug("Current Throttling Status after onThrowable {}", available.availablePermits()); - } + complete(); } } @@ -123,11 +127,11 @@ public STATE onHeadersReceived(HttpResponseHeaders headers) throws Exception { */ /* @Override */ public T onCompleted() throws Exception { - available.release(); - if (logger.isDebugEnabled()) { - logger.debug("Current Throttling Status {}", available.availablePermits()); + try { + return asyncHandler.onCompleted(); + } finally { + complete(); } - return asyncHandler.onCompleted(); } } } From 069dba3805dbf6d17ae6cbe5b46f68445559a5e8 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 17 Jul 2014 02:10:37 +0200 Subject: [PATCH 426/701] minor clean up --- .../client/extra/ThrottleRequestFilter.java | 20 +++++++------------ 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/ning/http/client/extra/ThrottleRequestFilter.java b/src/main/java/com/ning/http/client/extra/ThrottleRequestFilter.java index ea885223c5..1e5674ffd9 100644 --- a/src/main/java/com/ning/http/client/extra/ThrottleRequestFilter.java +++ b/src/main/java/com/ning/http/client/extra/ThrottleRequestFilter.java @@ -32,7 +32,7 @@ * the response to arrives before executing the next request. */ public class ThrottleRequestFilter implements RequestFilter { - private final static Logger logger = LoggerFactory.getLogger(ThrottleRequestFilter.class); + private final static Logger LOGGER = LoggerFactory.getLogger(ThrottleRequestFilter.class); private final Semaphore available; private final int maxWait; @@ -52,9 +52,9 @@ public ThrottleRequestFilter(int maxConnections, int maxWait) { public FilterContext filter(FilterContext ctx) throws FilterException { try { - if (logger.isDebugEnabled()) { - logger.debug("Current Throttling Status {}", available.availablePermits()); - } + if (LOGGER.isDebugEnabled()) + LOGGER.debug("Current Throttling Status {}", available.availablePermits()); + if (!available.tryAcquire(maxWait, TimeUnit.MILLISECONDS)) { throw new FilterException( String.format("No slot available for processing Request %s with AsyncHandler %s", @@ -70,9 +70,8 @@ public FilterContext filter(FilterContext ctx) throws FilterException { private class AsyncHandlerWrapper implements AsyncHandler { - private AtomicBoolean complete = new AtomicBoolean(false); - private final AsyncHandler asyncHandler; + private final AtomicBoolean complete = new AtomicBoolean(false); public AsyncHandlerWrapper(AsyncHandler asyncHandler) { this.asyncHandler = asyncHandler; @@ -81,15 +80,14 @@ public AsyncHandlerWrapper(AsyncHandler asyncHandler) { private void complete() { if (complete.compareAndSet(false, true)) available.release(); - if (logger.isDebugEnabled()) { - logger.debug("Current Throttling Status after onThrowable {}", available.availablePermits()); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Current Throttling Status after onThrowable {}", available.availablePermits()); } } /** * {@inheritDoc} */ - /* @Override */ public void onThrowable(Throwable t) { try { asyncHandler.onThrowable(t); @@ -101,7 +99,6 @@ public void onThrowable(Throwable t) { /** * {@inheritDoc} */ - /* @Override */ public STATE onBodyPartReceived(HttpResponseBodyPart bodyPart) throws Exception { return asyncHandler.onBodyPartReceived(bodyPart); } @@ -109,7 +106,6 @@ public STATE onBodyPartReceived(HttpResponseBodyPart bodyPart) throws Exception /** * {@inheritDoc} */ - /* @Override */ public STATE onStatusReceived(HttpResponseStatus responseStatus) throws Exception { return asyncHandler.onStatusReceived(responseStatus); } @@ -117,7 +113,6 @@ public STATE onStatusReceived(HttpResponseStatus responseStatus) throws Exceptio /** * {@inheritDoc} */ - /* @Override */ public STATE onHeadersReceived(HttpResponseHeaders headers) throws Exception { return asyncHandler.onHeadersReceived(headers); } @@ -125,7 +120,6 @@ public STATE onHeadersReceived(HttpResponseHeaders headers) throws Exception { /** * {@inheritDoc} */ - /* @Override */ public T onCompleted() throws Exception { try { return asyncHandler.onCompleted(); From 9dfb987837485fac2d44cfe88219b4224a0b14ca Mon Sep 17 00:00:00 2001 From: oleksiys Date: Wed, 16 Jul 2014 21:08:43 -0700 Subject: [PATCH 427/701] [1.9.x] + minor threads cleanup, use ioThreads config value, fix tests --- .../grizzly/GrizzlyAsyncHttpProvider.java | 22 +++++++++++- .../http/client/providers/grizzly/Utils.java | 16 +++++++++ .../GrizzlyFeedableBodyGeneratorTest.java | 34 +++++++++---------- .../GrizzlyNoTransferEncodingTest.java | 8 ++--- 4 files changed, 57 insertions(+), 23 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 7d16b44672..7d4da268cd 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 @@ -148,6 +148,8 @@ 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; +import org.glassfish.grizzly.nio.RoundRobinConnectionDistributor; +import org.glassfish.grizzly.threadpool.ThreadPoolConfig; /** * A Grizzly 2.0-based implementation of {@link AsyncHttpProvider}. @@ -421,6 +423,24 @@ public void onTimeout(Connection connection) { fcb.add(clientFilter); clientTransport.getAsyncQueueIO().getWriter() .setMaxPendingBytesPerConnection(AsyncQueueWriter.AUTO_SIZE); + + clientTransport.setNIOChannelDistributor( + new RoundRobinConnectionDistributor(clientTransport, false, false)); + + final int kernelThreadsCount = + clientConfig.getIoThreadMultiplier() * + Runtime.getRuntime().availableProcessors(); + + clientTransport.setSelectorRunnersCount(kernelThreadsCount); + clientTransport.setKernelThreadPoolConfig( + ThreadPoolConfig.defaultConfig() + .setCorePoolSize(kernelThreadsCount) + .setMaxPoolSize(kernelThreadsCount) + .setPoolName("grizzly-ahc-kernel") +// .setPoolName(discoverTestName("grizzly-ahc-kernel")) // uncomment for tests to track down the leaked threads + ); + + final TransportCustomizer customizer = (TransportCustomizer) providerConfig.getProperty(TRANSPORT_CUSTOMIZER); if (customizer != null) { @@ -429,7 +449,7 @@ public void onTimeout(Connection connection) { doDefaultTransportConfig(); } fcb.add(new WebSocketFilter()); - + clientTransport.setProcessor(fcb.build()); } diff --git a/src/main/java/com/ning/http/client/providers/grizzly/Utils.java b/src/main/java/com/ning/http/client/providers/grizzly/Utils.java index d03c579e80..658f656aa3 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/Utils.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/Utils.java @@ -31,4 +31,20 @@ public static boolean isSecure(final UriComponents uri) { final String scheme = uri.getScheme(); return ("https".equals(scheme) || "wss".equals(scheme)); } + + static String discoverTestName(final String defaultName) { + final StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); + final int strackTraceLen = stackTrace.length; + + if (stackTrace[strackTraceLen - 1].getClassName().contains("surefire")) { + for (int i = strackTraceLen - 2; i >= 0; i--) { + if (stackTrace[i].getClassName().contains("com.ning.http.client.async")) { + return "grizzly-kernel-" + + stackTrace[i].getClassName() + "." + stackTrace[i].getMethodName(); + } + } + } + + return defaultName; + } } 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 7bbd665b3a..c610e4f5db 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013 Sonatype, Inc. All rights reserved. + * Copyright (c) 2013-2014 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. @@ -20,20 +20,6 @@ import com.ning.http.client.providers.grizzly.FeedableBodyGenerator; import com.ning.http.client.providers.grizzly.FeedableBodyGenerator.NonBlockingFeeder; 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; @@ -45,12 +31,24 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; - +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 static org.glassfish.grizzly.http.server.NetworkListener.DEFAULT_NETWORK_HOST; +import org.glassfish.grizzly.http.server.Request; +import org.glassfish.grizzly.http.server.Response; +import org.glassfish.grizzly.memory.Buffers; import static org.glassfish.grizzly.memory.MemoryManager.DEFAULT_MEMORY_MANAGER; +import org.glassfish.grizzly.ssl.SSLContextConfigurator; +import org.glassfish.grizzly.ssl.SSLEngineConfigurator; +import org.glassfish.grizzly.utils.Charsets; import static org.testng.Assert.assertNull; import static org.testng.Assert.fail; import static org.testng.AssertJUnit.assertEquals; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; public class GrizzlyFeedableBodyGeneratorTest { @@ -68,7 +66,7 @@ public class GrizzlyFeedableBodyGeneratorTest { // ------------------------------------------------------------------- Setup - @BeforeTest + @BeforeMethod public void setup() throws Exception { generateTempFile(); server = new HttpServer(); @@ -92,7 +90,7 @@ public void setup() throws Exception { // --------------------------------------------------------------- Tear Down - @AfterTest + @AfterMethod public void tearDown() { if (!tempFile.delete()) { tempFile.deleteOnExit(); diff --git a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyNoTransferEncodingTest.java b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyNoTransferEncodingTest.java index 6b0aa334a3..00a15c596b 100644 --- a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyNoTransferEncodingTest.java +++ b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyNoTransferEncodingTest.java @@ -25,8 +25,8 @@ import org.glassfish.grizzly.http.server.Request; import org.glassfish.grizzly.http.server.Response; import org.testng.Assert; -import org.testng.annotations.AfterTest; -import org.testng.annotations.BeforeTest; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; public class GrizzlyNoTransferEncodingTest { @@ -37,7 +37,7 @@ public class GrizzlyNoTransferEncodingTest { // ------------------------------------------------------------------- Setup - @BeforeTest + @BeforeMethod public void setup() throws Exception { server = new HttpServer(); final NetworkListener listener = @@ -70,7 +70,7 @@ public void service(final Request request, // --------------------------------------------------------------- Tear Down - @AfterTest + @AfterMethod public void tearDown() { server.shutdownNow(); server = null; From 7da9677a2d8f32fcfe91aad37350697f2377733e Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 17 Jul 2014 10:10:08 +0200 Subject: [PATCH 428/701] Re-enable GrizzlyBodyDeferringAsyncHandlerTest, see #625 --- .../GrizzlyBodyDeferringAsyncHandlerTest.java | 21 ------------------- 1 file changed, 21 deletions(-) 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 62dd30eeb3..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 @@ -13,36 +13,15 @@ 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.BodyDeferringAsyncHandlerTest; import com.ning.http.client.async.ProviderUtil; -import java.io.IOException; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeoutException; - public class GrizzlyBodyDeferringAsyncHandlerTest extends BodyDeferringAsyncHandlerTest { @Override public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { return ProviderUtil.grizzlyProvider(config); } - - // FIXME - @Test(enabled = false) - public void deferredInputStreamTrick() throws IOException, ExecutionException, TimeoutException, InterruptedException { - } - - // FIXME - @Test(enabled = false) - public void deferredSimple() throws IOException, ExecutionException, TimeoutException, InterruptedException { - } - - // FIXME - @Test(enabled = false) - public void deferredInputStreamTrickWithFailure() throws IOException, ExecutionException, TimeoutException, InterruptedException { - } } From 0e1ecce2c2d0a75a70d1e078d89c94d3622a9c38 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 17 Jul 2014 10:19:42 +0200 Subject: [PATCH 429/701] Drop requestCompressionLevel config parameter, close #627 --- .../http/client/AsyncHttpClientConfig.java | 35 ------------------- .../client/AsyncHttpClientConfigBean.java | 6 ---- .../client/AsyncHttpClientConfigDefaults.java | 5 --- .../http/client/SimpleAsyncHttpClient.java | 5 --- .../netty/NettyAsyncHttpProvider.java | 4 --- 5 files changed, 55 deletions(-) diff --git a/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java b/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java index a510949e1c..bf2c6f0ff7 100644 --- a/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java @@ -71,7 +71,6 @@ public class AsyncHttpClientConfig { protected List requestFilters; protected List responseFilters; protected List ioExceptionFilters; - protected int requestCompressionLevel; protected int maxRequestRetry; protected boolean allowSslConnectionPool; protected boolean disableUrlEncodingForBoundedRequests; @@ -108,7 +107,6 @@ private AsyncHttpClientConfig(int maxTotalConnections, List requestFilters, List responseFilters, List ioExceptionFilters, - int requestCompressionLevel, int maxRequestRetry, boolean allowSslConnectionCaching, boolean disableUrlEncodingForBoundedRequests, @@ -139,7 +137,6 @@ private AsyncHttpClientConfig(int maxTotalConnections, this.requestFilters = requestFilters; this.responseFilters = responseFilters; this.ioExceptionFilters = ioExceptionFilters; - this.requestCompressionLevel = requestCompressionLevel; this.maxRequestRetry = maxRequestRetry; this.allowSslConnectionPool = allowSslConnectionCaching; this.removeQueryParamOnRedirect = removeQueryParamOnRedirect; @@ -342,15 +339,6 @@ public List getIOExceptionFilters() { return Collections.unmodifiableList(ioExceptionFilters); } - /** - * Return the compression level, or -1 if no compression is used. - * - * @return the compression level, or -1 if no compression is use - */ - public int getRequestCompressionLevel() { - return requestCompressionLevel; - } - /** * Return the number of time the library will retry when an {@link java.io.IOException} is throw by the remote server * @@ -489,7 +477,6 @@ public static class Builder { private boolean useProxySelector = defaultUseProxySelector(); private boolean allowPoolingConnection = defaultAllowPoolingConnection(); private boolean useRelativeURIsWithSSLProxies = defaultUseRelativeURIsWithSSLProxies(); - private int requestCompressionLevel = defaultRequestCompressionLevel(); private int maxRequestRetry = defaultMaxRequestRetry(); private int ioThreadMultiplier = defaultIoThreadMultiplier(); private boolean allowSslConnectionPool = defaultAllowSslConnectionPool(); @@ -787,26 +774,6 @@ public Builder removeIOExceptionFilter(IOExceptionFilter ioExceptionFilter) { return this; } - /** - * Return the compression level, or -1 if no compression is used. - * - * @return the compression level, or -1 if no compression is use - */ - public int getRequestCompressionLevel() { - return requestCompressionLevel; - } - - /** - * Set the compression level, or -1 if no compression is used. - * - * @param requestCompressionLevel compression level, or -1 if no compression is use - * @return this - */ - public Builder setRequestCompressionLevel(int requestCompressionLevel) { - this.requestCompressionLevel = requestCompressionLevel; - return this; - } - /** * Set the number of time a request will be retried when an {@link java.io.IOException} occurs because of a Network exception. * @@ -977,7 +944,6 @@ public Builder(AsyncHttpClientConfig prototype) { responseFilters.addAll(prototype.getResponseFilters()); ioExceptionFilters.addAll(prototype.getIOExceptionFilters()); - requestCompressionLevel = prototype.getRequestCompressionLevel(); disableUrlEncodingForBoundedRequests = prototype.isDisableUrlEncodingForBoundedRequests(); ioThreadMultiplier = prototype.getIoThreadMultiplier(); maxRequestRetry = prototype.getMaxRequestRetry(); @@ -1040,7 +1006,6 @@ public Thread newThread(Runnable r) { requestFilters, // responseFilters, // ioExceptionFilters, // - requestCompressionLevel, // maxRequestRetry, // allowSslConnectionPool, // disableUrlEncodingForBoundedRequests, // diff --git a/src/main/java/com/ning/http/client/AsyncHttpClientConfigBean.java b/src/main/java/com/ning/http/client/AsyncHttpClientConfigBean.java index a4fe56050a..1877b849ae 100644 --- a/src/main/java/com/ning/http/client/AsyncHttpClientConfigBean.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClientConfigBean.java @@ -59,7 +59,6 @@ void configureDefaults() { userAgent = defaultUserAgent(); allowPoolingConnection = defaultAllowPoolingConnection(); useRelativeURIsWithSSLProxies = defaultUseRelativeURIsWithSSLProxies(); - requestCompressionLevel = defaultRequestCompressionLevel(); maxRequestRetry = defaultMaxRequestRetry(); ioThreadMultiplier = defaultIoThreadMultiplier(); allowSslConnectionPool = defaultAllowSslConnectionPool(); @@ -199,11 +198,6 @@ public AsyncHttpClientConfigBean addIoExceptionFilters(IOExceptionFilter ioExcep return this; } - public AsyncHttpClientConfigBean setRequestCompressionLevel(int requestCompressionLevel) { - this.requestCompressionLevel = requestCompressionLevel; - return this; - } - public AsyncHttpClientConfigBean setMaxRequestRetry(int maxRequestRetry) { this.maxRequestRetry = maxRequestRetry; return this; diff --git a/src/main/java/com/ning/http/client/AsyncHttpClientConfigDefaults.java b/src/main/java/com/ning/http/client/AsyncHttpClientConfigDefaults.java index 0168768699..215dc577a0 100644 --- a/src/main/java/com/ning/http/client/AsyncHttpClientConfigDefaults.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClientConfigDefaults.java @@ -97,11 +97,6 @@ public static boolean defaultUseRelativeURIsWithSSLProxies() { return getBoolean(ASYNC_CLIENT + "useRelativeURIsWithSSLProxies", true); } - // unused/broken, left there for compatibility, fixed in Netty 4 - public static int defaultRequestCompressionLevel() { - return Integer.getInteger(ASYNC_CLIENT + "requestCompressionLevel", -1); - } - public static int defaultMaxRequestRetry() { return Integer.getInteger(ASYNC_CLIENT + "maxRequestRetry", 5); } diff --git a/src/main/java/com/ning/http/client/SimpleAsyncHttpClient.java b/src/main/java/com/ning/http/client/SimpleAsyncHttpClient.java index 9f9e87d5ea..af8d527b8d 100644 --- a/src/main/java/com/ning/http/client/SimpleAsyncHttpClient.java +++ b/src/main/java/com/ning/http/client/SimpleAsyncHttpClient.java @@ -544,11 +544,6 @@ public Builder setSSLContext(final SSLContext sslContext) { return this; } - public Builder setRequestCompressionLevel(int requestCompressionLevel) { - configBuilder.setRequestCompressionLevel(requestCompressionLevel); - return this; - } - public Builder setRealmNtlmDomain(String ntlmDomain) { realm().setNtlmDomain(ntlmDomain); return this; 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 e19327e79b..3b148b20dc 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 @@ -190,10 +190,6 @@ public NettyAsyncHttpProvider(AsyncHttpClientConfig config) { providerConfig = new NettyAsyncHttpProviderConfig(); } - if (config.getRequestCompressionLevel() > 0) { - LOGGER.warn("Request was enabled but Netty actually doesn't support this feature"); - } - // check if external NioClientSocketChannelFactory is defined if (providerConfig.getSocketChannelFactory() != null) { socketChannelFactory = providerConfig.getSocketChannelFactory(); From c9e37aefaefdff8484640da696f580cd28a6b0bc Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 17 Jul 2014 10:55:59 +0200 Subject: [PATCH 430/701] Stop re-setting the pipeline factory on every secure request, close #628, close #629 --- .../netty/NettyAsyncHttpProvider.java | 79 ++++++++----------- 1 file changed, 31 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 3b148b20dc..7dcf6770c7 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 @@ -162,16 +162,16 @@ public class NettyAsyncHttpProvider extends SimpleChannelUpstreamHandler impleme private final ClientBootstrap secureBootstrap; private final ClientBootstrap webSocketBootstrap; private final ClientBootstrap secureWebSocketBootstrap; + private final AsyncHttpClientConfig config; private final AtomicBoolean isClose = new AtomicBoolean(false); private final ClientSocketChannelFactory socketChannelFactory; private final boolean allowReleaseSocketChannelFactory; - private final ChannelManager channelManager; private final NettyAsyncHttpProviderConfig providerConfig; private final boolean disableZeroCopy; private static final NTLMEngine ntlmEngine = new NTLMEngine(); - private static SpnegoEngine spnegoEngine = null; + private static SpnegoEngine spnegoEngine; private final Protocol httpProtocol = new HttpProtocol(); private final Protocol webSocketProtocol = new WebSocketProtocol(); private final boolean allowStopNettyTimer; @@ -184,11 +184,12 @@ private static boolean isNTLM(List auth) { public NettyAsyncHttpProvider(AsyncHttpClientConfig config) { - if (config.getAsyncHttpProviderConfig() instanceof NettyAsyncHttpProviderConfig) { - providerConfig = NettyAsyncHttpProviderConfig.class.cast(config.getAsyncHttpProviderConfig()); - } else { + this.config = config; + + if (config.getAsyncHttpProviderConfig() instanceof NettyAsyncHttpProviderConfig) + providerConfig = (NettyAsyncHttpProviderConfig) config.getAsyncHttpProviderConfig(); + else providerConfig = new NettyAsyncHttpProviderConfig(); - } // check if external NioClientSocketChannelFactory is defined if (providerConfig.getSocketChannelFactory() != null) { @@ -217,18 +218,16 @@ public NettyAsyncHttpProvider(AsyncHttpClientConfig config) { secureWebSocketBootstrap = new ClientBootstrap(socketChannelFactory); disableZeroCopy = providerConfig.isDisableZeroCopy(); - this.config = config; - configureNetty(); // This is dangerous as we can't catch a wrong typed ConnectionsPool - ChannelPool cp = providerConfig.getChannelPool(); - if (cp == null && config.isAllowPoolingConnection()) { - cp = new DefaultChannelPool(config, nettyTimer); - } else if (cp == null) { - cp = new NoopChannelPool(); + ChannelPool channelPool = providerConfig.getChannelPool(); + if (channelPool == null && config.isAllowPoolingConnection()) { + channelPool = new DefaultChannelPool(config, nettyTimer); + } else if (channelPool == null) { + channelPool = new NoopChannelPool(); } - this.channelManager = new ChannelManager(config, cp); + this.channelManager = new ChannelManager(config, channelPool); } private Timer newNettyTimer() { @@ -239,23 +238,26 @@ private Timer newNettyTimer() { void configureNetty() { - // FIXME why not do that for other bootstraps + DefaultChannelFuture.setUseDeadLockChecker(providerConfig.isUseDeadLockChecker()); + for (Entry entry : providerConfig.propertiesSet()) { - plainBootstrap.setOption(entry.getKey(), entry.getValue()); + String key = entry.getKey(); + Object value = entry.getValue(); + plainBootstrap.setOption(key, value); + webSocketBootstrap.setOption(key, value); + secureBootstrap.setOption(key, value); + secureWebSocketBootstrap.setOption(key, value); } - DefaultChannelFuture.setUseDeadLockChecker(providerConfig.isUseDeadLockChecker()); + final boolean compressionEnabled = config.isCompressionEnabled(); plainBootstrap.setPipelineFactory(new ChannelPipelineFactory() { public ChannelPipeline getPipeline() throws Exception { ChannelPipeline pipeline = pipeline(); - pipeline.addLast(HTTP_HANDLER, createHttpClientCodec()); - - if (config.isCompressionEnabled()) { + if (compressionEnabled) pipeline.addLast("inflater", new HttpContentDecompressor()); - } pipeline.addLast("chunkedWriter", new ChunkedWriteHandler()); pipeline.addLast(HTTP_PROCESSOR, NettyAsyncHttpProvider.this); return pipeline; @@ -264,7 +266,6 @@ public ChannelPipeline getPipeline() throws Exception { webSocketBootstrap.setPipelineFactory(new ChannelPipelineFactory() { - /* @Override */ public ChannelPipeline getPipeline() throws Exception { ChannelPipeline pipeline = pipeline(); pipeline.addLast(HTTP_HANDLER, createHttpClientCodec()); @@ -272,27 +273,15 @@ public ChannelPipeline getPipeline() throws Exception { return pipeline; } }); - } - - SslHandler createSslHandler(String peerHost, int peerPort) throws GeneralSecurityException, IOException { - SSLEngine sslEngine = SslUtils.getInstance().createClientSSLEngine(config, peerHost, peerPort); - return handshakeTimeoutInMillis > 0 ? new SslHandler(sslEngine, getDefaultBufferPool(), false, nettyTimer, handshakeTimeoutInMillis) - : new SslHandler(sslEngine); - } - - void constructSSLPipeline(final NettyConnectListener cl) { secureBootstrap.setPipelineFactory(new ChannelPipelineFactory() { - /* @Override */ public ChannelPipeline getPipeline() throws Exception { ChannelPipeline pipeline = pipeline(); pipeline.addLast(SSL_HANDLER, new SslInitializer(NettyAsyncHttpProvider.this)); pipeline.addLast(HTTP_HANDLER, createHttpsClientCodec()); - - if (config.isCompressionEnabled()) { + if (compressionEnabled) pipeline.addLast("inflater", new HttpContentDecompressor()); - } pipeline.addLast("chunkedWriter", new ChunkedWriteHandler()); pipeline.addLast(HTTP_PROCESSOR, NettyAsyncHttpProvider.this); return pipeline; @@ -301,23 +290,20 @@ public ChannelPipeline getPipeline() throws Exception { secureWebSocketBootstrap.setPipelineFactory(new ChannelPipelineFactory() { - /* @Override */ public ChannelPipeline getPipeline() throws Exception { ChannelPipeline pipeline = pipeline(); pipeline.addLast(SSL_HANDLER, new SslInitializer(NettyAsyncHttpProvider.this)); pipeline.addLast(HTTP_HANDLER, createHttpsClientCodec()); pipeline.addLast(WS_PROCESSOR, NettyAsyncHttpProvider.this); - return pipeline; } }); + } - if (providerConfig != null) { - for (Entry entry : providerConfig.propertiesSet()) { - secureBootstrap.setOption(entry.getKey(), entry.getValue()); - secureWebSocketBootstrap.setOption(entry.getKey(), entry.getValue()); - } - } + SslHandler createSslHandler(String peerHost, int peerPort) throws GeneralSecurityException, IOException { + SSLEngine sslEngine = SslUtils.getInstance().createClientSSLEngine(config, peerHost, peerPort); + return handshakeTimeoutInMillis > 0 ? new SslHandler(sslEngine, getDefaultBufferPool(), false, nettyTimer, handshakeTimeoutInMillis) + : new SslHandler(sslEngine); } private Channel lookupInCache(UriComponents uri, ProxyServer proxy, ConnectionPoolKeyStrategy strategy) { @@ -954,9 +940,6 @@ private ListenableFuture doConnect(final Request request, final AsyncHand NettyConnectListener connectListener = new NettyConnectListener(config, connectListenerFuture, this, channelManager, channelPreempted, poolKey); - if (useSSl) - constructSSLPipeline(connectListener); - ChannelFuture channelFuture; ClientBootstrap bootstrap = (request.getURI().getScheme().startsWith(WEBSOCKET) && !useProxy) ? (useSSl ? secureWebSocketBootstrap : webSocketBootstrap) : (useSSl ? secureBootstrap : plainBootstrap); @@ -2011,8 +1994,8 @@ private final boolean exitAfterHandlingHead(Channel channel, NettyResponseFuture return false; } - private final void handleHttpResponse(final HttpResponse response, final Channel channel, - final NettyResponseFuture future, AsyncHandler handler) throws Exception { + private final void handleHttpResponse(final HttpResponse response, final Channel channel, final NettyResponseFuture future, + AsyncHandler handler) throws Exception { HttpRequest nettyRequest = future.getNettyRequest(); Request request = future.getRequest(); From 5facba9c056ad95f2e477a7ec03eb8d5b606d654 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 17 Jul 2014 11:48:48 +0200 Subject: [PATCH 431/701] Re-enable Grizzly test, see #630 --- .../http/client/async/AsyncProvidersBasicTest.java | 4 +++- .../async/grizzly/GrizzlyAsyncProviderBasicTest.java | 12 +++--------- .../async/netty/NettyAsyncProviderBasicTest.java | 10 ++++++---- 3 files changed, 12 insertions(+), 14 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 35c6121093..5c1ceec7f6 100755 --- a/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java +++ b/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java @@ -700,6 +700,8 @@ public Response onCompleted(Response response) throws Exception { } } + protected abstract String generatedAcceptEncodingHeader(); + @Test(groups = { "standalone", "default_provider", "async" }) public void asyncDoPostBasicGZIPTest() throws Throwable { AsyncHttpClientConfig cf = new AsyncHttpClientConfig.Builder().setCompressionEnabled(true).build(); @@ -724,7 +726,7 @@ public void asyncDoPostBasicGZIPTest() throws Throwable { public Response onCompleted(Response response) throws Exception { try { assertEquals(response.getStatusCode(), 200); - assertEquals(response.getHeader("X-Accept-Encoding"), "gzip,deflate"); + assertEquals(response.getHeader("X-Accept-Encoding"), generatedAcceptEncodingHeader()); } finally { l.countDown(); } 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 ff472421c3..9882a20ef5 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 @@ -35,12 +35,6 @@ public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig 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. - } - @Override protected AsyncHttpProviderConfig getProviderConfig() { final GrizzlyAsyncHttpProviderConfig config = new GrizzlyAsyncHttpProviderConfig(); @@ -54,9 +48,9 @@ public void customize(TCPNIOTransport transport, FilterChainBuilder builder) { return config; } - // FIXME why disabled? - @Test(groups = { "standalone", "default_provider", "async" }, enabled = false) - public void asyncDoPostBasicGZIPTest() throws Throwable { + @Override + protected String generatedAcceptEncodingHeader() { + return "gzip"; } // FIXME server replies with a foo=bar cookie and yet Grizzly decodes it into foo=value; domain=/; path=/ 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 bf713d309c..4cb857e708 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 @@ -28,9 +28,11 @@ public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { @Override protected AsyncHttpProviderConfig getProviderConfig() { - final NettyAsyncHttpProviderConfig config = - new NettyAsyncHttpProviderConfig(); - config.addProperty("tcpNoDelay", true); - return config; + return new NettyAsyncHttpProviderConfig().addProperty("tcpNoDelay", true); + } + + @Override + protected String generatedAcceptEncodingHeader() { + return "gzip,deflate"; } } From c89a348291229f44e03b190486f083212f3637e5 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 17 Jul 2014 11:51:09 +0200 Subject: [PATCH 432/701] Add comment, see #631 --- .../http/client/async/grizzly/GrizzlyAsyncProviderBasicTest.java | 1 + 1 file changed, 1 insertion(+) 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 9882a20ef5..38a87df634 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 @@ -54,6 +54,7 @@ protected String generatedAcceptEncodingHeader() { } // FIXME server replies with a foo=bar cookie and yet Grizzly decodes it into foo=value; domain=/; path=/ + // see https://github.com/AsyncHttpClient/async-http-client/issues/631 @Test(groups = { "standalone", "default_provider", "async" }, enabled = false) public void asyncDoGetCookieTest() throws Throwable { } From be7225c4cbfee8952347e71f46291c30b259e0a1 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 17 Jul 2014 12:06:19 +0200 Subject: [PATCH 433/701] Fix test --- .../client/async/AsyncProvidersBasicTest.java | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 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 5c1ceec7f6..f7d09995de 100755 --- a/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java +++ b/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java @@ -356,36 +356,38 @@ public Response onCompleted(Response response) throws Exception { } } - // FIXME: fix test @Test(groups = { "standalone", "default_provider", "async" }, enabled = false) public void asyncStatusHEADContentLenghtTest() throws Throwable { 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 AtomicReference responseRef = new AtomicReference(null); + final AtomicReference throwableRef = new AtomicReference(null); client.executeRequest(request, new AsyncCompletionHandlerAdapter() { @Override public Response onCompleted(Response response) throws Exception { - Assert.fail(); + responseRef.set(response); 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(); - } - + throwableRef.set(t); + l.countDown(); } }).get(); if (!l.await(10 * 5 * 1000, TimeUnit.SECONDS)) { Assert.fail("Timeout out"); } + Assert.assertNull(responseRef.get(), "Got a Response while expecting a Throwable"); + Throwable t = throwableRef.get(); + Assert.assertNotNull(t, "Expected a Throwable"); + assertEquals(t.getClass(), IOException.class); + assertEquals(t.getMessage(), "No response received. Connection timed out"); + } finally { client.close(); } From 8578c0df728fa74ed42762aa48f9a0facbf3e717 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 17 Jul 2014 12:08:43 +0200 Subject: [PATCH 434/701] This test seems to be working, re-enabling --- .../async/grizzly/GrizzlyByteBufferCapacityTest.java | 7 ------- 1 file changed, 7 deletions(-) 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 9ee102bb9c..2d1d15d570 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,8 +13,6 @@ 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; @@ -26,9 +24,4 @@ public class GrizzlyByteBufferCapacityTest extends ByteBufferCapacityTest { public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { return ProviderUtil.grizzlyProvider(config); } - - // FIXME - @Test(groups = { "standalone", "default_provider" }, enabled = false) - public void basicByteBufferTest() throws Throwable { - } } From 5d6816a72440a0a89ecb958e36cca0e6e8bbe934 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 17 Jul 2014 12:36:21 +0200 Subject: [PATCH 435/701] Add missing Host header port when using a virtual host, close #632 --- .../providers/netty/NettyAsyncHttpProvider.java | 12 ++---------- 1 file changed, 2 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 7dcf6770c7..a3d5170422 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 @@ -573,16 +573,8 @@ private static HttpRequest construct(AsyncHttpClientConfig config, Request reque } String host = request.getVirtualHost() != null ? request.getVirtualHost() : uri.getHost(); - if (host != null) { - // FIXME why write port when regular host? - if (request.getVirtualHost() != null || uri.getPort() == -1) { - nettyRequestHeaders.set(HttpHeaders.Names.HOST, host); - } else { - nettyRequestHeaders.set(HttpHeaders.Names.HOST, host + ":" + uri.getPort()); - } - } else { - host = "127.0.0.1"; - } + String hostHeader = uri.getPort() == -1 ? host : host + ":" + uri.getPort(); + nettyRequestHeaders.set(HttpHeaders.Names.HOST, hostHeader); if (!m.equals(HttpMethod.CONNECT)) { for (Entry> header : request.getHeaders()) { From edb091ddc033b38f97d6a1049e8c67f52be278e6 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 17 Jul 2014 15:07:37 +0200 Subject: [PATCH 436/701] NettyResponseFuture.get timeout shouldn't cancel http request, close #370 + revert #632 --- .../netty/NettyAsyncHttpProvider.java | 17 +- .../providers/netty/NettyResponseFuture.java | 268 +++++++----------- .../IdleConnectionTimeoutTimerTask.java | 1 - .../timeout/RequestTimeoutTimerTask.java | 8 +- .../netty/NettyAsyncProviderBasicTest.java | 3 + 5 files changed, 113 insertions(+), 184 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 a3d5170422..b331465cb0 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 @@ -506,7 +506,7 @@ public void operationComplete(ChannelFuture cf) { int requestTimeoutInMs = AsyncHttpProviderUtils.requestTimeout(config, future.getRequest()); TimeoutsHolder timeoutsHolder = new TimeoutsHolder(); if (requestTimeoutInMs != -1) { - Timeout requestTimeout = newTimeoutInMs(new RequestTimeoutTimerTask(future, this, timeoutsHolder), requestTimeoutInMs); + Timeout requestTimeout = newTimeoutInMs(new RequestTimeoutTimerTask(future, this, timeoutsHolder, requestTimeoutInMs), requestTimeoutInMs); timeoutsHolder.requestTimeout = requestTimeout; } @@ -573,7 +573,7 @@ private static HttpRequest construct(AsyncHttpClientConfig config, Request reque } String host = request.getVirtualHost() != null ? request.getVirtualHost() : uri.getHost(); - String hostHeader = uri.getPort() == -1 ? host : host + ":" + uri.getPort(); + String hostHeader = request.getVirtualHost() != null || uri.getPort() == -1 ? host : host + ":" + uri.getPort(); nettyRequestHeaders.set(HttpHeaders.Names.HOST, hostHeader); if (!m.equals(HttpMethod.CONNECT)) { @@ -808,7 +808,7 @@ private NettyResponseFuture buildNettyResponseFutureWithCachedChannel(Req if (f == null) { nettyRequest = buildRequest(config, request, uri, false, bufferedBytes, proxyServer); - f = newFuture(uri, request, asyncHandler, nettyRequest, config, this, proxyServer); + f = newFuture(uri, request, asyncHandler, nettyRequest, config, proxyServer); } else if (i == 0) { // only build request on first try nettyRequest = buildRequest(config, request, uri, f.isConnectAllowed(), bufferedBytes, proxyServer); @@ -832,13 +832,12 @@ private NettyResponseFuture buildConnectListenerFuture(AsyncHttpClientCon Request request,// AsyncHandler asyncHandler,// NettyResponseFuture future,// - NettyAsyncHttpProvider provider,// ChannelBuffer buffer,// UriComponents uri) throws IOException { ProxyServer proxyServer = ProxyUtils.getProxyServer(config, request); HttpRequest nettyRequest = NettyAsyncHttpProvider.buildRequest(config, request, uri, true, buffer, proxyServer); if (future == null) { - return NettyAsyncHttpProvider.newFuture(uri, request, asyncHandler, nettyRequest, config, provider, proxyServer); + return NettyAsyncHttpProvider.newFuture(uri, request, asyncHandler, nettyRequest, config, proxyServer); } else { future.setNettyRequest(nettyRequest); future.setRequest(request); @@ -902,7 +901,7 @@ private ListenableFuture doConnect(final Request request, final AsyncHand } } - NettyResponseFuture connectListenerFuture = buildConnectListenerFuture(config, request, asyncHandler, f, this, bufferedBytes, + NettyResponseFuture connectListenerFuture = buildConnectListenerFuture(config, request, asyncHandler, f, bufferedBytes, uri); boolean channelPreempted = false; @@ -1461,15 +1460,13 @@ protected static boolean abortOnWriteCloseException(Throwable cause) { } public static NettyResponseFuture newFuture(UriComponents uri, Request request, AsyncHandler asyncHandler, - HttpRequest nettyRequest, AsyncHttpClientConfig config, NettyAsyncHttpProvider provider, ProxyServer proxyServer) { + HttpRequest nettyRequest, AsyncHttpClientConfig config, ProxyServer proxyServer) { NettyResponseFuture f = new NettyResponseFuture(uri,// request,// asyncHandler,// nettyRequest,// - AsyncHttpProviderUtils.requestTimeout(config, request),// - config.getIdleConnectionTimeoutInMs(),// - provider,// + config.getMaxRequestRetry(),// request.getConnectionPoolKeyStrategy(),// proxyServer); 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 4453b7bd43..b211b5e5b9 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 @@ -50,8 +50,7 @@ */ public final class NettyResponseFuture extends AbstractListenableFuture { - private final static Logger logger = LoggerFactory.getLogger(NettyResponseFuture.class); - public final static String MAX_RETRY = "com.ning.http.client.providers.netty.maxRetry"; + private static final Logger LOGGER = LoggerFactory.getLogger(NettyResponseFuture.class); enum STATE { NEW, POOLED, RECONNECTED, CLOSED, @@ -61,8 +60,6 @@ enum STATE { private final AtomicBoolean isDone = new AtomicBoolean(false); private final AtomicBoolean isCancelled = new AtomicBoolean(false); private AsyncHandler asyncHandler; - private final int requestTimeoutInMs; - private final int idleConnectionTimeoutInMs; private Request request; private HttpRequest nettyRequest; private final AtomicReference content = new AtomicReference(); @@ -71,8 +68,6 @@ enum STATE { private HttpResponse httpResponse; private final AtomicReference exEx = new AtomicReference(); private final AtomicInteger redirectCount = new AtomicInteger(); - private volatile boolean requestTimeoutReached; - private volatile boolean idleConnectionTimeoutReached; private volatile TimeoutsHolder timeoutsHolder; private final AtomicBoolean inAuth = new AtomicBoolean(false); private final AtomicBoolean statusReceived = new AtomicBoolean(false); @@ -95,50 +90,28 @@ public NettyResponseFuture(UriComponents uri,// Request request,// AsyncHandler asyncHandler,// HttpRequest nettyRequest,// - int requestTimeoutInMs,// - int idleConnectionTimeoutInMs,// - NettyAsyncHttpProvider asyncHttpProvider,// + int maxRetry,// ConnectionPoolKeyStrategy connectionPoolKeyStrategy,// ProxyServer proxyServer) { this.asyncHandler = asyncHandler; - this.requestTimeoutInMs = requestTimeoutInMs; - this.idleConnectionTimeoutInMs = idleConnectionTimeoutInMs; this.request = request; this.nettyRequest = nettyRequest; this.uri = uri; this.connectionPoolKeyStrategy = connectionPoolKeyStrategy; this.proxyServer = proxyServer; - - if (System.getProperty(MAX_RETRY) != null) { - maxRetry = Integer.valueOf(System.getProperty(MAX_RETRY)); - } else { - maxRetry = asyncHttpProvider.getConfig().getMaxRequestRetry(); - } + this.maxRetry = maxRetry; writeHeaders = true; writeBody = true; } - protected UriComponents getURI() { - return uri; - } - - protected void setURI(UriComponents uri) { - this.uri = uri; - } - - public ConnectionPoolKeyStrategy getConnectionPoolKeyStrategy() { - return connectionPoolKeyStrategy; - } - - public ProxyServer getProxyServer() { - return proxyServer; - } + /*********************************************/ + /** java.util.concurrent.Future **/ + /*********************************************/ /** * {@inheritDoc} */ - /* @Override */ public boolean isDone() { return isDone.get() || isCancelled.get(); } @@ -146,20 +119,15 @@ public boolean isDone() { /** * {@inheritDoc} */ - /* @Override */ public boolean isCancelled() { return isCancelled.get(); } - void setAsyncHandler(AsyncHandler asyncHandler) { - this.asyncHandler = asyncHandler; - } - /** * {@inheritDoc} */ - /* @Override */ public boolean cancel(boolean force) { + cancelTimeouts(); if (isCancelled.getAndSet(true)) @@ -168,116 +136,44 @@ public boolean cancel(boolean force) { try { Channels.setDiscard(channel); channel.close(); - } catch (Throwable t) { + } catch (Exception t) { // Ignore } - if (!onThrowableCalled.getAndSet(true)) { + + if (!onThrowableCalled.getAndSet(true)) try { + // FIXME should we set the future exception once and for all asyncHandler.onThrowable(new CancellationException()); - } catch (Throwable t) { - logger.warn("cancel", t); + } catch (Exception t) { + // Ignore } - } + latch.countDown(); runListeners(); return true; } - /** - * Is the Future still valid - * - * @return true if response has expired and should be terminated. - */ - public boolean hasExpired() { - return requestTimeoutReached || idleConnectionTimeoutReached; - } - - public void setRequestTimeoutReached() { - this.requestTimeoutReached = true; - } - - public boolean isRequestTimeoutReached() { - return requestTimeoutReached; - } - - public void setIdleConnectionTimeoutReached() { - this.idleConnectionTimeoutReached = true; - } - - public boolean isIdleConnectionTimeoutReached() { - return idleConnectionTimeoutReached; - } - - public void setTimeoutsHolder(TimeoutsHolder timeoutsHolder) { - this.timeoutsHolder = timeoutsHolder; - } - /** * {@inheritDoc} */ - /* @Override */ public V get() throws InterruptedException, ExecutionException { - try { - return get(requestTimeoutInMs, TimeUnit.MILLISECONDS); - } catch (TimeoutException e) { - cancelTimeouts(); - throw new ExecutionException(e); - } - } - - public void cancelTimeouts() { - if (timeoutsHolder != null) { - timeoutsHolder.cancel(); - timeoutsHolder = null; - } + if (!isDone()) + latch.await(); + return getContent(); } /** * {@inheritDoc} */ - /* @Override */ public V get(long l, TimeUnit tu) throws InterruptedException, TimeoutException, ExecutionException { - if (!isDone()) { - boolean expired = false; - if (l == -1) { - latch.await(); - } else { - expired = !latch.await(l, tu); - } - - if (expired) { - isCancelled.set(true); - try { - Channels.setDiscard(channel); - channel.close(); - } catch (Throwable t) { - // Ignore - } - if (!onThrowableCalled.getAndSet(true)) { - try { - TimeoutException te = new TimeoutException(String.format("No response received after %s ms", l)); - try { - asyncHandler.onThrowable(te); - } catch (Throwable t) { - logger.debug("asyncHandler.onThrowable", t); - } - throw new ExecutionException(te); - } finally { - cancelTimeouts(); - } - } - } - isDone.set(true); - - ExecutionException e = exEx.getAndSet(null); - if (e != null) { - throw e; - } - } + if (!isDone() && !latch.await(l, tu)) + throw new TimeoutException(); return getContent(); } V getContent() throws ExecutionException { + + // FIXME why lose the exception??? ExecutionException e = exEx.getAndSet(null); if (e != null) { throw e; @@ -295,7 +191,7 @@ V getContent() throws ExecutionException { try { asyncHandler.onThrowable(ex); } catch (Throwable t) { - logger.debug("asyncHandler.onThrowable", t); + LOGGER.debug("asyncHandler.onThrowable", t); } throw new RuntimeException(ex); } finally { @@ -308,7 +204,11 @@ V getContent() throws ExecutionException { return update; } + /*********************************************/ + /** com.ning.http.clientListenableFuture **/ + /*********************************************/ public final void done() { + cancelTimeouts(); try { @@ -320,8 +220,8 @@ public final void done() { } catch (ExecutionException t) { return; } catch (RuntimeException t) { - Throwable exception = t.getCause() != null ? t.getCause() : t; - exEx.compareAndSet(null, new ExecutionException(exception)); + Throwable exception = t.getCause() != null ? t.getCause() : t; + exEx.compareAndSet(null, new ExecutionException(exception)); } finally { latch.countDown(); @@ -331,6 +231,7 @@ public final void done() { } public final void abort(final Throwable t) { + cancelTimeouts(); if (isDone.get() || isCancelled.getAndSet(true)) @@ -342,7 +243,7 @@ public final void abort(final Throwable t) { try { asyncHandler.onThrowable(t); } catch (Throwable te) { - logger.debug("asyncHandler.onThrowable", te); + LOGGER.debug("asyncHandler.onThrowable", te); } } latch.countDown(); @@ -353,6 +254,70 @@ public void content(V v) { content.set(v); } + /** + * {@inheritDoc} + */ + public void touch() { + touch.set(millisTime()); + } + + public long getLastTouch() { + return touch.get(); + } + + /** + * {@inheritDoc} + */ + public boolean getAndSetWriteHeaders(boolean writeHeaders) { + boolean b = this.writeHeaders; + this.writeHeaders = writeHeaders; + return b; + } + + /** + * {@inheritDoc} + */ + public boolean getAndSetWriteBody(boolean writeBody) { + boolean b = this.writeBody; + this.writeBody = writeBody; + return b; + } + + /*********************************************/ + /** INTERNAL **/ + /*********************************************/ + + protected UriComponents getURI() { + return uri; + } + + protected void setURI(UriComponents uri) { + this.uri = uri; + } + + public ConnectionPoolKeyStrategy getConnectionPoolKeyStrategy() { + return connectionPoolKeyStrategy; + } + + public ProxyServer getProxyServer() { + return proxyServer; + } + + void setAsyncHandler(AsyncHandler asyncHandler) { + this.asyncHandler = asyncHandler; + } + + public void setTimeoutsHolder(TimeoutsHolder timeoutsHolder) { + this.timeoutsHolder = timeoutsHolder; + } + + public void cancelTimeouts() { + if (timeoutsHolder != null) { + timeoutsHolder.cancel(); + timeoutsHolder = null; + } + } + protected final Request getRequest() { return request; } @@ -408,36 +373,7 @@ protected void setState(STATE state) { public boolean getAndSetStatusReceived(boolean sr) { return statusReceived.getAndSet(sr); } - - /** - * {@inheritDoc} - */ - public void touch() { - touch.set(millisTime()); - } - - public long getLastTouch() { - return touch.get(); - } - - /** - * {@inheritDoc} - */ - public boolean getAndSetWriteHeaders(boolean writeHeaders) { - boolean b = this.writeHeaders; - this.writeHeaders = writeHeaders; - return b; - } - - /** - * {@inheritDoc} - */ - public boolean getAndSetWriteBody(boolean writeBody) { - boolean b = this.writeBody; - this.writeBody = writeBody; - return b; - } - + protected void attachChannel(Channel channel) { this.channel = channel; } @@ -475,7 +411,7 @@ protected boolean canRetry() { } public SocketAddress getChannelRemoteAddress() { - return channel() != null? channel().getRemoteAddress(): null; + return channel() != null ? channel().getRemoteAddress() : null; } public void setRequest(Request request) { @@ -488,21 +424,14 @@ public void setRequest(Request request) { * @return true if that {@link Future} cannot be recovered. */ public boolean canBeReplay() { - return !isDone() && canRetry() && !(channel != null && channel.isOpen() && uri.getScheme().compareToIgnoreCase("https") != 0) && !isInAuth(); + return !isDone() && canRetry() && !(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{" + // @@ -510,7 +439,6 @@ public String toString() { ",\n\tisDone=" + isDone + // ",\n\tisCancelled=" + isCancelled + // ",\n\tasyncHandler=" + asyncHandler + // - ",\n\trequestTimeoutInMs=" + requestTimeoutInMs + // ",\n\tnettyRequest=" + nettyRequest + // ",\n\tcontent=" + content + // ",\n\turi=" + uri + // diff --git a/src/main/java/com/ning/http/client/providers/netty/timeout/IdleConnectionTimeoutTimerTask.java b/src/main/java/com/ning/http/client/providers/netty/timeout/IdleConnectionTimeoutTimerTask.java index dbab00c72b..c4fddd5e0b 100644 --- a/src/main/java/com/ning/http/client/providers/netty/timeout/IdleConnectionTimeoutTimerTask.java +++ b/src/main/java/com/ning/http/client/providers/netty/timeout/IdleConnectionTimeoutTimerTask.java @@ -48,7 +48,6 @@ public void run(Timeout timeout) throws Exception { String message = "Idle connection timeout to " + nettyResponseFuture.getChannelRemoteAddress() + " of " + idleConnectionTimeout + " ms"; long durationSinceLastTouch = now - nettyResponseFuture.getLastTouch(); expire(message, durationSinceLastTouch); - nettyResponseFuture.setIdleConnectionTimeoutReached(); } else if (currentIdleConnectionTimeoutInstant < requestTimeoutInstant) { // reschedule diff --git a/src/main/java/com/ning/http/client/providers/netty/timeout/RequestTimeoutTimerTask.java b/src/main/java/com/ning/http/client/providers/netty/timeout/RequestTimeoutTimerTask.java index 236e8334f8..1ac1b48fb8 100644 --- a/src/main/java/com/ning/http/client/providers/netty/timeout/RequestTimeoutTimerTask.java +++ b/src/main/java/com/ning/http/client/providers/netty/timeout/RequestTimeoutTimerTask.java @@ -21,8 +21,11 @@ public class RequestTimeoutTimerTask extends TimeoutTimerTask { - public RequestTimeoutTimerTask(NettyResponseFuture nettyResponseFuture, NettyAsyncHttpProvider provider, TimeoutsHolder timeoutsHolder) { + private final long requestTimeout; + + public RequestTimeoutTimerTask(NettyResponseFuture nettyResponseFuture, NettyAsyncHttpProvider provider, TimeoutsHolder timeoutsHolder, long requestTimeout) { super(nettyResponseFuture, provider, timeoutsHolder); + this.requestTimeout = requestTimeout; } public void run(Timeout timeout) throws Exception { @@ -34,9 +37,8 @@ public void run(Timeout timeout) throws Exception { return; } - String message = "Request timed out to " + nettyResponseFuture.getChannelRemoteAddress() + " of " + nettyResponseFuture.getRequestTimeoutInMs() + " ms"; + String message = "Request timed out to " + nettyResponseFuture.getChannelRemoteAddress() + " of " + requestTimeout + " ms"; long age = millisTime() - nettyResponseFuture.getStart(); expire(message, age); - nettyResponseFuture.setRequestTimeoutReached(); } } 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 4cb857e708..02718102ab 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 @@ -12,6 +12,8 @@ */ package com.ning.http.client.async.netty; +import org.testng.annotations.Test; + import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.AsyncHttpProviderConfig; @@ -19,6 +21,7 @@ import com.ning.http.client.async.ProviderUtil; import com.ning.http.client.providers.netty.NettyAsyncHttpProviderConfig; +@Test public class NettyAsyncProviderBasicTest extends AsyncProvidersBasicTest { @Override From 7e2326c64492f69d59edbe1067d5702eac3ebebf Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 17 Jul 2014 15:44:05 +0200 Subject: [PATCH 437/701] NettyResponseFuture.getContent shouldn't lose registered exception, close #271 --- .../client/providers/netty/NettyResponseFuture.java | 10 ++++------ 1 file changed, 4 insertions(+), 6 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 b211b5e5b9..7cab8adf6e 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 @@ -172,17 +172,15 @@ public V get(long l, TimeUnit tu) throws InterruptedException, TimeoutException, } V getContent() throws ExecutionException { - - // FIXME why lose the exception??? - ExecutionException e = exEx.getAndSet(null); - if (e != null) { + + ExecutionException e = exEx.get(); + if (e != null) throw e; - } V update = content.get(); // No more retry currentRetry.set(maxRetry); - if (exEx.get() == null && !contentProcessed.getAndSet(true)) { + if (!contentProcessed.getAndSet(true)) { try { update = asyncHandler.onCompleted(); } catch (Throwable ex) { From abc7fbd66161921a11866b9ae3720cd14f1492cc Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 17 Jul 2014 16:21:04 +0200 Subject: [PATCH 438/701] Make NettyResponseFuture done and abort mutually exclusive, close #247 --- .../http/client/providers/netty/NettyResponseFuture.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 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 7cab8adf6e..1ffd058833 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 @@ -209,12 +209,12 @@ public final void done() { cancelTimeouts(); + if (!isDone.getAndSet(true) || isCancelled.get()) + return; + try { - if (exEx.get() != null) { - return; - } getContent(); - isDone.set(true); + } catch (ExecutionException t) { return; } catch (RuntimeException t) { From 5efbbee14e9fb07755b6798a08655f2b99f12532 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 17 Jul 2014 18:15:56 +0200 Subject: [PATCH 439/701] Fix NettyResponseFuture.done exit --- .../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 1ffd058833..b7bbc23e8e 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 @@ -209,7 +209,7 @@ public final void done() { cancelTimeouts(); - if (!isDone.getAndSet(true) || isCancelled.get()) + if (isDone.getAndSet(true) || isCancelled.get()) return; try { From 62ab7fa124297e3ba99b4a784f0b449137c4422f Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 17 Jul 2014 18:26:32 +0200 Subject: [PATCH 440/701] Rename AsyncHttpClientConfig parameters, close #622 --- .../http/client/AsyncHttpClientConfig.java | 412 +++++++++--------- .../client/AsyncHttpClientConfigBean.java | 48 +- .../client/AsyncHttpClientConfigDefaults.java | 38 +- .../java/com/ning/http/client/Request.java | 2 +- .../ning/http/client/RequestBuilderBase.java | 12 +- .../http/client/SimpleAsyncHttpClient.java | 26 +- .../apache/ApacheAsyncHttpProvider.java | 16 +- .../grizzly/GrizzlyAsyncHttpProvider.java | 20 +- .../grizzly/GrizzlyConnectionPool.java | 36 +- .../providers/jdk/JDKAsyncHttpProvider.java | 14 +- .../netty/NettyAsyncHttpProvider.java | 30 +- .../providers/netty/pool/ChannelManager.java | 8 +- .../netty/pool/DefaultChannelPool.java | 8 +- .../IdleConnectionTimeoutTimerTask.java | 2 +- .../http/util/AsyncHttpProviderUtils.java | 4 +- .../client/async/AsyncProvidersBasicTest.java | 8 +- .../http/client/async/AuthTimeoutTest.java | 16 +- .../ning/http/client/async/BasicAuthTest.java | 4 +- .../http/client/async/BasicHttpsTest.java | 4 +- .../ning/http/client/async/BodyChunkTest.java | 6 +- .../async/BodyDeferringAsyncHandlerTest.java | 2 +- .../ning/http/client/async/ChunkingTest.java | 10 +- .../http/client/async/ConnectionPoolTest.java | 9 +- .../client/async/FilePartLargeFileTest.java | 2 +- .../client/async/HttpToHttpsRedirectTest.java | 6 +- .../client/async/IdleStateHandlerTest.java | 2 +- .../client/async/MaxConnectionsInThreads.java | 2 +- .../client/async/MaxTotalConnectionTest.java | 12 +- .../http/client/async/NoNullResponseTest.java | 4 +- .../client/async/PerRequestTimeoutTest.java | 10 +- .../http/client/async/PutLargeFileTest.java | 2 +- .../com/ning/http/client/async/RC10KTest.java | 2 +- .../async/RedirectConnectionUsageTest.java | 10 +- .../http/client/async/RemoteSiteTest.java | 14 +- .../client/async/RetryNonBlockingIssue.java | 24 +- .../async/SimpleAsyncHttpClientTest.java | 8 +- .../grizzly/GrizzlyConnectionPoolTest.java | 4 +- .../GrizzlyFeedableBodyGeneratorTest.java | 8 +- .../GrizzlyNoTransferEncodingTest.java | 6 +- .../GrizzlyUnexpectingTimeoutTest.java | 2 +- .../async/netty/NettyConnectionPoolTest.java | 2 +- .../NettyRequestThrottleTimeoutTest.java | 4 +- 42 files changed, 422 insertions(+), 437 deletions(-) diff --git a/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java b/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java index bf2c6f0ff7..72f869f2a0 100644 --- a/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java @@ -38,122 +38,114 @@ * object default behavior by doing: *

    * -Dcom.ning.http.client.AsyncHttpClientConfig.nameOfTheProperty - * ex: - *

    - * -Dcom.ning.http.client.AsyncHttpClientConfig.defaultMaxTotalConnections - * -Dcom.ning.http.client.AsyncHttpClientConfig.defaultMaxTotalConnections - * -Dcom.ning.http.client.AsyncHttpClientConfig.defaultMaxConnectionsPerHost - * -Dcom.ning.http.client.AsyncHttpClientConfig.defaultConnectionTimeoutInMS - * -Dcom.ning.http.client.AsyncHttpClientConfig.defaultIdleConnectionInPoolTimeoutInMS - * -Dcom.ning.http.client.AsyncHttpClientConfig.defaultRequestTimeoutInMS - * -Dcom.ning.http.client.AsyncHttpClientConfig.defaultRedirectsEnabled - * -Dcom.ning.http.client.AsyncHttpClientConfig.defaultMaxRedirects */ public class AsyncHttpClientConfig { - protected int maxTotalConnections; - protected int maxConnectionPerHost; - protected int connectionTimeOutInMs; - protected int webSocketIdleTimeoutInMs; - protected int idleConnectionInPoolTimeoutInMs; - protected int idleConnectionTimeoutInMs; - protected int requestTimeoutInMs; + protected int connectionTimeout; + + protected int maxConnections; + protected int maxConnectionsPerHost; + + protected int requestTimeout; + protected int readTimeout; + protected int webSocketReadTimeout; + + protected boolean allowPoolingConnections; + protected boolean allowPoolingSslConnections; + protected int pooledConnectionIdleTimeout; + protected int connectionTTL; + + protected SSLContext sslContext; + protected HostnameVerifier hostnameVerifier; + protected boolean acceptAnyCertificate; + protected boolean followRedirect; protected int maxRedirects; + protected boolean removeQueryParamOnRedirect; + protected boolean strict302Handling; + + protected ProxyServerSelector proxyServerSelector; + protected boolean useRelativeURIsWithSSLProxies; + protected boolean compressionEnabled; protected String userAgent; - protected boolean allowPoolingConnection; protected ExecutorService applicationThreadPool; - protected ProxyServerSelector proxyServerSelector; - protected SSLContext sslContext; - protected AsyncHttpProviderConfig providerConfig; protected Realm realm; protected List requestFilters; protected List responseFilters; protected List ioExceptionFilters; protected int maxRequestRetry; - protected boolean allowSslConnectionPool; protected boolean disableUrlEncodingForBoundedRequests; - protected boolean removeQueryParamOnRedirect; - protected HostnameVerifier hostnameVerifier; protected int ioThreadMultiplier; - protected boolean strict302Handling; - protected boolean useRelativeURIsWithSSLProxies; - protected int maxConnectionLifeTimeInMs; protected TimeConverter timeConverter; - protected boolean acceptAnyCertificate; + protected AsyncHttpProviderConfig providerConfig; protected AsyncHttpClientConfig() { } - private AsyncHttpClientConfig(int maxTotalConnections, - int maxConnectionPerHost, - int connectionTimeOutInMs, - int webSocketTimeoutInMs, - int idleConnectionInPoolTimeoutInMs, - int idleConnectionTimeoutInMs, - int requestTimeoutInMs, - int connectionMaxLifeTimeInMs, - boolean followRedirect, - int maxRedirects, - boolean compressionEnabled, - String userAgent, - boolean keepAlive, - ExecutorService applicationThreadPool, - ProxyServerSelector proxyServerSelector, - SSLContext sslContext, - AsyncHttpProviderConfig providerConfig, - Realm realm, - List requestFilters, - List responseFilters, - List ioExceptionFilters, - int maxRequestRetry, - boolean allowSslConnectionCaching, - boolean disableUrlEncodingForBoundedRequests, - boolean removeQueryParamOnRedirect, - HostnameVerifier hostnameVerifier, - int ioThreadMultiplier, - boolean strict302Handling, - boolean useRelativeURIsWithSSLProxies, - TimeConverter timeConverter, // - boolean acceptAnyCertificate) { - - this.maxTotalConnections = maxTotalConnections; - this.maxConnectionPerHost = maxConnectionPerHost; - this.connectionTimeOutInMs = connectionTimeOutInMs; - this.webSocketIdleTimeoutInMs = webSocketTimeoutInMs; - this.idleConnectionInPoolTimeoutInMs = idleConnectionInPoolTimeoutInMs; - this.idleConnectionTimeoutInMs = idleConnectionTimeoutInMs; - this.requestTimeoutInMs = requestTimeoutInMs; - this.maxConnectionLifeTimeInMs = connectionMaxLifeTimeInMs; + private AsyncHttpClientConfig(int connectionTimeout,// + int maxConnections,// + int maxConnectionsPerHost,// + int requestTimeout,// + int readTimeout,// + int webSocketIdleTimeout,// + boolean allowPoolingConnection,// + boolean allowSslConnectionPool,// + int idleConnectionInPoolTimeout,// + int maxConnectionLifeTime,// + SSLContext sslContext, // + HostnameVerifier hostnameVerifier,// + boolean acceptAnyCertificate, // + boolean followRedirect, // + int maxRedirects, // + boolean removeQueryParamOnRedirect,// + boolean strict302Handling, // + ExecutorService applicationThreadPool,// + ProxyServerSelector proxyServerSelector, // + boolean useRelativeURIsWithSSLProxies, // + boolean compressionEnabled, // + String userAgent,// + Realm realm,// + List requestFilters,// + List responseFilters,// + List ioExceptionFilters,// + int maxRequestRetry, // + boolean disableUrlEncodingForBoundedRequests, // + int ioThreadMultiplier, // + TimeConverter timeConverter,// + AsyncHttpProviderConfig providerConfig) { + + this.connectionTimeout = connectionTimeout; + this.maxConnections = maxConnections; + this.maxConnectionsPerHost = maxConnectionsPerHost; + this.requestTimeout = requestTimeout; + this.readTimeout = readTimeout; + this.webSocketReadTimeout = webSocketIdleTimeout; + this.allowPoolingConnections = allowPoolingConnection; + this.allowPoolingSslConnections = allowSslConnectionPool; + this.pooledConnectionIdleTimeout = idleConnectionInPoolTimeout; + this.connectionTTL = maxConnectionLifeTime; + this.sslContext = sslContext; + this.hostnameVerifier = hostnameVerifier; + this.acceptAnyCertificate = acceptAnyCertificate; this.followRedirect = followRedirect; this.maxRedirects = maxRedirects; + this.removeQueryParamOnRedirect = removeQueryParamOnRedirect; + this.strict302Handling = strict302Handling; + this.proxyServerSelector = proxyServerSelector; + this.useRelativeURIsWithSSLProxies = useRelativeURIsWithSSLProxies; this.compressionEnabled = compressionEnabled; this.userAgent = userAgent; - this.allowPoolingConnection = keepAlive; - this.sslContext = sslContext; - this.providerConfig = providerConfig; + this.applicationThreadPool = applicationThreadPool == null ? Executors.newCachedThreadPool() : applicationThreadPool; this.realm = realm; this.requestFilters = requestFilters; this.responseFilters = responseFilters; this.ioExceptionFilters = ioExceptionFilters; this.maxRequestRetry = maxRequestRetry; - this.allowSslConnectionPool = allowSslConnectionCaching; - this.removeQueryParamOnRedirect = removeQueryParamOnRedirect; - this.hostnameVerifier = hostnameVerifier; - this.ioThreadMultiplier = ioThreadMultiplier; - this.strict302Handling = strict302Handling; - this.useRelativeURIsWithSSLProxies = useRelativeURIsWithSSLProxies; - - if (applicationThreadPool == null) { - this.applicationThreadPool = Executors.newCachedThreadPool(); - } else { - this.applicationThreadPool = applicationThreadPool; - } - this.proxyServerSelector = proxyServerSelector; this.disableUrlEncodingForBoundedRequests = disableUrlEncodingForBoundedRequests; + this.ioThreadMultiplier = ioThreadMultiplier; this.timeConverter = timeConverter; - this.acceptAnyCertificate = acceptAnyCertificate; + this.providerConfig = providerConfig; } /** @@ -161,8 +153,8 @@ private AsyncHttpClientConfig(int maxTotalConnections, * * @return the maximum number of connections an {@link com.ning.http.client.AsyncHttpClient} can handle. */ - public int getMaxTotalConnections() { - return maxTotalConnections; + public int getMaxConnections() { + return maxConnections; } /** @@ -170,8 +162,8 @@ public int getMaxTotalConnections() { * * @return the maximum number of connections per host an {@link com.ning.http.client.AsyncHttpClient} can handle. */ - public int getMaxConnectionPerHost() { - return maxConnectionPerHost; + public int getMaxConnectionsPerHost() { + return maxConnectionsPerHost; } /** @@ -179,16 +171,16 @@ public int getMaxConnectionPerHost() { * * @return the maximum time in millisecond an {@link com.ning.http.client.AsyncHttpClient} can wait when connecting to a remote host */ - public int getConnectionTimeoutInMs() { - return connectionTimeOutInMs; + public int getConnectionTimeout() { + return connectionTimeout; } /** * Return the maximum time, in milliseconds, a {@link com.ning.http.client.websocket.WebSocket} may be idle before being timed out. * @return the maximum time, in milliseconds, a {@link com.ning.http.client.websocket.WebSocket} may be idle before being timed out. */ - public int getWebSocketIdleTimeoutInMs() { - return webSocketIdleTimeoutInMs; + public int getWebSocketReadTimeout() { + return webSocketReadTimeout; } /** @@ -196,8 +188,8 @@ public int getWebSocketIdleTimeoutInMs() { * * @return the maximum time in millisecond an {@link com.ning.http.client.AsyncHttpClient} can stay idle. */ - public int getIdleConnectionTimeoutInMs() { - return idleConnectionTimeoutInMs; + public int getReadTimeout() { + return readTimeout; } /** @@ -207,8 +199,8 @@ public int getIdleConnectionTimeoutInMs() { * @return the maximum time in millisecond an {@link com.ning.http.client.AsyncHttpClient} will keep connection * in pool. */ - public int getIdleConnectionInPoolTimeoutInMs() { - return idleConnectionInPoolTimeoutInMs; + public int getPooledConnectionIdleTimeout() { + return pooledConnectionIdleTimeout; } /** @@ -216,8 +208,8 @@ public int getIdleConnectionInPoolTimeoutInMs() { * * @return the maximum time in millisecond an {@link com.ning.http.client.AsyncHttpClient} wait for a response */ - public int getRequestTimeoutInMs() { - return requestTimeoutInMs; + public int getRequestTimeout() { + return requestTimeout; } /** @@ -241,10 +233,10 @@ public int getMaxRedirects() { /** * Is the {@link ChannelPool} support enabled. * - * @return true if keep-alive is enabled + * @return if polling connections is enabled */ - public boolean isAllowPoolingConnection() { - return allowPoolingConnection; + public boolean isAllowPoolingConnections() { + return allowPoolingConnections; } /** @@ -353,11 +345,10 @@ public int getMaxRequestRetry() { * * @return true is enabled. */ - public boolean isSslConnectionPoolEnabled() { - return allowSslConnectionPool; + public boolean isAllowPoolingSslConnections() { + return allowPoolingSslConnections; } - /** * @return the disableUrlEncodingForBoundedRequests */ @@ -387,8 +378,8 @@ public boolean isValid() { // isShutdown() will thrown an exception in an EE7 environment // when using a ManagedExecutorService. // When this is the case, we assume it's running. + return true; } - return true; } /** @@ -433,14 +424,14 @@ public boolean isStrict302Handling() { 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; + public int getConnectionTTL() { + return connectionTTL; } /** @@ -461,40 +452,39 @@ public boolean isAcceptAnyCertificate() { * Builder for an {@link AsyncHttpClient} */ public static class Builder { - private int maxTotalConnections = defaultMaxTotalConnections(); - private int maxConnectionPerHost = defaultMaxConnectionPerHost(); - private int connectionTimeOutInMs = defaultConnectionTimeOutInMs(); - private int webSocketIdleTimeoutInMs = defaultWebSocketIdleTimeoutInMs(); - private int idleConnectionInPoolTimeoutInMs = defaultIdleConnectionInPoolTimeoutInMs(); - private int idleConnectionTimeoutInMs = defaultIdleConnectionTimeoutInMs(); - private int requestTimeoutInMs = defaultRequestTimeoutInMs(); - private int maxConnectionLifeTimeInMs = defaultMaxConnectionLifeTimeInMs(); + private int connectionTimeout = defaultConnectionTimeout(); + private int maxConnections = defaultMaxConnections(); + private int maxConnectionsPerHost = defaultMaxConnectionsPerHost(); + private int requestTimeout = defaultRequestTimeout(); + private int readTimeout = defaultReadTimeout(); + private int webSocketReadTimeout = defaultWebSocketReadTimeout(); + private boolean allowPoolingConnections = defaultAllowPoolingConnections(); + private boolean allowPoolingSslConnections = defaultAllowPoolingSslConnections(); + private int pooledConnectionIdleTimeout = defaultPooledConnectionIdleTimeout(); + private int connectionTTL = defaultConnectionTTL(); + private SSLContext sslContext; + private HostnameVerifier hostnameVerifier = defaultHostnameVerifier(); + private boolean acceptAnyCertificate = defaultAcceptAnyCertificate(); private boolean followRedirect = defaultFollowRedirect(); - private int maxDefaultRedirects = defaultMaxRedirects(); - private boolean compressionEnabled = defaultCompressionEnabled(); - private String userAgent = defaultUserAgent(); - private boolean useProxyProperties = defaultUseProxyProperties(); - private boolean useProxySelector = defaultUseProxySelector(); - private boolean allowPoolingConnection = defaultAllowPoolingConnection(); - private boolean useRelativeURIsWithSSLProxies = defaultUseRelativeURIsWithSSLProxies(); - private int maxRequestRetry = defaultMaxRequestRetry(); - private int ioThreadMultiplier = defaultIoThreadMultiplier(); - private boolean allowSslConnectionPool = defaultAllowSslConnectionPool(); - private boolean disableUrlEncodingForBoundedRequests = defaultDisableUrlEncodingForBoundedRequests(); + private int maxRedirects = defaultMaxRedirects(); private boolean removeQueryParamOnRedirect = defaultRemoveQueryParamOnRedirect(); private boolean strict302Handling = defaultStrict302Handling(); - private HostnameVerifier hostnameVerifier = defaultHostnameVerifier(); - private boolean acceptAnyCertificate = defaultAcceptAnyCertificate(); - - private ExecutorService applicationThreadPool; private ProxyServerSelector proxyServerSelector = null; - private SSLContext sslContext; - private AsyncHttpProviderConfig providerConfig; + private boolean useProxySelector = defaultUseProxySelector(); + private boolean useProxyProperties = defaultUseProxyProperties(); + private boolean useRelativeURIsWithSSLProxies = defaultUseRelativeURIsWithSSLProxies(); + private boolean compressionEnabled = defaultCompressionEnabled(); + private String userAgent = defaultUserAgent(); + private ExecutorService applicationThreadPool; private Realm realm; private final List requestFilters = new LinkedList(); private final List responseFilters = new LinkedList(); private final List ioExceptionFilters = new LinkedList(); + private int maxRequestRetry = defaultMaxRequestRetry(); + private boolean disableUrlEncodingForBoundedRequests = defaultDisableUrlEncodingForBoundedRequests(); + private int ioThreadMultiplier = defaultIoThreadMultiplier(); private TimeConverter timeConverter; + private AsyncHttpProviderConfig providerConfig; public Builder() { } @@ -502,57 +492,57 @@ public Builder() { /** * Set the maximum number of connections an {@link com.ning.http.client.AsyncHttpClient} can handle. * - * @param maxTotalConnections the maximum number of connections an {@link com.ning.http.client.AsyncHttpClient} can handle. + * @param maxConnections the maximum number of connections an {@link com.ning.http.client.AsyncHttpClient} can handle. * @return a {@link Builder} */ - public Builder setMaximumConnectionsTotal(int maxTotalConnections) { - this.maxTotalConnections = maxTotalConnections; + public Builder setMaxConnections(int maxConnections) { + this.maxConnections = maxConnections; return this; } /** * Set the maximum number of connections per hosts an {@link com.ning.http.client.AsyncHttpClient} can handle. * - * @param maxConnectionPerHost the maximum number of connections per host an {@link com.ning.http.client.AsyncHttpClient} can handle. + * @param maxConnectionsPerHost the maximum number of connections per host an {@link com.ning.http.client.AsyncHttpClient} can handle. * @return a {@link Builder} */ - public Builder setMaximumConnectionsPerHost(int maxConnectionPerHost) { - this.maxConnectionPerHost = maxConnectionPerHost; + public Builder setMaxConnectionsPerHost(int maxConnectionsPerHost) { + this.maxConnectionsPerHost = maxConnectionsPerHost; return this; } /** * Set the maximum time in millisecond an {@link com.ning.http.client.AsyncHttpClient} can wait when connecting to a remote host * - * @param connectionTimeOutInMs the maximum time in millisecond an {@link com.ning.http.client.AsyncHttpClient} can wait when connecting to a remote host + * @param connectionTimeOut the maximum time in millisecond an {@link com.ning.http.client.AsyncHttpClient} can wait when connecting to a remote host * @return a {@link Builder} */ - public Builder setConnectionTimeoutInMs(int connectionTimeOutInMs) { - this.connectionTimeOutInMs = connectionTimeOutInMs; + public Builder setConnectionTimeout(int connectionTimeOut) { + this.connectionTimeout = connectionTimeOut; return this; } /** * Set the maximum time in millisecond an {@link com.ning.http.client.websocket.WebSocket} can stay idle. * - * @param webSocketIdleTimeoutInMs + * @param webSocketIdleTimeout * the maximum time in millisecond an {@link com.ning.http.client.websocket.WebSocket} can stay idle. * @return a {@link Builder} */ - public Builder setWebSocketIdleTimeoutInMs(int webSocketIdleTimeoutInMs) { - this.webSocketIdleTimeoutInMs = webSocketIdleTimeoutInMs; + public Builder setWebSocketIdleTimeout(int webSocketIdleTimeout) { + this.webSocketReadTimeout = webSocketIdleTimeout; return this; } /** * Set the maximum time in millisecond an {@link com.ning.http.client.AsyncHttpClient} can stay idle. * - * @param idleConnectionTimeoutInMs + * @param readTimeout * the maximum time in millisecond an {@link com.ning.http.client.AsyncHttpClient} can stay idle. * @return a {@link Builder} */ - public Builder setIdleConnectionTimeoutInMs(int idleConnectionTimeoutInMs) { - this.idleConnectionTimeoutInMs = idleConnectionTimeoutInMs; + public Builder setReadTimeout(int readTimeout) { + this.readTimeout = readTimeout; return this; } @@ -560,24 +550,24 @@ public Builder setIdleConnectionTimeoutInMs(int idleConnectionTimeoutInMs) { * Set the maximum time in millisecond an {@link com.ning.http.client.AsyncHttpClient} will keep connection * idle in pool. * - * @param idleConnectionInPoolTimeoutInMs + * @param idleConnectionInPoolTimeout * the maximum time in millisecond an {@link com.ning.http.client.AsyncHttpClient} will keep connection * idle in pool. * @return a {@link Builder} */ - public Builder setIdleConnectionInPoolTimeoutInMs(int idleConnectionInPoolTimeoutInMs) { - this.idleConnectionInPoolTimeoutInMs = idleConnectionInPoolTimeoutInMs; + public Builder setPooledConnectionIdleTimeout(int pooledConnectionIdleTimeout) { + this.pooledConnectionIdleTimeout = pooledConnectionIdleTimeout; return this; } /** * Set the maximum time in millisecond an {@link com.ning.http.client.AsyncHttpClient} wait for a response * - * @param requestTimeoutInMs the maximum time in millisecond an {@link com.ning.http.client.AsyncHttpClient} wait for a response + * @param requestTimeout the maximum time in millisecond an {@link com.ning.http.client.AsyncHttpClient} wait for a response * @return a {@link Builder} */ - public Builder setRequestTimeoutInMs(int requestTimeoutInMs) { - this.requestTimeoutInMs = requestTimeoutInMs; + public Builder setRequestTimeout(int requestTimeout) { + this.requestTimeout = requestTimeout; return this; } @@ -595,11 +585,11 @@ public Builder setFollowRedirect(boolean followRedirect) { /** * Set the maximum number of HTTP redirect * - * @param maxDefaultRedirects the maximum number of HTTP redirect + * @param maxRedirects the maximum number of HTTP redirect * @return a {@link Builder} */ - public Builder setMaximumNumberOfRedirects(int maxDefaultRedirects) { - this.maxDefaultRedirects = maxDefaultRedirects; + public Builder setMaxRedirects(int maxRedirects) { + this.maxRedirects = maxRedirects; return this; } @@ -628,11 +618,11 @@ public Builder setUserAgent(String userAgent) { /** * Set true if connection can be pooled by a {@link ChannelPool}. Default is true. * - * @param allowPoolingConnection true if connection can be pooled by a {@link ChannelPool} + * @param allowPoolingConnections true if connection can be pooled by a {@link ChannelPool} * @return a {@link Builder} */ - public Builder setAllowPoolingConnection(boolean allowPoolingConnection) { - this.allowPoolingConnection = allowPoolingConnection; + public Builder setAllowPoolingConnections(boolean allowPoolingConnections) { + this.allowPoolingConnections = allowPoolingConnections; return this; } @@ -788,11 +778,11 @@ public Builder setMaxRequestRetry(int maxRequestRetry) { /** * Return true is if connections pooling is enabled. * - * @param allowSslConnectionPool true if enabled + * @param allowPoolingSslConnections true if enabled * @return this */ - public Builder setAllowSslConnectionPool(boolean allowSslConnectionPool) { - this.allowSslConnectionPool = allowSslConnectionPool; + public Builder setAllowPoolingSslConnections(boolean allowPoolingSslConnections) { + this.allowPoolingSslConnections = allowPoolingSslConnections; return this; } @@ -877,7 +867,7 @@ 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. * @@ -894,12 +884,12 @@ public Builder setUseRelativeURIsWithSSLProxies(boolean useRelativeURIsWithSSLPr /** * 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 + * @param connectionTTL 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.maxConnectionLifeTimeInMs = maxConnectionLifeTimeInMs; - return this; + public Builder setConnectionTTL(int connectionTTL) { + this.connectionTTL = connectionTTL; + return this; } public Builder setTimeConverter(TimeConverter timeConverter) { @@ -918,18 +908,18 @@ public Builder setAcceptAnyCertificate(boolean acceptAnyCertificate) { * @param prototype the configuration to use as a prototype. */ public Builder(AsyncHttpClientConfig prototype) { - allowPoolingConnection = prototype.isAllowPoolingConnection(); + allowPoolingConnections = prototype.isAllowPoolingConnections(); providerConfig = prototype.getAsyncHttpProviderConfig(); - connectionTimeOutInMs = prototype.getConnectionTimeoutInMs(); - idleConnectionInPoolTimeoutInMs = prototype.getIdleConnectionInPoolTimeoutInMs(); - idleConnectionTimeoutInMs = prototype.getIdleConnectionTimeoutInMs(); - maxConnectionPerHost = prototype.getMaxConnectionPerHost(); - maxConnectionLifeTimeInMs = prototype.getMaxConnectionLifeTimeInMs(); - maxDefaultRedirects = prototype.getMaxRedirects(); - maxTotalConnections = prototype.getMaxTotalConnections(); + connectionTimeout = prototype.getConnectionTimeout(); + pooledConnectionIdleTimeout = prototype.getPooledConnectionIdleTimeout(); + readTimeout = prototype.getReadTimeout(); + maxConnectionsPerHost = prototype.getMaxConnectionsPerHost(); + connectionTTL = prototype.getConnectionTTL(); + maxRedirects = prototype.getMaxRedirects(); + maxConnections = prototype.getMaxConnections(); proxyServerSelector = prototype.getProxyServerSelector(); realm = prototype.getRealm(); - requestTimeoutInMs = prototype.getRequestTimeoutInMs(); + requestTimeout = prototype.getRequestTimeout(); sslContext = prototype.getSSLContext(); userAgent = prototype.getUserAgent(); followRedirect = prototype.isFollowRedirect(); @@ -947,7 +937,7 @@ public Builder(AsyncHttpClientConfig prototype) { disableUrlEncodingForBoundedRequests = prototype.isDisableUrlEncodingForBoundedRequests(); ioThreadMultiplier = prototype.getIoThreadMultiplier(); maxRequestRetry = prototype.getMaxRequestRetry(); - allowSslConnectionPool = prototype.isAllowPoolingConnection(); + allowPoolingSslConnections = prototype.isAllowPoolingConnections(); removeQueryParamOnRedirect = prototype.isRemoveQueryParamOnRedirect(); hostnameVerifier = prototype.getHostnameVerifier(); strict302Handling = prototype.isStrict302Handling(); @@ -962,15 +952,13 @@ public Builder(AsyncHttpClientConfig prototype) { */ public AsyncHttpClientConfig build() { 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; - } - }); + applicationThreadPool = Executors.newCachedThreadPool(new ThreadFactory() { + public Thread newThread(Runnable r) { + Thread t = new Thread(r, "AsyncHttpClient-Callback"); + t.setDaemon(true); + return t; + } + }); } if (proxyServerSelector == null && useProxySelector) { @@ -985,37 +973,37 @@ public Thread newThread(Runnable r) { proxyServerSelector = ProxyServerSelector.NO_PROXY_SELECTOR; } - return new AsyncHttpClientConfig(maxTotalConnections, // - maxConnectionPerHost, // - connectionTimeOutInMs, // - webSocketIdleTimeoutInMs, // - idleConnectionInPoolTimeoutInMs, // - idleConnectionTimeoutInMs, // - requestTimeoutInMs, // - maxConnectionLifeTimeInMs, // + return new AsyncHttpClientConfig(connectionTimeout,// + maxConnections,// + maxConnectionsPerHost,// + requestTimeout,// + readTimeout,// + webSocketReadTimeout,// + allowPoolingConnections,// + allowPoolingSslConnections,// + pooledConnectionIdleTimeout,// + connectionTTL,// + sslContext, // + hostnameVerifier,// + acceptAnyCertificate, // followRedirect, // - maxDefaultRedirects, // - compressionEnabled, // - userAgent, // - allowPoolingConnection, // + maxRedirects, // + removeQueryParamOnRedirect,// + strict302Handling, // applicationThreadPool, // proxyServerSelector, // - sslContext, // - providerConfig, // - realm, // + useRelativeURIsWithSSLProxies, // + compressionEnabled, // + userAgent,// + realm,// requestFilters, // - responseFilters, // - ioExceptionFilters, // + responseFilters,// + ioExceptionFilters,// maxRequestRetry, // - allowSslConnectionPool, // disableUrlEncodingForBoundedRequests, // - removeQueryParamOnRedirect, // - hostnameVerifier, // ioThreadMultiplier, // - strict302Handling, // - useRelativeURIsWithSSLProxies, // - timeConverter, // - acceptAnyCertificate); + timeConverter,// + providerConfig); } } } diff --git a/src/main/java/com/ning/http/client/AsyncHttpClientConfigBean.java b/src/main/java/com/ning/http/client/AsyncHttpClientConfigBean.java index 1877b849ae..a6b8eaf6a6 100644 --- a/src/main/java/com/ning/http/client/AsyncHttpClientConfigBean.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClientConfigBean.java @@ -45,23 +45,23 @@ void configureFilters() { } void configureDefaults() { - maxTotalConnections = defaultMaxTotalConnections(); - maxConnectionPerHost = defaultMaxConnectionPerHost(); - connectionTimeOutInMs = defaultConnectionTimeOutInMs(); - webSocketIdleTimeoutInMs = defaultWebSocketIdleTimeoutInMs(); - idleConnectionInPoolTimeoutInMs = defaultIdleConnectionInPoolTimeoutInMs(); - idleConnectionTimeoutInMs = defaultIdleConnectionTimeoutInMs(); - requestTimeoutInMs = defaultRequestTimeoutInMs(); - maxConnectionLifeTimeInMs = defaultMaxConnectionLifeTimeInMs(); + maxConnections = defaultMaxConnections(); + maxConnectionsPerHost = defaultMaxConnectionsPerHost(); + connectionTimeout = defaultConnectionTimeout(); + webSocketReadTimeout = defaultWebSocketReadTimeout(); + pooledConnectionIdleTimeout = defaultPooledConnectionIdleTimeout(); + readTimeout = defaultReadTimeout(); + requestTimeout = defaultRequestTimeout(); + connectionTTL = defaultConnectionTTL(); followRedirect = defaultFollowRedirect(); maxRedirects = defaultMaxRedirects(); compressionEnabled = defaultCompressionEnabled(); userAgent = defaultUserAgent(); - allowPoolingConnection = defaultAllowPoolingConnection(); + allowPoolingConnections = defaultAllowPoolingConnections(); useRelativeURIsWithSSLProxies = defaultUseRelativeURIsWithSSLProxies(); maxRequestRetry = defaultMaxRequestRetry(); ioThreadMultiplier = defaultIoThreadMultiplier(); - allowSslConnectionPool = defaultAllowSslConnectionPool(); + allowPoolingSslConnections = defaultAllowPoolingSslConnections(); disableUrlEncodingForBoundedRequests = defaultDisableUrlEncodingForBoundedRequests(); removeQueryParamOnRedirect = defaultRemoveQueryParamOnRedirect(); strict302Handling = defaultStrict302Handling(); @@ -86,22 +86,22 @@ public Thread newThread(Runnable r) { } public AsyncHttpClientConfigBean setMaxTotalConnections(int maxTotalConnections) { - this.maxTotalConnections = maxTotalConnections; + this.maxConnections = maxTotalConnections; return this; } public AsyncHttpClientConfigBean setMaxConnectionPerHost(int maxConnectionPerHost) { - this.maxConnectionPerHost = maxConnectionPerHost; + this.maxConnectionsPerHost = maxConnectionPerHost; return this; } - public AsyncHttpClientConfigBean setConnectionTimeOutInMs(int connectionTimeOutInMs) { - this.connectionTimeOutInMs = connectionTimeOutInMs; + public AsyncHttpClientConfigBean setConnectionTimeOut(int connectionTimeOut) { + this.connectionTimeout = connectionTimeOut; return this; } - public AsyncHttpClientConfigBean setIdleConnectionInPoolTimeoutInMs(int idleConnectionInPoolTimeoutInMs) { - this.idleConnectionInPoolTimeoutInMs = idleConnectionInPoolTimeoutInMs; + public AsyncHttpClientConfigBean setIdleConnectionInPoolTimeout(int idleConnectionInPoolTimeout) { + this.pooledConnectionIdleTimeout = idleConnectionInPoolTimeout; return this; } @@ -110,18 +110,18 @@ public AsyncHttpClientConfigBean setStrict302Handling(boolean strict302Handling) return this; } - public AsyncHttpClientConfigBean setIdleConnectionTimeoutInMs(int idleConnectionTimeoutInMs) { - this.idleConnectionTimeoutInMs = idleConnectionTimeoutInMs; + public AsyncHttpClientConfigBean setIdleConnectionTimeout(int idleConnectionTimeout) { + this.readTimeout = idleConnectionTimeout; return this; } - public AsyncHttpClientConfigBean setRequestTimeoutInMs(int requestTimeoutInMs) { - this.requestTimeoutInMs = requestTimeoutInMs; + public AsyncHttpClientConfigBean setRequestTimeout(int requestTimeout) { + this.requestTimeout = requestTimeout; return this; } - public AsyncHttpClientConfigBean setMaxConnectionLifeTimeInMs(int maxConnectionLifeTimeInMs) { - this.maxConnectionLifeTimeInMs = maxConnectionLifeTimeInMs; + public AsyncHttpClientConfigBean setMaxConnectionLifeTime(int maxConnectionLifeTime) { + this.connectionTTL = maxConnectionLifeTime; return this; } @@ -146,7 +146,7 @@ public AsyncHttpClientConfigBean setUserAgent(String userAgent) { } public AsyncHttpClientConfigBean setAllowPoolingConnection(boolean allowPoolingConnection) { - this.allowPoolingConnection = allowPoolingConnection; + this.allowPoolingConnections = allowPoolingConnection; return this; } @@ -204,7 +204,7 @@ public AsyncHttpClientConfigBean setMaxRequestRetry(int maxRequestRetry) { } public AsyncHttpClientConfigBean setAllowSslConnectionPool(boolean allowSslConnectionPool) { - this.allowSslConnectionPool = allowSslConnectionPool; + this.allowPoolingSslConnections = allowSslConnectionPool; return this; } diff --git a/src/main/java/com/ning/http/client/AsyncHttpClientConfigDefaults.java b/src/main/java/com/ning/http/client/AsyncHttpClientConfigDefaults.java index 215dc577a0..b0f8f50f7f 100644 --- a/src/main/java/com/ning/http/client/AsyncHttpClientConfigDefaults.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClientConfigDefaults.java @@ -25,36 +25,36 @@ private AsyncHttpClientConfigDefaults() { public static final String ASYNC_CLIENT = AsyncHttpClientConfig.class.getName() + "."; - public static int defaultMaxTotalConnections() { - return Integer.getInteger(ASYNC_CLIENT + "maxTotalConnections", -1); + public static int defaultMaxConnections() { + return Integer.getInteger(ASYNC_CLIENT + "maxConnections", -1); } - public static int defaultMaxConnectionPerHost() { + public static int defaultMaxConnectionsPerHost() { return Integer.getInteger(ASYNC_CLIENT + "maxConnectionsPerHost", -1); } - public static int defaultConnectionTimeOutInMs() { - return Integer.getInteger(ASYNC_CLIENT + "connectionTimeoutInMs", 60 * 1000); + public static int defaultConnectionTimeout() { + return Integer.getInteger(ASYNC_CLIENT + "connectionTimeout", 60 * 1000); } - public static int defaultIdleConnectionInPoolTimeoutInMs() { - return Integer.getInteger(ASYNC_CLIENT + "idleConnectionInPoolTimeoutInMs", 60 * 1000); + public static int defaultPooledConnectionIdleTimeout() { + return Integer.getInteger(ASYNC_CLIENT + "pooledConnectionIdleTimeout", 60 * 1000); } - public static int defaultIdleConnectionTimeoutInMs() { - return Integer.getInteger(ASYNC_CLIENT + "idleConnectionTimeoutInMs", 60 * 1000); + public static int defaultReadTimeout() { + return Integer.getInteger(ASYNC_CLIENT + "readTimeout", 60 * 1000); } - public static int defaultRequestTimeoutInMs() { - return Integer.getInteger(ASYNC_CLIENT + "requestTimeoutInMs", 60 * 1000); + public static int defaultRequestTimeout() { + return Integer.getInteger(ASYNC_CLIENT + "requestTimeout", 60 * 1000); } - public static int defaultWebSocketIdleTimeoutInMs() { - return Integer.getInteger(ASYNC_CLIENT + "webSocketTimoutInMS", 15 * 60 * 1000); + public static int defaultWebSocketReadTimeout() { + return Integer.getInteger(ASYNC_CLIENT + "webSocketReadTimeout", 15 * 60 * 1000); } - public static int defaultMaxConnectionLifeTimeInMs() { - return Integer.getInteger(ASYNC_CLIENT + "maxConnectionLifeTimeInMs", -1); + public static int defaultConnectionTTL() { + return Integer.getInteger(ASYNC_CLIENT + "connectionTTL", -1); } public static boolean defaultFollowRedirect() { @@ -89,8 +89,8 @@ public static boolean defaultStrict302Handling() { return Boolean.getBoolean(ASYNC_CLIENT + "strict302Handling"); } - public static boolean defaultAllowPoolingConnection() { - return getBoolean(ASYNC_CLIENT + "allowPoolingConnection", true); + public static boolean defaultAllowPoolingConnections() { + return getBoolean(ASYNC_CLIENT + "allowPoolingConnections", true); } public static boolean defaultUseRelativeURIsWithSSLProxies() { @@ -101,8 +101,8 @@ public static int defaultMaxRequestRetry() { return Integer.getInteger(ASYNC_CLIENT + "maxRequestRetry", 5); } - public static boolean defaultAllowSslConnectionPool() { - return getBoolean(ASYNC_CLIENT + "allowSslConnectionPool", true); + public static boolean defaultAllowPoolingSslConnections() { + return getBoolean(ASYNC_CLIENT + "allowPoolingSslConnections", true); } public static boolean defaultDisableUrlEncodingForBoundedRequests() { diff --git a/src/main/java/com/ning/http/client/Request.java b/src/main/java/com/ning/http/client/Request.java index 54b04aa3d7..cd37e49ec2 100644 --- a/src/main/java/com/ning/http/client/Request.java +++ b/src/main/java/com/ning/http/client/Request.java @@ -166,7 +166,7 @@ public interface Request { * Overrides the config default value * @return the request timeout */ - int getRequestTimeoutInMs(); + int getRequestTimeout(); /** * Return the HTTP Range header value, or diff --git a/src/main/java/com/ning/http/client/RequestBuilderBase.java b/src/main/java/com/ning/http/client/RequestBuilderBase.java index bc3e8b1163..f4ab066579 100644 --- a/src/main/java/com/ning/http/client/RequestBuilderBase.java +++ b/src/main/java/com/ning/http/client/RequestBuilderBase.java @@ -63,7 +63,7 @@ private static final class RequestImpl implements Request { private Realm realm; private File file; private Boolean followRedirects; - private int requestTimeoutInMs; + private int requestTimeout; private long rangeOffset; public String charset; private ConnectionPoolKeyStrategy connectionPoolKeyStrategy = DefaultConnectionPoolStrategy.INSTANCE; @@ -92,7 +92,7 @@ public RequestImpl(Request prototype) { this.realm = prototype.getRealm(); this.file = prototype.getFile(); this.followRedirects = prototype.getFollowRedirect(); - this.requestTimeoutInMs = prototype.getRequestTimeoutInMs(); + this.requestTimeout = prototype.getRequestTimeout(); this.rangeOffset = prototype.getRangeOffset(); this.charset = prototype.getBodyEncoding(); this.connectionPoolKeyStrategy = prototype.getConnectionPoolKeyStrategy(); @@ -171,8 +171,8 @@ public Boolean getFollowRedirect() { return followRedirects; } - public int getRequestTimeoutInMs() { - return requestTimeoutInMs; + public int getRequestTimeout() { + return requestTimeout; } public long getRangeOffset() { @@ -489,8 +489,8 @@ public T setFollowRedirects(boolean followRedirects) { return derived.cast(this); } - public T setRequestTimeoutInMs(int requestTimeoutInMs) { - request.requestTimeoutInMs = requestTimeoutInMs; + public T setRequestTimeout(int requestTimeout) { + request.requestTimeout = requestTimeout; return derived.cast(this); } diff --git a/src/main/java/com/ning/http/client/SimpleAsyncHttpClient.java b/src/main/java/com/ning/http/client/SimpleAsyncHttpClient.java index af8d527b8d..19986c6974 100644 --- a/src/main/java/com/ning/http/client/SimpleAsyncHttpClient.java +++ b/src/main/java/com/ning/http/client/SimpleAsyncHttpClient.java @@ -40,9 +40,9 @@ * {@link AsyncHandler} are required. As simple as: *

      * SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder()
    - * .setIdleConnectionInPoolTimeoutInMs(100)
    + * .setIdleConnectionInPoolTimeout(100)
      * .setMaximumConnectionsTotal(50)
    - * .setRequestTimeoutInMs(5 * 60 * 1000)
    + * .setRequestTimeout(5 * 60 * 1000)
      * .setUrl(getTargetUrl())
      * .setHeader("Content-Type", "text/html").build();
      * 

    @@ -490,32 +490,32 @@ public Builder setFollowRedirects(boolean followRedirects) { } public Builder setMaximumConnectionsTotal(int defaultMaxTotalConnections) { - configBuilder.setMaximumConnectionsTotal(defaultMaxTotalConnections); + configBuilder.setMaxConnections(defaultMaxTotalConnections); return this; } public Builder setMaximumConnectionsPerHost(int defaultMaxConnectionPerHost) { - configBuilder.setMaximumConnectionsPerHost(defaultMaxConnectionPerHost); + configBuilder.setMaxConnectionsPerHost(defaultMaxConnectionPerHost); return this; } - public Builder setConnectionTimeoutInMs(int connectionTimeuot) { - configBuilder.setConnectionTimeoutInMs(connectionTimeuot); + public Builder setConnectionTimeout(int connectionTimeuot) { + configBuilder.setConnectionTimeout(connectionTimeuot); return this; } - public Builder setIdleConnectionInPoolTimeoutInMs(int defaultIdleConnectionInPoolTimeoutInMs) { - configBuilder.setIdleConnectionInPoolTimeoutInMs(defaultIdleConnectionInPoolTimeoutInMs); + public Builder setPooledConnectionIdleTimeout(int pooledConnectionIdleTimeout) { + configBuilder.setPooledConnectionIdleTimeout(pooledConnectionIdleTimeout); return this; } - public Builder setRequestTimeoutInMs(int defaultRequestTimeoutInMs) { - configBuilder.setRequestTimeoutInMs(defaultRequestTimeoutInMs); + public Builder setRequestTimeout(int defaultRequestTimeout) { + configBuilder.setRequestTimeout(defaultRequestTimeout); return this; } public Builder setMaximumNumberOfRedirects(int maxDefaultRedirects) { - configBuilder.setMaximumNumberOfRedirects(maxDefaultRedirects); + configBuilder.setMaxRedirects(maxDefaultRedirects); return this; } @@ -529,8 +529,8 @@ public Builder setUserAgent(String userAgent) { return this; } - public Builder setAllowPoolingConnection(boolean allowPoolingConnection) { - configBuilder.setAllowPoolingConnection(allowPoolingConnection); + public Builder setAllowPoolingConnections(boolean allowPoolingConnections) { + configBuilder.setAllowPoolingConnections(allowPoolingConnections); return this; } 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 f2924653d5..af0d4091f4 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 @@ -191,8 +191,8 @@ public ListenableFuture execute(Request request, AsyncHandler handler) request = ResumableAsyncHandler.class.cast(handler).adjustRequestRange(request); } - if (config.getMaxTotalConnections() > -1 && (maxConnections.get() + 1) > config.getMaxTotalConnections()) { - throw new IOException(String.format("Too many connections %s", config.getMaxTotalConnections())); + if (config.getMaxConnections() > -1 && (maxConnections.get() + 1) > config.getMaxConnections()) { + throw new IOException(String.format("Too many connections %s", config.getMaxConnections())); } if (idleConnectionTimeoutThread != null) { @@ -201,9 +201,9 @@ public ListenableFuture execute(Request request, AsyncHandler handler) } int requestTimeout = AsyncHttpProviderUtils.requestTimeout(config, request); - if (config.getIdleConnectionTimeoutInMs() > 0 && requestTimeout != -1 && requestTimeout < config.getIdleConnectionTimeoutInMs()) { + if (config.getReadTimeout() > 0 && requestTimeout != -1 && requestTimeout < config.getReadTimeout()) { idleConnectionTimeoutThread = new IdleConnectionTimeoutThread(); - idleConnectionTimeoutThread.setConnectionTimeout(config.getIdleConnectionTimeoutInMs()); + idleConnectionTimeoutThread.setConnectionTimeout(config.getReadTimeout()); idleConnectionTimeoutThread.addConnectionManager(connectionManager); idleConnectionTimeoutThread.start(); } @@ -605,7 +605,7 @@ public T call() { try { fc = handleIoException(fc); } catch (FilterException e) { - if (config.getMaxTotalConnections() != -1) { + if (config.getMaxConnections() != -1) { maxConnections.decrementAndGet(); } future.done(); @@ -631,7 +631,7 @@ public T call() { } } finally { if (terminate) { - if (config.getMaxTotalConnections() != -1) { + if (config.getMaxConnections() != -1) { maxConnections.decrementAndGet(); } future.done(); @@ -653,8 +653,8 @@ private Throwable filterException(Throwable t) { t = new ConnectException(t.getMessage()); } else if (t instanceof NoHttpResponseException) { - int responseTimeoutInMs = AsyncHttpProviderUtils.requestTimeout(config, request); - t = new TimeoutException(String.format("No response received after %s", responseTimeoutInMs)); + int responseTimeout = AsyncHttpProviderUtils.requestTimeout(config, request); + t = new TimeoutException(String.format("No response received after %s", responseTimeout)); } else if (t instanceof SSLHandshakeException) { Throwable t2 = new ConnectException(); 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 7d4da268cd..f567dcf4f9 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 @@ -345,7 +345,7 @@ protected void initializeTransport(final AsyncHttpClientConfig clientConfig) { final FilterChainBuilder fcb = FilterChainBuilder.stateless(); fcb.add(new TransportFilter()); - final int timeout = clientConfig.getRequestTimeoutInMs(); + final int timeout = clientConfig.getRequestTimeout(); if (timeout > 0) { int delay = 500; if (timeout < delay) { @@ -361,9 +361,9 @@ public long getTimeout(FilterChainContext ctx) { HttpTransactionContext.get(ctx.getConnection()); if (context != null) { if (context.isWSRequest) { - return clientConfig.getWebSocketIdleTimeoutInMs(); + return clientConfig.getWebSocketReadTimeout(); } - final long timeout = context.request.getRequestTimeoutInMs(); + final long timeout = context.request.getRequestTimeout(); if (timeout > 0) { return timeout; } @@ -460,14 +460,14 @@ public void onTimeout(Connection connection) { void touchConnection(final Connection c, final Request request) { - final long perRequestTimeout = request.getRequestTimeoutInMs(); + final long perRequestTimeout = request.getRequestTimeout(); if (perRequestTimeout > 0) { final long newTimeout = System.currentTimeMillis() + perRequestTimeout; if (resolver != null) { resolver.setTimeoutMillis(c, newTimeout); } } else { - final long timeout = clientConfig.getRequestTimeoutInMs(); + final long timeout = clientConfig.getRequestTimeout(); if (timeout > 0) { if (resolver != null) { resolver.setTimeoutMillis(c, System.currentTimeMillis() + timeout); @@ -1407,7 +1407,7 @@ protected void onHttpHeadersParsed(HttpHeader httpHeader, context.protocolHandler, ws); ((WebSocketUpgradeHandler) context.handler).onSuccess(context.webSocket); - final int wsTimeout = context.provider.clientConfig.getWebSocketIdleTimeoutInMs(); + final int wsTimeout = context.provider.clientConfig.getWebSocketReadTimeout(); IdleTimeoutFilter.setCustomTimeout(ctx.getConnection(), ((wsTimeout <= 0) ? IdleTimeoutFilter.FOREVER @@ -2354,7 +2354,7 @@ static class ConnectionManager { ConnectionPool connectionPool; this.provider = provider; final AsyncHttpClientConfig config = provider.clientConfig; - if (config.isAllowPoolingConnection()) { + if (config.isAllowPoolingConnections()) { ConnectionPool pool = providerConfig != null ? providerConfig.getConnectionPool() : null; if (pool != null) { connectionPool = pool; @@ -2366,7 +2366,7 @@ static class ConnectionManager { } pool = connectionPool; connectionHandler = TCPNIOConnectorHandler.builder(transport).build(); - final int maxConns = provider.clientConfig.getMaxTotalConnections(); + final int maxConns = provider.clientConfig.getMaxConnections(); connectionMonitor = new ConnectionMonitor(maxConns); @@ -2454,7 +2454,7 @@ private Connection obtainConnection0(final Request request, 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(); + int cTimeout = provider.clientConfig.getConnectionTimeout(); FutureImpl future = Futures.createSafeFuture(); CompletionHandler ch = Futures.toCompletionHandler(future, createConnectionCompletionHandler(request, requestFuture, null)); @@ -2967,7 +2967,7 @@ public static void main(String[] args) { e.printStackTrace(); } AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder() - .setConnectionTimeoutInMs(5000) + .setConnectionTimeout(5000) .setSSLContext(sslContext).build(); AsyncHttpClient client = new AsyncHttpClient(new GrizzlyAsyncHttpProvider(config), config); try { diff --git a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyConnectionPool.java b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyConnectionPool.java index 63729a6cfb..8b83c0f0d5 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyConnectionPool.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyConnectionPool.java @@ -59,7 +59,7 @@ public class GrizzlyConnectionPool implements ConnectionPool { private final int maxConnections; private final boolean unlimitedConnections; private final long timeout; - private final long maxConnectionLifeTimeInMs; + private final long maxConnectionLifeTime; private final DelayedExecutor delayedExecutor; private final boolean ownsDelayedExecutor; @@ -85,13 +85,13 @@ public void onClosed(Connection connection, CloseType closeType) @SuppressWarnings("UnusedDeclaration") public GrizzlyConnectionPool(final boolean cacheSSLConnections, final int timeout, - final int maxConnectionLifeTimeInMs, + final int maxConnectionLifeTime, final int maxConnectionsPerHost, final int maxConnections, final DelayedExecutor delayedExecutor) { this.cacheSSLConnections = cacheSSLConnections; this.timeout = timeout; - this.maxConnectionLifeTimeInMs = maxConnectionLifeTimeInMs; + this.maxConnectionLifeTime = maxConnectionLifeTime; this.maxConnectionsPerHost = maxConnectionsPerHost; this.maxConnections = maxConnections; unlimitedConnections = (maxConnections == -1); @@ -111,11 +111,11 @@ public GrizzlyConnectionPool(final boolean cacheSSLConnections, public GrizzlyConnectionPool(final AsyncHttpClientConfig config) { - cacheSSLConnections = config.isSslConnectionPoolEnabled(); - timeout = config.getIdleConnectionInPoolTimeoutInMs(); - maxConnectionLifeTimeInMs = config.getMaxConnectionLifeTimeInMs(); - maxConnectionsPerHost = config.getMaxConnectionPerHost(); - maxConnections = config.getMaxTotalConnections(); + cacheSSLConnections = config.isAllowPoolingSslConnections(); + timeout = config.getPooledConnectionIdleTimeout(); + maxConnectionLifeTime = config.getConnectionTTL(); + maxConnectionsPerHost = config.getMaxConnectionsPerHost(); + maxConnections = config.getMaxConnections(); unlimitedConnections = (maxConnections == -1); delayedExecutor = new DelayedExecutor(Executors.newSingleThreadExecutor(), this); delayedExecutor.start(); @@ -142,7 +142,7 @@ public boolean offer(String uri, Connection connection) { new Object[]{uri, connection}); } DelayedExecutor.IdleConnectionQueue newPool = - delayedExecutor.createIdleConnectionQueue(timeout, maxConnectionLifeTimeInMs); + delayedExecutor.createIdleConnectionQueue(timeout, maxConnectionLifeTime); conQueue = connectionsPool.putIfAbsent(uri, newPool); if (conQueue == null) { conQueue = newPool; @@ -328,8 +328,8 @@ private ExecutorService getThreadPool() { return threadPool; } - private IdleConnectionQueue createIdleConnectionQueue(final long timeout, final long maxConnectionLifeTimeInMs) { - final IdleConnectionQueue queue = new IdleConnectionQueue(timeout, maxConnectionLifeTimeInMs); + private IdleConnectionQueue createIdleConnectionQueue(final long timeout, final long maxConnectionLifeTime) { + final IdleConnectionQueue queue = new IdleConnectionQueue(timeout, maxConnectionLifeTime); queues.add(queue); return queue; } @@ -407,14 +407,14 @@ final class IdleConnectionQueue { final TimeoutResolver resolver = new TimeoutResolver(); final long timeout; final AtomicInteger count = new AtomicInteger(0); - final long maxConnectionLifeTimeInMs; + final long maxConnectionLifeTime; // ---------------------------------------------------- Constructors - public IdleConnectionQueue(final long timeout, final long maxConnectionLifeTimeInMs) { + public IdleConnectionQueue(final long timeout, final long maxConnectionLifeTime) { this.timeout = timeout; - this.maxConnectionLifeTimeInMs = maxConnectionLifeTimeInMs; + this.maxConnectionLifeTime = maxConnectionLifeTime; } @@ -424,15 +424,15 @@ public IdleConnectionQueue(final long timeout, final long maxConnectionLifeTimeI void offer(final Connection c) { long timeoutMs = UNSET_TIMEOUT; long currentTime = millisTime(); - if (maxConnectionLifeTimeInMs < 0 && timeout >= 0) { + if (maxConnectionLifeTime < 0 && timeout >= 0) { timeoutMs = currentTime + timeout; - } else if (maxConnectionLifeTimeInMs >= 0) { + } else if (maxConnectionLifeTime >= 0) { long t = resolver.getTimeoutMs(c); if (t == UNSET_TIMEOUT) { if (timeout >= 0) { - timeoutMs = currentTime + Math.min(maxConnectionLifeTimeInMs, timeout); + timeoutMs = currentTime + Math.min(maxConnectionLifeTime, timeout); } else { - timeoutMs = currentTime + maxConnectionLifeTimeInMs; + timeoutMs = currentTime + maxConnectionLifeTime; } } else { if (timeout >= 0) { 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 46ba6be474..055a63a9aa 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 @@ -128,8 +128,8 @@ public ListenableFuture execute(Request request, AsyncHandler handler, throw new IOException("Closed"); } - if (config.getMaxTotalConnections() > -1 && (maxConnections.get() + 1) > config.getMaxTotalConnections()) { - throw new IOException(String.format("Too many connections %s", config.getMaxTotalConnections())); + if (config.getMaxConnections() > -1 && (maxConnections.get() + 1) > config.getMaxConnections()) { + throw new IOException(String.format("Too many connections %s", config.getMaxConnections())); } ProxyServer proxyServer = ProxyUtils.getProxyServer(config, request); @@ -373,7 +373,7 @@ public T call() throws Exception { try { fc = handleIoException(fc); } catch (FilterException e) { - if (config.getMaxTotalConnections() != -1) { + if (config.getMaxConnections() != -1) { maxConnections.decrementAndGet(); } future.done(); @@ -393,7 +393,7 @@ public T call() throws Exception { } } finally { if (terminate) { - if (config.getMaxTotalConnections() != -1) { + if (config.getMaxConnections() != -1) { maxConnections.decrementAndGet(); } urlConnection.disconnect(); @@ -421,8 +421,8 @@ private Throwable filterException(Throwable t) { t = new ConnectException(t.getMessage()); } else if (t instanceof SocketTimeoutException) { - int responseTimeoutInMs = AsyncHttpProviderUtils.requestTimeout(config, request); - t = new TimeoutException(String.format("No response received after %s", responseTimeoutInMs)); + int responseTimeout = AsyncHttpProviderUtils.requestTimeout(config, request); + t = new TimeoutException(String.format("No response received after %s", responseTimeout)); } else if (t instanceof SSLHandshakeException) { Throwable t2 = new ConnectException(); @@ -437,7 +437,7 @@ private void configure(UriComponents uri, HttpURLConnection urlConnection, Reque int requestTimeout = AsyncHttpProviderUtils.requestTimeout(config, request); - urlConnection.setConnectTimeout(config.getConnectionTimeoutInMs()); + urlConnection.setConnectTimeout(config.getConnectionTimeout()); if (requestTimeout != -1) urlConnection.setReadTimeout(requestTimeout); 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 b331465cb0..b8468ad137 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 @@ -222,7 +222,7 @@ public NettyAsyncHttpProvider(AsyncHttpClientConfig config) { // This is dangerous as we can't catch a wrong typed ConnectionsPool ChannelPool channelPool = providerConfig.getChannelPool(); - if (channelPool == null && config.isAllowPoolingConnection()) { + if (channelPool == null && config.isAllowPoolingConnections()) { channelPool = new DefaultChannelPool(config, nettyTimer); } else if (channelPool == null) { channelPool = new NoopChannelPool(); @@ -503,19 +503,17 @@ public void operationComplete(ChannelFuture cf) { try { future.touch(); - int requestTimeoutInMs = AsyncHttpProviderUtils.requestTimeout(config, future.getRequest()); + int requestTimeout = AsyncHttpProviderUtils.requestTimeout(config, future.getRequest()); TimeoutsHolder timeoutsHolder = new TimeoutsHolder(); - if (requestTimeoutInMs != -1) { - Timeout requestTimeout = newTimeoutInMs(new RequestTimeoutTimerTask(future, this, timeoutsHolder, requestTimeoutInMs), requestTimeoutInMs); - timeoutsHolder.requestTimeout = requestTimeout; + if (requestTimeout != -1) { + timeoutsHolder.requestTimeout = newTimeout(new RequestTimeoutTimerTask(future, this, timeoutsHolder, requestTimeout), requestTimeout); } - int idleConnectionTimeoutInMs = config.getIdleConnectionTimeoutInMs(); - if (idleConnectionTimeoutInMs != -1 && idleConnectionTimeoutInMs <= requestTimeoutInMs) { - // no need for a idleConnectionTimeout that's less than the requestTimeoutInMs - Timeout idleConnectionTimeout = newTimeoutInMs(new IdleConnectionTimeoutTimerTask(future, this, timeoutsHolder, - requestTimeoutInMs, idleConnectionTimeoutInMs), idleConnectionTimeoutInMs); - timeoutsHolder.idleConnectionTimeout = idleConnectionTimeout; + int idleConnectionTimeout = config.getReadTimeout(); + if (idleConnectionTimeout != -1 && idleConnectionTimeout <= requestTimeout) { + // no need for a idleConnectionTimeout that's less than the requestTimeout + timeoutsHolder.idleConnectionTimeout = newTimeout(new IdleConnectionTimeoutTimerTask(future, this, timeoutsHolder, + requestTimeout, idleConnectionTimeout), idleConnectionTimeout); } future.setTimeoutsHolder(timeoutsHolder); @@ -912,13 +910,13 @@ private ListenableFuture doConnect(final Request request, final AsyncHand // only compute when maxConnectionPerHost is enabled // FIXME clean up - if (config.getMaxConnectionPerHost() > 0) + if (config.getMaxConnectionsPerHost() > 0) poolKey = getPoolKey(connectListenerFuture); if (channelManager.preemptChannel(poolKey)) { channelPreempted = true; } else { - IOException ex = new IOException(String.format("Too many connections %s", config.getMaxTotalConnections())); + IOException ex = new IOException(String.format("Too many connections %s", config.getMaxConnections())); try { asyncHandler.onThrowable(ex); } catch (Exception e) { @@ -934,7 +932,7 @@ private ListenableFuture doConnect(final Request request, final AsyncHand ChannelFuture channelFuture; ClientBootstrap bootstrap = (request.getURI().getScheme().startsWith(WEBSOCKET) && !useProxy) ? (useSSl ? secureWebSocketBootstrap : webSocketBootstrap) : (useSSl ? secureBootstrap : plainBootstrap); - bootstrap.setOption("connectTimeoutMillis", config.getConnectionTimeoutInMs()); + bootstrap.setOption("connectTimeoutMillis", config.getConnectionTimeout()); try { InetSocketAddress remoteAddress; @@ -2293,8 +2291,8 @@ public boolean isClose() { return isClose.get(); } - public Timeout newTimeoutInMs(TimerTask task, long delayInMs) { - return nettyTimer.newTimeout(task, delayInMs, TimeUnit.MILLISECONDS); + public Timeout newTimeout(TimerTask task, long delay) { + return nettyTimer.newTimeout(task, delay, TimeUnit.MILLISECONDS); } private static boolean isWebSocket(String scheme) { diff --git a/src/main/java/com/ning/http/client/providers/netty/pool/ChannelManager.java b/src/main/java/com/ning/http/client/providers/netty/pool/ChannelManager.java index 2c881c77b0..a53dad6b82 100644 --- a/src/main/java/com/ning/http/client/providers/netty/pool/ChannelManager.java +++ b/src/main/java/com/ning/http/client/providers/netty/pool/ChannelManager.java @@ -42,7 +42,7 @@ public class ChannelManager { public ChannelManager(AsyncHttpClientConfig config, ChannelPool channelPool) { this.channelPool = channelPool; - maxTotalConnectionsEnabled = config.getMaxTotalConnections() > 0; + maxTotalConnectionsEnabled = config.getMaxConnections() > 0; if (maxTotalConnectionsEnabled) { openChannels = new CleanupChannelGroup("asyncHttpClient") { @@ -63,14 +63,14 @@ public boolean remove(Object o) { return removed; } }; - freeChannels = new Semaphore(config.getMaxTotalConnections()); + freeChannels = new Semaphore(config.getMaxConnections()); } else { openChannels = new CleanupChannelGroup("asyncHttpClient"); freeChannels = null; } - maxConnectionsPerHost = config.getMaxConnectionPerHost(); - maxConnectionsPerHostEnabled = config.getMaxConnectionPerHost() > 0; + maxConnectionsPerHost = config.getMaxConnectionsPerHost(); + maxConnectionsPerHostEnabled = config.getMaxConnectionsPerHost() > 0; if (maxConnectionsPerHostEnabled) { freeChannelsPerHost = new ConcurrentHashMap(); diff --git a/src/main/java/com/ning/http/client/providers/netty/pool/DefaultChannelPool.java b/src/main/java/com/ning/http/client/providers/netty/pool/DefaultChannelPool.java index a1b45ff6cf..e09e478ba0 100644 --- a/src/main/java/com/ning/http/client/providers/netty/pool/DefaultChannelPool.java +++ b/src/main/java/com/ning/http/client/providers/netty/pool/DefaultChannelPool.java @@ -53,10 +53,10 @@ public final class DefaultChannelPool implements ChannelPool { private final long cleanerPeriod; public DefaultChannelPool(AsyncHttpClientConfig config, Timer hashedWheelTimer) { - this(config.getMaxConnectionPerHost(),// - config.getIdleConnectionInPoolTimeoutInMs(),// - config.getMaxConnectionLifeTimeInMs(),// - config.isSslConnectionPoolEnabled(),// + this(config.getMaxConnectionsPerHost(),// + config.getPooledConnectionIdleTimeout(),// + config.getConnectionTTL(),// + config.isAllowPoolingSslConnections(),// hashedWheelTimer); } diff --git a/src/main/java/com/ning/http/client/providers/netty/timeout/IdleConnectionTimeoutTimerTask.java b/src/main/java/com/ning/http/client/providers/netty/timeout/IdleConnectionTimeoutTimerTask.java index c4fddd5e0b..75c8fb0267 100644 --- a/src/main/java/com/ning/http/client/providers/netty/timeout/IdleConnectionTimeoutTimerTask.java +++ b/src/main/java/com/ning/http/client/providers/netty/timeout/IdleConnectionTimeoutTimerTask.java @@ -51,7 +51,7 @@ public void run(Timeout timeout) throws Exception { } else if (currentIdleConnectionTimeoutInstant < requestTimeoutInstant) { // reschedule - timeoutsHolder.idleConnectionTimeout = provider.newTimeoutInMs(this, durationBeforeCurrentIdleConnectionTimeout); + timeoutsHolder.idleConnectionTimeout = provider.newTimeout(this, durationBeforeCurrentIdleConnectionTimeout); } else { // otherwise, no need to reschedule: requestTimeout will happen sooner diff --git a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java index 3d33f5f1d8..f015963bdb 100644 --- a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java +++ b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java @@ -216,11 +216,11 @@ public static String parseCharset(String contentType) { } public static String keepAliveHeaderValue(AsyncHttpClientConfig config) { - return config.isAllowPoolingConnection() ? "keep-alive" : "close"; + return config.isAllowPoolingConnections() ? "keep-alive" : "close"; } public static int requestTimeout(AsyncHttpClientConfig config, Request request) { - return request.getRequestTimeoutInMs() != 0 ? request.getRequestTimeoutInMs() : config.getRequestTimeoutInMs(); + return request.getRequestTimeout() != 0 ? request.getRequestTimeout() : config.getRequestTimeout(); } public static boolean followRedirect(AsyncHttpClientConfig config, Request request) { 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 f7d09995de..0dabb230cd 100755 --- a/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java +++ b/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java @@ -358,7 +358,7 @@ public Response onCompleted(Response response) throws Exception { @Test(groups = { "standalone", "default_provider", "async" }, enabled = false) public void asyncStatusHEADContentLenghtTest() throws Throwable { - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeoutInMs(120 * 1000).build()); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeout(120 * 1000).build()); try { final CountDownLatch l = new CountDownLatch(1); Request request = new RequestBuilder("HEAD").setUrl(getTargetUrl()).build(); @@ -1275,7 +1275,7 @@ public void onThrowable(Throwable t) { @Test(groups = { "standalone", "default_provider", "async" }) public void asyncDoGetDelayHandlerTest() throws Throwable { - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeoutInMs(5 * 1000).build()); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeout(5 * 1000).build()); try { FluentCaseInsensitiveStringsMap h = new FluentCaseInsensitiveStringsMap(); h.add("LockThread", "true"); @@ -1389,7 +1389,7 @@ public Response onCompleted(Response response) throws Exception { @Test(groups = { "online", "default_provider", "async" }) public void asyncDoGetMaxRedirectTest() throws Throwable { - AsyncHttpClient client = getAsyncHttpClient(new Builder().setMaximumNumberOfRedirects(0).setFollowRedirect(true).build()); + AsyncHttpClient client = getAsyncHttpClient(new Builder().setMaxRedirects(0).setFollowRedirect(true).build()); try { // Use a l in case the assert fail final CountDownLatch l = new CountDownLatch(1); @@ -1537,7 +1537,7 @@ public void testAsyncHttpProviderConfig() throws Exception { @Test(groups = { "standalone", "default_provider" }) public void idleRequestTimeoutTest() throws Exception { - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setIdleConnectionInPoolTimeoutInMs(5000).setRequestTimeoutInMs(10000).build()); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setPooledConnectionIdleTimeout(5000).setRequestTimeout(10000).build()); try { FluentCaseInsensitiveStringsMap h = new FluentCaseInsensitiveStringsMap(); h.add("Content-Type", "application/x-www-form-urlencoded"); 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 6ef33a3ef4..d6a7174a2d 100644 --- a/src/test/java/com/ning/http/client/async/AuthTimeoutTest.java +++ b/src/test/java/com/ning/http/client/async/AuthTimeoutTest.java @@ -125,7 +125,7 @@ public void handle(String s, Request r, HttpServletRequest request, HttpServletR @Test(groups = { "standalone", "default_provider" }, enabled = false) public void basicAuthTimeoutTest() throws Exception { setUpServer(Constraint.__BASIC_AUTH); - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setIdleConnectionInPoolTimeoutInMs(2000).setConnectionTimeoutInMs(20000).setRequestTimeoutInMs(2000).build()); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setPooledConnectionIdleTimeout(2000).setConnectionTimeout(20000).setRequestTimeout(2000).build()); try { Future f = execute(client, false); @@ -143,7 +143,7 @@ public void basicAuthTimeoutTest() throws Exception { @Test(groups = { "standalone", "default_provider" }, enabled = false) public void basicPreemptiveAuthTimeoutTest() throws Exception { setUpServer(Constraint.__BASIC_AUTH); - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setIdleConnectionInPoolTimeoutInMs(2000).setConnectionTimeoutInMs(20000).setRequestTimeoutInMs(2000).build()); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setPooledConnectionIdleTimeout(2000).setConnectionTimeout(20000).setRequestTimeout(2000).build()); try { Future f = execute(client, true); @@ -161,7 +161,7 @@ public void basicPreemptiveAuthTimeoutTest() throws Exception { @Test(groups = { "standalone", "default_provider" }, enabled = false) public void digestAuthTimeoutTest() throws Exception { setUpServer(Constraint.__DIGEST_AUTH); - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setIdleConnectionInPoolTimeoutInMs(2000).setConnectionTimeoutInMs(20000).setRequestTimeoutInMs(2000).build()); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setPooledConnectionIdleTimeout(2000).setConnectionTimeout(20000).setRequestTimeout(2000).build()); try { Future f = execute(client, false); @@ -179,7 +179,7 @@ public void digestAuthTimeoutTest() throws Exception { @Test(groups = { "standalone", "default_provider" }, enabled = false) public void digestPreemptiveAuthTimeoutTest() throws Exception { setUpServer(Constraint.__DIGEST_AUTH); - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setIdleConnectionInPoolTimeoutInMs(2000).setConnectionTimeoutInMs(20000).setRequestTimeoutInMs(2000).build()); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setPooledConnectionIdleTimeout(2000).setConnectionTimeout(20000).setRequestTimeout(2000).build()); try { Future f = execute(client, true); @@ -195,7 +195,7 @@ public void digestPreemptiveAuthTimeoutTest() throws Exception { @Test(groups = { "standalone", "default_provider" }, enabled = false) public void basicFutureAuthTimeoutTest() throws Exception { setUpServer(Constraint.__BASIC_AUTH); - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setIdleConnectionInPoolTimeoutInMs(2000).setConnectionTimeoutInMs(20000).setRequestTimeoutInMs(2000).build()); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setPooledConnectionIdleTimeout(2000).setConnectionTimeout(20000).setRequestTimeout(2000).build()); try { Future f = execute(client, false); @@ -211,7 +211,7 @@ public void basicFutureAuthTimeoutTest() throws Exception { @Test(groups = { "standalone", "default_provider" }, enabled = false) public void basicFuturePreemptiveAuthTimeoutTest() throws Exception { setUpServer(Constraint.__BASIC_AUTH); - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setIdleConnectionInPoolTimeoutInMs(2000).setConnectionTimeoutInMs(20000).setRequestTimeoutInMs(2000).build()); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setPooledConnectionIdleTimeout(2000).setConnectionTimeout(20000).setRequestTimeout(2000).build()); try { Future f = execute(client, true); @@ -227,7 +227,7 @@ public void basicFuturePreemptiveAuthTimeoutTest() throws Exception { @Test(groups = { "standalone", "default_provider" }, enabled = false) public void digestFutureAuthTimeoutTest() throws Exception { setUpServer(Constraint.__DIGEST_AUTH); - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setIdleConnectionInPoolTimeoutInMs(2000).setConnectionTimeoutInMs(20000).setRequestTimeoutInMs(2000).build()); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setPooledConnectionIdleTimeout(2000).setConnectionTimeout(20000).setRequestTimeout(2000).build()); try { Future f = execute(client, false); @@ -243,7 +243,7 @@ public void digestFutureAuthTimeoutTest() throws Exception { @Test(groups = { "standalone", "default_provider" }, enabled = false) public void digestFuturePreemptiveAuthTimeoutTest() throws Exception { setUpServer(Constraint.__DIGEST_AUTH); - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setIdleConnectionInPoolTimeoutInMs(2000).setConnectionTimeoutInMs(20000).setRequestTimeoutInMs(2000).build()); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setPooledConnectionIdleTimeout(2000).setConnectionTimeout(20000).setRequestTimeout(2000).build()); try { Future f = execute(client, true); 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 c2016fc136..792a1e6c9e 100644 --- a/src/test/java/com/ning/http/client/async/BasicAuthTest.java +++ b/src/test/java/com/ning/http/client/async/BasicAuthTest.java @@ -297,7 +297,7 @@ public void basicAuthTest() throws IOException, ExecutionException, TimeoutExcep @Test(groups = { "standalone", "default_provider" }) public void redirectAndBasicAuthTest() throws Exception, ExecutionException, TimeoutException, InterruptedException { - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setFollowRedirect(true).setMaximumNumberOfRedirects(10).build()); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setFollowRedirect(true).setMaxRedirects(10).build()); try { setUpSecondServer(); AsyncHttpClient.BoundRequestBuilder r = client.prepareGet(getTargetUrl2()) @@ -478,7 +478,7 @@ public void basicAuthAsyncConfigTest() throws Throwable { @Test(groups = { "standalone", "default_provider" }) public void basicAuthFileNoKeepAliveTest() throws Throwable { - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setAllowPoolingConnection(false).build()); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setAllowPoolingConnections(false).build()); try { ClassLoader cl = getClass().getClassLoader(); // override system properties 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 a1afa3b81f..8a55b4a1fb 100644 --- a/src/test/java/com/ning/http/client/async/BasicHttpsTest.java +++ b/src/test/java/com/ning/http/client/async/BasicHttpsTest.java @@ -252,7 +252,7 @@ public void multipleSSLRequestsTest() throws Throwable { @Test(groups = { "standalone", "default_provider" }) public void multipleSSLWithoutCacheTest() throws Throwable { - final AsyncHttpClient client = getAsyncHttpClient(new Builder().setSSLContext(createSSLContext(new AtomicBoolean(true))).setAllowSslConnectionPool(false).build()); + final AsyncHttpClient client = getAsyncHttpClient(new Builder().setSSLContext(createSSLContext(new AtomicBoolean(true))).setAllowPoolingSslConnections(false).build()); try { String body = "hello there"; client.preparePost(getTargetUrl()).setBody(body).setHeader("Content-Type", "text/html").execute(); @@ -309,7 +309,7 @@ public boolean verify(String arg0, SSLSession arg1) { } }; - AsyncHttpClient client = getAsyncHttpClient(new Builder().setHostnameVerifier(hostnameVerifier).setRequestTimeoutInMs(20000).build()); + AsyncHttpClient client = getAsyncHttpClient(new Builder().setHostnameVerifier(hostnameVerifier).setRequestTimeout(20000).build()); try { try { 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 c86605f704..07457fc589 100644 --- a/src/test/java/com/ning/http/client/async/BodyChunkTest.java +++ b/src/test/java/com/ning/http/client/async/BodyChunkTest.java @@ -34,9 +34,9 @@ public abstract class BodyChunkTest extends AbstractBasicTest { @Test(groups = { "standalone", "default_provider" }) public void negativeContentTypeTest() throws Throwable { AsyncHttpClientConfig.Builder confbuilder = new AsyncHttpClientConfig.Builder(); - confbuilder = confbuilder.setConnectionTimeoutInMs(100); - confbuilder = confbuilder.setMaximumConnectionsTotal(50); - confbuilder = confbuilder.setRequestTimeoutInMs(5 * 60 * 1000); // 5 minutes + confbuilder = confbuilder.setConnectionTimeout(100); + confbuilder = confbuilder.setMaxConnections(50); + confbuilder = confbuilder.setRequestTimeout(5 * 60 * 1000); // 5 minutes // Create client AsyncHttpClient client = getAsyncHttpClient(confbuilder.build()); 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 7960b0bfb2..fd77407753 100644 --- a/src/test/java/com/ning/http/client/async/BodyDeferringAsyncHandlerTest.java +++ b/src/test/java/com/ning/http/client/async/BodyDeferringAsyncHandlerTest.java @@ -118,7 +118,7 @@ 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).setRequestTimeout(10000).build(); } @Test(groups = { "standalone", "default_provider" }) 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 391fc0aefb..941feddf29 100644 --- a/src/test/java/com/ning/http/client/async/ChunkingTest.java +++ b/src/test/java/com/ning/http/client/async/ChunkingTest.java @@ -75,11 +75,11 @@ public void testCustomChunking() throws Throwable { private void doTest(boolean customChunkedInputStream) throws Exception { AsyncHttpClientConfig.Builder bc = new AsyncHttpClientConfig.Builder()// - .setAllowPoolingConnection(true)// - .setMaximumConnectionsPerHost(1)// - .setMaximumConnectionsTotal(1)// - .setConnectionTimeoutInMs(1000)// - .setRequestTimeoutInMs(1000)// + .setAllowPoolingConnections(true)// + .setMaxConnectionsPerHost(1)// + .setMaxConnections(1)// + .setConnectionTimeout(1000)// + .setRequestTimeout(1000)// .setFollowRedirect(true); AsyncHttpClient client = getAsyncHttpClient(bc.build()); 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 d779f2e920..781d841ce0 100644 --- a/src/test/java/com/ning/http/client/async/ConnectionPoolTest.java +++ b/src/test/java/com/ning/http/client/async/ConnectionPoolTest.java @@ -44,7 +44,7 @@ public abstract class ConnectionPoolTest extends AbstractBasicTest { @Test(groups = { "standalone", "default_provider" }) public void testMaxTotalConnections() { - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setAllowPoolingConnection(true).setMaximumConnectionsTotal(1).build()); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setAllowPoolingConnections(true).setMaxConnections(1).build()); try { String url = getTargetUrl(); int i; @@ -66,7 +66,7 @@ public void testMaxTotalConnections() { @Test(groups = { "standalone", "default_provider" }) public void testMaxTotalConnectionsException() { - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setAllowPoolingConnection(true).setMaximumConnectionsTotal(1).build()); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setAllowPoolingConnections(true).setMaxConnections(1).build()); try { String url = getTargetUrl(); int i; @@ -134,7 +134,7 @@ public Response onCompleted(Response response) throws Exception { @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().setAllowPoolingConnections(true).setConnectionTimeout(5000).setMaxConnections(1).build(); AsyncHttpClient client = getAsyncHttpClient(cg); try { String body = "hello there"; @@ -162,7 +162,7 @@ public void multipleMaxConnectionOpenTest() throws Throwable { @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().setAllowPoolingConnections(true).setConnectionTimeout(5000).setMaxConnections(1).build(); AsyncHttpClient client = getAsyncHttpClient(cg); try { String body = "hello there"; @@ -178,7 +178,6 @@ public void multipleMaxConnectionOpenTestWithQuery() throws Throwable { response = client.preparePost(getTargetUrl()).setBody(body).execute().get(TIMEOUT, TimeUnit.SECONDS); } catch (Exception ex) { ex.printStackTrace(); - exception = ex; } assertNull(exception); assertNotNull(response); 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 3ecaad9d0c..6749ad4c84 100644 --- a/src/test/java/com/ning/http/client/async/FilePartLargeFileTest.java +++ b/src/test/java/com/ning/http/client/async/FilePartLargeFileTest.java @@ -41,7 +41,7 @@ public abstract class FilePartLargeFileTest extends AbstractBasicTest { @Test(groups = { "standalone", "default_provider" }, enabled = true) public void testPutImageFile() throws Exception { File largeFile = getTestFile(); - AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder().setRequestTimeoutInMs(100 * 6000).build(); + AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder().setRequestTimeout(100 * 6000).build(); AsyncHttpClient client = getAsyncHttpClient(config); try { BoundRequestBuilder rb = client.preparePut(getTargetUrl()); 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 a568740d83..cb9bfa1875 100644 --- a/src/test/java/com/ning/http/client/async/HttpToHttpsRedirectTest.java +++ b/src/test/java/com/ning/http/client/async/HttpToHttpsRedirectTest.java @@ -120,7 +120,7 @@ public void httpToHttpsRedirect() throws Throwable { isSet.getAndSet(false); AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder()// - .setMaximumNumberOfRedirects(5)// + .setMaxRedirects(5)// .setFollowRedirect(true)// .setAcceptAnyCertificate(true)// .build(); @@ -145,7 +145,7 @@ public void httpToHttpsProperConfig() throws Throwable { isSet.getAndSet(false); AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder()// - .setMaximumNumberOfRedirects(5)// + .setMaxRedirects(5)// .setFollowRedirect(true)// .setAcceptAnyCertificate(true)// .build(); @@ -171,7 +171,7 @@ public void relativeLocationUrl() throws Throwable { isSet.getAndSet(false); AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder()// - .setMaximumNumberOfRedirects(5)// + .setMaxRedirects(5)// .setFollowRedirect(true)// .setAcceptAnyCertificate(true)// .build(); diff --git a/src/test/java/com/ning/http/client/async/IdleStateHandlerTest.java b/src/test/java/com/ning/http/client/async/IdleStateHandlerTest.java index c34015c725..32c469c11e 100644 --- a/src/test/java/com/ning/http/client/async/IdleStateHandlerTest.java +++ b/src/test/java/com/ning/http/client/async/IdleStateHandlerTest.java @@ -75,7 +75,7 @@ public void setUpGlobal() throws Exception { @Test(groups = {"online", "default_provider"}) public void idleStateTest() throws Throwable { isSet.getAndSet(false); - AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setIdleConnectionInPoolTimeoutInMs(10 * 1000).build(); + AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setPooledConnectionIdleTimeout(10 * 1000).build(); AsyncHttpClient client = getAsyncHttpClient(cg); try { 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 405ef9b76d..3b131d8b03 100644 --- a/src/test/java/com/ning/http/client/async/MaxConnectionsInThreads.java +++ b/src/test/java/com/ning/http/client/async/MaxConnectionsInThreads.java @@ -48,7 +48,7 @@ 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 AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setConnectionTimeout(1000).setRequestTimeout(5000).setAllowPoolingConnections(true).setMaxConnections(1).setMaxConnectionsPerHost(1).build()); try { final Boolean[] caughtError = new Boolean[] { Boolean.FALSE }; 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 32417e97c7..73827900ab 100644 --- a/src/test/java/com/ning/http/client/async/MaxTotalConnectionTest.java +++ b/src/test/java/com/ning/http/client/async/MaxTotalConnectionTest.java @@ -37,8 +37,8 @@ public abstract class MaxTotalConnectionTest extends AbstractBasicTest { public void testMaxTotalConnectionsExceedingException() { 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) + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setConnectionTimeout(1000) + .setRequestTimeout(5000).setAllowPoolingConnections(false).setMaxConnections(1).setMaxConnectionsPerHost(1) .build()); try { @@ -62,8 +62,8 @@ public void testMaxTotalConnectionsExceedingException() { public void testMaxTotalConnections() throws IOException { 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) + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setConnectionTimeout(1000) + .setRequestTimeout(5000).setAllowPoolingConnections(false).setMaxConnections(2).setMaxConnectionsPerHost(1) .build()); try { for (String url : urls) { @@ -83,8 +83,8 @@ public void testMaxTotalConnections() throws IOException { public void testMaxTotalConnectionsCorrectExceptionHandling() throws InterruptedException, ExecutionException { 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) + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setConnectionTimeout(1000) + .setRequestTimeout(5000).setAllowPoolingConnections(false).setMaxConnections(1).setMaxConnectionsPerHost(1) .build()); try { List> futures = new ArrayList>(); 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 8521542b54..f4ddd828b0 100644 --- a/src/test/java/com/ning/http/client/async/NoNullResponseTest.java +++ b/src/test/java/com/ning/http/client/async/NoNullResponseTest.java @@ -54,8 +54,8 @@ public void multipleSslRequestsWithDelayAndKeepAlive() throws Throwable { } private AsyncHttpClient create() throws GeneralSecurityException { - final AsyncHttpClientConfig.Builder configBuilder = new AsyncHttpClientConfig.Builder().setCompressionEnabled(true).setFollowRedirect(true).setSSLContext(getSSLContext()).setAllowPoolingConnection(true).setConnectionTimeoutInMs(10000) - .setIdleConnectionInPoolTimeoutInMs(60000).setRequestTimeoutInMs(10000).setMaximumConnectionsPerHost(-1).setMaximumConnectionsTotal(-1); + final AsyncHttpClientConfig.Builder configBuilder = new AsyncHttpClientConfig.Builder().setCompressionEnabled(true).setFollowRedirect(true).setSSLContext(getSSLContext()).setAllowPoolingConnections(true).setConnectionTimeout(10000) + .setPooledConnectionIdleTimeout(60000).setRequestTimeout(10000).setMaxConnectionsPerHost(-1).setMaxConnections(-1); return getAsyncHttpClient(configBuilder.build()); } 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 323dddc4e2..a78ec161ca 100644 --- a/src/test/java/com/ning/http/client/async/PerRequestTimeoutTest.java +++ b/src/test/java/com/ning/http/client/async/PerRequestTimeoutTest.java @@ -98,7 +98,7 @@ public void run() { public void testRequestTimeout() throws IOException { AsyncHttpClient client = getAsyncHttpClient(null); try { - Future responseFuture = client.prepareGet(getTargetUrl()).setRequestTimeoutInMs(100).execute(); + Future responseFuture = client.prepareGet(getTargetUrl()).setRequestTimeout(100).execute(); Response response = responseFuture.get(2000, TimeUnit.MILLISECONDS); assertNull(response); client.close(); @@ -116,9 +116,9 @@ public void testRequestTimeout() throws IOException { @Test(groups = { "standalone", "default_provider" }) public void testGlobalDefaultPerRequestInfiniteTimeout() throws IOException { - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeoutInMs(100).build()); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeout(100).build()); try { - Future responseFuture = client.prepareGet(getTargetUrl()).setRequestTimeoutInMs(-1).execute(); + Future responseFuture = client.prepareGet(getTargetUrl()).setRequestTimeout(-1).execute(); Response response = responseFuture.get(); assertNotNull(response); client.close(); @@ -134,7 +134,7 @@ public void testGlobalDefaultPerRequestInfiniteTimeout() throws IOException { @Test(groups = { "standalone", "default_provider" }) public void testGlobalRequestTimeout() throws IOException { - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeoutInMs(100).build()); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeout(100).build()); try { Future responseFuture = client.prepareGet(getTargetUrl()).execute(); Response response = responseFuture.get(2000, TimeUnit.MILLISECONDS); @@ -156,7 +156,7 @@ public void testGlobalRequestTimeout() throws IOException { public void testGlobalIdleTimeout() throws IOException { final long times[] = new long[] { -1, -1 }; - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setIdleConnectionInPoolTimeoutInMs(2000).build()); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setPooledConnectionIdleTimeout(2000).build()); try { Future responseFuture = client.prepareGet(getTargetUrl()).execute(new AsyncCompletionHandler() { @Override 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 a5d8d73651..71d6516399 100644 --- a/src/test/java/com/ning/http/client/async/PutLargeFileTest.java +++ b/src/test/java/com/ning/http/client/async/PutLargeFileTest.java @@ -44,7 +44,7 @@ public void testPutLargeFile() throws Exception { 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(); + AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder().setConnectionTimeout(timeout).build(); AsyncHttpClient client = getAsyncHttpClient(config); try { BoundRequestBuilder rb = client.preparePut(getTargetUrl()); 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 f178e98c07..704ffd846c 100644 --- a/src/test/java/com/ning/http/client/async/RC10KTest.java +++ b/src/test/java/com/ning/http/client/async/RC10KTest.java @@ -102,7 +102,7 @@ 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 client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setMaximumConnectionsPerHost(C10K).setAllowPoolingConnection(true).build()); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setMaxConnectionsPerHost(C10K).setAllowPoolingConnections(true).build()); try { List> resps = new ArrayList>(C10K); int i = 0; 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 6b490822f5..4e692f9f5f 100644 --- a/src/test/java/com/ning/http/client/async/RedirectConnectionUsageTest.java +++ b/src/test/java/com/ning/http/client/async/RedirectConnectionUsageTest.java @@ -104,11 +104,11 @@ public void tearDown() { public void testGetRedirectFinalUrl() { AsyncHttpClientConfig.Builder bc = new AsyncHttpClientConfig.Builder()// - .setAllowPoolingConnection(true)// - .setMaximumConnectionsPerHost(1)// - .setMaximumConnectionsTotal(1)// - .setConnectionTimeoutInMs(1000)// - .setRequestTimeoutInMs(1000)// + .setAllowPoolingConnections(true)// + .setMaxConnectionsPerHost(1)// + .setMaxConnections(1)// + .setConnectionTimeout(1000)// + .setRequestTimeout(1000)// .setFollowRedirect(true); AsyncHttpClient client = getAsyncHttpClient(bc.build()); 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 b9393a52ac..f5b2d043c4 100644 --- a/src/test/java/com/ning/http/client/async/RemoteSiteTest.java +++ b/src/test/java/com/ning/http/client/async/RemoteSiteTest.java @@ -53,7 +53,7 @@ public abstract class RemoteSiteTest extends AbstractBasicTest { @Test(groups = { "online", "default_provider" }) public void testGoogleCom() throws Throwable { - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeoutInMs(10000).build()); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeout(10000).build()); try { Response response = client.prepareGet("http://www.google.com/").execute().get(10, TimeUnit.SECONDS); assertNotNull(response); @@ -64,7 +64,7 @@ public void testGoogleCom() throws Throwable { @Test(groups = { "online", "default_provider" }) public void testMailGoogleCom() throws Throwable { - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeoutInMs(10000).build()); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeout(10000).build()); try { Response response = client.prepareGet("http://mail.google.com/").execute().get(10, TimeUnit.SECONDS); assertNotNull(response); @@ -76,7 +76,7 @@ public void testMailGoogleCom() throws Throwable { @Test(groups = { "online", "default_provider" }, enabled = false) public void testMicrosoftCom() throws Throwable { - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeoutInMs(10000).build()); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeout(10000).build()); try { Response response = client.prepareGet("http://microsoft.com/").execute().get(10, TimeUnit.SECONDS); assertNotNull(response); @@ -88,7 +88,7 @@ public void testMicrosoftCom() throws Throwable { @Test(groups = { "online", "default_provider" }, enabled = false) public void testWwwMicrosoftCom() throws Throwable { - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeoutInMs(10000).build()); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeout(10000).build()); try { Response response = client.prepareGet("http://www.microsoft.com/").execute().get(10, TimeUnit.SECONDS); assertNotNull(response); @@ -100,7 +100,7 @@ public void testWwwMicrosoftCom() throws Throwable { @Test(groups = { "online", "default_provider" }, enabled = false) public void testUpdateMicrosoftCom() throws Throwable { - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeoutInMs(10000).build()); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeout(10000).build()); try { Response response = client.prepareGet("http://update.microsoft.com/").execute().get(10, TimeUnit.SECONDS); assertNotNull(response); @@ -112,7 +112,7 @@ public void testUpdateMicrosoftCom() throws Throwable { @Test(groups = { "online", "default_provider" }) public void testGoogleComWithTimeout() throws Throwable { - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeoutInMs(10000).build()); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeout(10000).build()); try { Response response = client.prepareGet("http://google.com/").execute().get(10, TimeUnit.SECONDS); assertNotNull(response); @@ -148,7 +148,7 @@ public Response onCompleted(Response response) throws Exception { @Test(groups = { "online", "default_provider" }, enabled = false) public void invalidStreamTest2() throws Throwable { - AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder().setRequestTimeoutInMs(10000).setFollowRedirect(true).setAllowPoolingConnection(false).setMaximumNumberOfRedirects(6).build(); + AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder().setRequestTimeout(10000).setFollowRedirect(true).setAllowPoolingConnections(false).setMaxRedirects(6).build(); AsyncHttpClient client = getAsyncHttpClient(config); try { 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 b2fd6839ab..2aa93db35e 100644 --- a/src/test/java/com/ning/http/client/async/RetryNonBlockingIssue.java +++ b/src/test/java/com/ning/http/client/async/RetryNonBlockingIssue.java @@ -128,10 +128,10 @@ private ListenableFuture testMethodRequest(AsyncHttpClient public void testRetryNonBlocking() throws IOException, InterruptedException, ExecutionException { AsyncHttpClientConfig.Builder bc = new AsyncHttpClientConfig.Builder()// - .setAllowPoolingConnection(true)// - .setMaximumConnectionsTotal(100)// - .setConnectionTimeoutInMs(60000)// - .setRequestTimeoutInMs(30000); + .setAllowPoolingConnections(true)// + .setMaxConnections(100)// + .setConnectionTimeout(60000)// + .setRequestTimeout(30000); AsyncHttpClient client = new AsyncHttpClient(bc.build()); List> res = new ArrayList>(); @@ -162,10 +162,10 @@ public void testRetryNonBlocking() throws IOException, InterruptedException, public void testRetryNonBlockingAsyncConnect() throws IOException, InterruptedException, ExecutionException { AsyncHttpClientConfig.Builder bc = new AsyncHttpClientConfig.Builder()// - .setAllowPoolingConnection(true)// - .setMaximumConnectionsTotal(100)// - .setConnectionTimeoutInMs(60000)// - .setRequestTimeoutInMs(30000); + .setAllowPoolingConnections(true)// + .setMaxConnections(100)// + .setConnectionTimeout(60000)// + .setRequestTimeout(30000); AsyncHttpClient client = new AsyncHttpClient(bc.build()); List> res = new ArrayList>(); try { @@ -195,10 +195,10 @@ public void testRetryNonBlockingAsyncConnect() throws IOException, InterruptedEx public void testRetryBlocking() throws IOException, InterruptedException, ExecutionException { AsyncHttpClientConfig.Builder bc = new AsyncHttpClientConfig.Builder()// - .setAllowPoolingConnection(true)// - .setMaximumConnectionsTotal(100)// - .setConnectionTimeoutInMs(30000)// - .setRequestTimeoutInMs(30000); + .setAllowPoolingConnections(true)// + .setMaxConnections(100)// + .setConnectionTimeout(30000)// + .setRequestTimeout(30000); AsyncHttpClient client = new AsyncHttpClient(bc.build()); List> res = new ArrayList>(); 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 21cfefbb6f..53539389ab 100644 --- a/src/test/java/com/ning/http/client/async/SimpleAsyncHttpClientTest.java +++ b/src/test/java/com/ning/http/client/async/SimpleAsyncHttpClientTest.java @@ -46,7 +46,7 @@ public abstract class SimpleAsyncHttpClientTest extends AbstractBasicTest { @Test(groups = { "standalone", "default_provider" }) public void inputStreamBodyConsumerTest() throws Throwable { - SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setProviderClass(getProviderClass()).setIdleConnectionInPoolTimeoutInMs(100).setMaximumConnectionsTotal(50).setRequestTimeoutInMs(5 * 60 * 1000).setUrl(getTargetUrl()).setHeader("Content-Type", "text/html").build(); + SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setProviderClass(getProviderClass()).setPooledConnectionIdleTimeout(100).setMaximumConnectionsTotal(50).setRequestTimeout(5 * 60 * 1000).setUrl(getTargetUrl()).setHeader("Content-Type", "text/html").build(); try { Future future = client.post(new InputStreamBodyGenerator(new ByteArrayInputStream(MY_MESSAGE.getBytes()))); @@ -62,7 +62,7 @@ public void inputStreamBodyConsumerTest() throws Throwable { @Test(groups = { "standalone", "default_provider" }) public void stringBuilderBodyConsumerTest() throws Throwable { - SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setProviderClass(getProviderClass()).setIdleConnectionInPoolTimeoutInMs(100).setMaximumConnectionsTotal(50).setRequestTimeoutInMs(5 * 60 * 1000).setUrl(getTargetUrl()).setHeader("Content-Type", "text/html").build(); + SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setProviderClass(getProviderClass()).setPooledConnectionIdleTimeout(100).setMaximumConnectionsTotal(50).setRequestTimeout(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)); @@ -79,7 +79,7 @@ public void stringBuilderBodyConsumerTest() throws Throwable { @Test(groups = { "standalone", "default_provider" }) public void byteArrayOutputStreamBodyConsumerTest() throws Throwable { - SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setProviderClass(getProviderClass()).setIdleConnectionInPoolTimeoutInMs(100).setMaximumConnectionsTotal(50).setRequestTimeoutInMs(5 * 60 * 1000).setUrl(getTargetUrl()).setHeader("Content-Type", "text/html").build(); + SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setProviderClass(getProviderClass()).setPooledConnectionIdleTimeout(100).setMaximumConnectionsTotal(50).setRequestTimeout(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)); @@ -115,7 +115,7 @@ public void requestByteArrayOutputStreamBodyConsumerTest() throws Throwable { */ @Test(groups = { "standalone", "default_provider" }, enabled = true) public void testPutZeroBytesFileTest() throws Throwable { - SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setProviderClass(getProviderClass()).setIdleConnectionInPoolTimeoutInMs(100).setMaximumConnectionsTotal(50).setRequestTimeoutInMs(5 * 1000).setUrl(getTargetUrl() + "/testPutZeroBytesFileTest.txt").setHeader("Content-Type", "text/plain") + SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setProviderClass(getProviderClass()).setPooledConnectionIdleTimeout(100).setMaximumConnectionsTotal(50).setRequestTimeout(5 * 1000).setUrl(getTargetUrl() + "/testPutZeroBytesFileTest.txt").setHeader("Content-Type", "text/plain") .build(); try { File tmpfile = File.createTempFile("testPutZeroBytesFile", ".tmp"); 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 0d7216258e..7c57936768 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 @@ -39,7 +39,7 @@ public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { @Override @Test public void testMaxTotalConnectionsException() { - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setAllowPoolingConnection(true).setMaximumConnectionsTotal(1).build()); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setAllowPoolingConnections(true).setMaxConnections(1).build()); try { String url = getTargetUrl(); ListenableFuture lockRequest = null; @@ -65,7 +65,7 @@ public void testMaxTotalConnectionsException() { @Override @Test public void multipleMaxConnectionOpenTest() throws Throwable { - AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setAllowPoolingConnection(true).setConnectionTimeoutInMs(5000).setMaximumConnectionsTotal(1).build(); + AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setAllowPoolingConnections(true).setConnectionTimeout(5000).setMaxConnections(1).build(); AsyncHttpClient c = getAsyncHttpClient(cg); try { String body = "hello there"; 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 c610e4f5db..84d9a40080 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 @@ -135,8 +135,8 @@ private void doSimpleFeeder(final boolean secure) { ExecutorService service = Executors.newFixedThreadPool(threadCount); AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder() - .setMaximumConnectionsPerHost(60) - .setMaximumConnectionsTotal(60) + .setMaxConnectionsPerHost(60) + .setMaxConnections(60) .setAcceptAnyCertificate(true) .build(); final AsyncHttpClient client = new AsyncHttpClient(new GrizzlyAsyncHttpProvider(config), config); @@ -234,8 +234,8 @@ private void doNonBlockingFeeder(final boolean secure) { final ExecutorService service = Executors.newCachedThreadPool(); AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder() - .setMaximumConnectionsPerHost(60) - .setMaximumConnectionsTotal(60) + .setMaxConnectionsPerHost(60) + .setMaxConnections(60) .setAcceptAnyCertificate(true) .build(); final AsyncHttpClient client = new AsyncHttpClient(new GrizzlyAsyncHttpProvider(config), config); diff --git a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyNoTransferEncodingTest.java b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyNoTransferEncodingTest.java index 00a15c596b..eb46291796 100644 --- a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyNoTransferEncodingTest.java +++ b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyNoTransferEncodingTest.java @@ -87,9 +87,9 @@ public void testNoTransferEncoding() throws Exception { AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder() .setCompressionEnabled(true) .setFollowRedirect(false) - .setConnectionTimeoutInMs(15000) - .setRequestTimeoutInMs(15000) - .setAllowPoolingConnection(false) + .setConnectionTimeout(15000) + .setRequestTimeout(15000) + .setAllowPoolingConnections(false) .setDisableUrlEncodingForBoundedRequests(true) .setIOThreadMultiplier(2) // 2 is default .build(); 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 index e4d92c2c48..25687227a7 100644 --- a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyUnexpectingTimeoutTest.java +++ b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyUnexpectingTimeoutTest.java @@ -84,7 +84,7 @@ public void unexpectedTimeoutTest() throws IOException { final AtomicInteger counts = new AtomicInteger(); final int timeout = 100; - final AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeoutInMs(timeout).build()); + final AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeout(timeout).build()); try { Future responseFuture = client.prepareGet(getTargetUrl()).execute(new AsyncCompletionHandler() { diff --git a/src/test/java/com/ning/http/client/async/netty/NettyConnectionPoolTest.java b/src/test/java/com/ning/http/client/async/netty/NettyConnectionPoolTest.java index b016971a72..c81aba6a15 100644 --- a/src/test/java/com/ning/http/client/async/netty/NettyConnectionPoolTest.java +++ b/src/test/java/com/ning/http/client/async/netty/NettyConnectionPoolTest.java @@ -129,7 +129,7 @@ public void destroy() { @Test public void testHostNotContactable() { AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder() - .setAllowPoolingConnection(true).setMaximumConnectionsTotal(1).build()); + .setAllowPoolingConnections(true).setMaxConnections(1).build()); try { String url = null; 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 index f6240ad3e6..515ffb1e6a 100644 --- a/src/test/java/com/ning/http/client/async/netty/NettyRequestThrottleTimeoutTest.java +++ b/src/test/java/com/ning/http/client/async/netty/NettyRequestThrottleTimeoutTest.java @@ -74,7 +74,7 @@ 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()); + .setAllowPoolingConnections(true).setMaxConnections(1).build()); try { final CountDownLatch latch = new CountDownLatch(2); @@ -88,7 +88,7 @@ public void run() { requestThrottle.acquire(); Future responseFuture = null; try { - responseFuture = client.prepareGet(getTargetUrl()).setRequestTimeoutInMs(SLEEPTIME_MS / 2) + responseFuture = client.prepareGet(getTargetUrl()).setRequestTimeout(SLEEPTIME_MS / 2) .execute(new AsyncCompletionHandler() { @Override From 2b7d2c978ae68ef565da577a5ab598a3d849fd69 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 17 Jul 2014 19:16:11 +0200 Subject: [PATCH 441/701] Rename IdleConnectionTimeoutTask into ReadTimeoutTimerTask --- .../netty/NettyAsyncHttpProvider.java | 10 ++++---- ...merTask.java => ReadTimeoutTimerTask.java} | 24 +++++++++---------- .../netty/timeout/TimeoutsHolder.java | 8 +++---- 3 files changed, 21 insertions(+), 21 deletions(-) rename src/main/java/com/ning/http/client/providers/netty/timeout/{IdleConnectionTimeoutTimerTask.java => ReadTimeoutTimerTask.java} (62%) 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 b8468ad137..5b5b1f6e23 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 @@ -125,7 +125,7 @@ import com.ning.http.client.providers.netty.pool.DefaultChannelPool; import com.ning.http.client.providers.netty.pool.NoopChannelPool; import com.ning.http.client.providers.netty.spnego.SpnegoEngine; -import com.ning.http.client.providers.netty.timeout.IdleConnectionTimeoutTimerTask; +import com.ning.http.client.providers.netty.timeout.ReadTimeoutTimerTask; import com.ning.http.client.providers.netty.timeout.RequestTimeoutTimerTask; import com.ning.http.client.providers.netty.timeout.TimeoutsHolder; import com.ning.http.client.uri.UriComponents; @@ -509,11 +509,11 @@ public void operationComplete(ChannelFuture cf) { timeoutsHolder.requestTimeout = newTimeout(new RequestTimeoutTimerTask(future, this, timeoutsHolder, requestTimeout), requestTimeout); } - int idleConnectionTimeout = config.getReadTimeout(); - if (idleConnectionTimeout != -1 && idleConnectionTimeout <= requestTimeout) { + int readTimeout = config.getReadTimeout(); + if (readTimeout != -1 && readTimeout <= requestTimeout) { // no need for a idleConnectionTimeout that's less than the requestTimeout - timeoutsHolder.idleConnectionTimeout = newTimeout(new IdleConnectionTimeoutTimerTask(future, this, timeoutsHolder, - requestTimeout, idleConnectionTimeout), idleConnectionTimeout); + timeoutsHolder.readTimeout = newTimeout(new ReadTimeoutTimerTask(future, this, timeoutsHolder, + requestTimeout, readTimeout), readTimeout); } future.setTimeoutsHolder(timeoutsHolder); diff --git a/src/main/java/com/ning/http/client/providers/netty/timeout/IdleConnectionTimeoutTimerTask.java b/src/main/java/com/ning/http/client/providers/netty/timeout/ReadTimeoutTimerTask.java similarity index 62% rename from src/main/java/com/ning/http/client/providers/netty/timeout/IdleConnectionTimeoutTimerTask.java rename to src/main/java/com/ning/http/client/providers/netty/timeout/ReadTimeoutTimerTask.java index 75c8fb0267..ec397a152d 100644 --- a/src/main/java/com/ning/http/client/providers/netty/timeout/IdleConnectionTimeoutTimerTask.java +++ b/src/main/java/com/ning/http/client/providers/netty/timeout/ReadTimeoutTimerTask.java @@ -19,15 +19,15 @@ import com.ning.http.client.providers.netty.NettyAsyncHttpProvider; import com.ning.http.client.providers.netty.NettyResponseFuture; -public class IdleConnectionTimeoutTimerTask extends TimeoutTimerTask { +public class ReadTimeoutTimerTask extends TimeoutTimerTask { - private final long idleConnectionTimeout; + private final long readTimeout; private final long requestTimeoutInstant; - public IdleConnectionTimeoutTimerTask(NettyResponseFuture nettyResponseFuture, NettyAsyncHttpProvider provider, TimeoutsHolder timeoutsHolder, - long requestTimeout, long idleConnectionTimeout) { + public ReadTimeoutTimerTask(NettyResponseFuture nettyResponseFuture, NettyAsyncHttpProvider provider, TimeoutsHolder timeoutsHolder, + long requestTimeout, long readTimeout) { super(nettyResponseFuture, provider, timeoutsHolder); - this.idleConnectionTimeout = idleConnectionTimeout; + this.readTimeout = readTimeout; requestTimeoutInstant = requestTimeout >= 0 ? nettyResponseFuture.getStart() + requestTimeout : Long.MAX_VALUE; } @@ -40,22 +40,22 @@ public void run(Timeout timeout) throws Exception { long now = millisTime(); - long currentIdleConnectionTimeoutInstant = idleConnectionTimeout + nettyResponseFuture.getLastTouch(); - long durationBeforeCurrentIdleConnectionTimeout = currentIdleConnectionTimeoutInstant - now; + long currentReadTimeoutInstant = readTimeout + nettyResponseFuture.getLastTouch(); + long durationBeforeCurrentReadTimeout = currentReadTimeoutInstant - now; - if (durationBeforeCurrentIdleConnectionTimeout <= 0L) { + if (durationBeforeCurrentReadTimeout <= 0L) { // idleConnectionTimeout reached - String message = "Idle connection timeout to " + nettyResponseFuture.getChannelRemoteAddress() + " of " + idleConnectionTimeout + " ms"; + String message = "Read timeout to " + nettyResponseFuture.getChannelRemoteAddress() + " of " + readTimeout + " ms"; long durationSinceLastTouch = now - nettyResponseFuture.getLastTouch(); expire(message, durationSinceLastTouch); - } else if (currentIdleConnectionTimeoutInstant < requestTimeoutInstant) { + } else if (currentReadTimeoutInstant < requestTimeoutInstant) { // reschedule - timeoutsHolder.idleConnectionTimeout = provider.newTimeout(this, durationBeforeCurrentIdleConnectionTimeout); + timeoutsHolder.readTimeout = provider.newTimeout(this, durationBeforeCurrentReadTimeout); } else { // otherwise, no need to reschedule: requestTimeout will happen sooner - timeoutsHolder.idleConnectionTimeout = null; + timeoutsHolder.readTimeout = null; } } } diff --git a/src/main/java/com/ning/http/client/providers/netty/timeout/TimeoutsHolder.java b/src/main/java/com/ning/http/client/providers/netty/timeout/TimeoutsHolder.java index 33797b80a2..9855f655cd 100644 --- a/src/main/java/com/ning/http/client/providers/netty/timeout/TimeoutsHolder.java +++ b/src/main/java/com/ning/http/client/providers/netty/timeout/TimeoutsHolder.java @@ -20,7 +20,7 @@ public class TimeoutsHolder { private final AtomicBoolean cancelled = new AtomicBoolean(); public volatile Timeout requestTimeout; - public volatile Timeout idleConnectionTimeout; + public volatile Timeout readTimeout; public void cancel() { if (cancelled.compareAndSet(false, true)) { @@ -28,9 +28,9 @@ public void cancel() { requestTimeout.cancel(); requestTimeout = null; } - if (idleConnectionTimeout != null) { - idleConnectionTimeout.cancel(); - idleConnectionTimeout = null; + if (readTimeout != null) { + readTimeout.cancel(); + readTimeout = null; } } } From f0dffd056989a6f55297566ae42f13e4d31e9997 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 17 Jul 2014 23:19:03 +0200 Subject: [PATCH 442/701] Rename webSocketReadTimeout into webSocketTimeout --- .../http/client/AsyncHttpClientConfig.java | 18 +++++++++--------- .../http/client/AsyncHttpClientConfigBean.java | 2 +- .../client/AsyncHttpClientConfigDefaults.java | 4 ++-- .../grizzly/GrizzlyAsyncHttpProvider.java | 4 ++-- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java b/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java index 72f869f2a0..a8dd36d587 100644 --- a/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java @@ -48,7 +48,7 @@ public class AsyncHttpClientConfig { protected int requestTimeout; protected int readTimeout; - protected int webSocketReadTimeout; + protected int webSocketTimeout; protected boolean allowPoolingConnections; protected boolean allowPoolingSslConnections; @@ -120,7 +120,7 @@ private AsyncHttpClientConfig(int connectionTimeout,// this.maxConnectionsPerHost = maxConnectionsPerHost; this.requestTimeout = requestTimeout; this.readTimeout = readTimeout; - this.webSocketReadTimeout = webSocketIdleTimeout; + this.webSocketTimeout = webSocketIdleTimeout; this.allowPoolingConnections = allowPoolingConnection; this.allowPoolingSslConnections = allowSslConnectionPool; this.pooledConnectionIdleTimeout = idleConnectionInPoolTimeout; @@ -179,8 +179,8 @@ public int getConnectionTimeout() { * Return the maximum time, in milliseconds, a {@link com.ning.http.client.websocket.WebSocket} may be idle before being timed out. * @return the maximum time, in milliseconds, a {@link com.ning.http.client.websocket.WebSocket} may be idle before being timed out. */ - public int getWebSocketReadTimeout() { - return webSocketReadTimeout; + public int getWebSocketTimeout() { + return webSocketTimeout; } /** @@ -457,7 +457,7 @@ public static class Builder { private int maxConnectionsPerHost = defaultMaxConnectionsPerHost(); private int requestTimeout = defaultRequestTimeout(); private int readTimeout = defaultReadTimeout(); - private int webSocketReadTimeout = defaultWebSocketReadTimeout(); + private int webSocketTimeout = defaultWebSocketTimeout(); private boolean allowPoolingConnections = defaultAllowPoolingConnections(); private boolean allowPoolingSslConnections = defaultAllowPoolingSslConnections(); private int pooledConnectionIdleTimeout = defaultPooledConnectionIdleTimeout(); @@ -525,12 +525,12 @@ public Builder setConnectionTimeout(int connectionTimeOut) { /** * Set the maximum time in millisecond an {@link com.ning.http.client.websocket.WebSocket} can stay idle. * - * @param webSocketIdleTimeout + * @param webSocketTimeout * the maximum time in millisecond an {@link com.ning.http.client.websocket.WebSocket} can stay idle. * @return a {@link Builder} */ - public Builder setWebSocketIdleTimeout(int webSocketIdleTimeout) { - this.webSocketReadTimeout = webSocketIdleTimeout; + public Builder setWebSocketTimeout(int webSocketTimeout) { + this.webSocketTimeout = webSocketTimeout; return this; } @@ -978,7 +978,7 @@ public Thread newThread(Runnable r) { maxConnectionsPerHost,// requestTimeout,// readTimeout,// - webSocketReadTimeout,// + webSocketTimeout,// allowPoolingConnections,// allowPoolingSslConnections,// pooledConnectionIdleTimeout,// diff --git a/src/main/java/com/ning/http/client/AsyncHttpClientConfigBean.java b/src/main/java/com/ning/http/client/AsyncHttpClientConfigBean.java index a6b8eaf6a6..86e51162bf 100644 --- a/src/main/java/com/ning/http/client/AsyncHttpClientConfigBean.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClientConfigBean.java @@ -48,7 +48,7 @@ void configureDefaults() { maxConnections = defaultMaxConnections(); maxConnectionsPerHost = defaultMaxConnectionsPerHost(); connectionTimeout = defaultConnectionTimeout(); - webSocketReadTimeout = defaultWebSocketReadTimeout(); + webSocketTimeout = defaultWebSocketTimeout(); pooledConnectionIdleTimeout = defaultPooledConnectionIdleTimeout(); readTimeout = defaultReadTimeout(); requestTimeout = defaultRequestTimeout(); diff --git a/src/main/java/com/ning/http/client/AsyncHttpClientConfigDefaults.java b/src/main/java/com/ning/http/client/AsyncHttpClientConfigDefaults.java index b0f8f50f7f..41ad0997c6 100644 --- a/src/main/java/com/ning/http/client/AsyncHttpClientConfigDefaults.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClientConfigDefaults.java @@ -49,8 +49,8 @@ public static int defaultRequestTimeout() { return Integer.getInteger(ASYNC_CLIENT + "requestTimeout", 60 * 1000); } - public static int defaultWebSocketReadTimeout() { - return Integer.getInteger(ASYNC_CLIENT + "webSocketReadTimeout", 15 * 60 * 1000); + public static int defaultWebSocketTimeout() { + return Integer.getInteger(ASYNC_CLIENT + "webSocketTimeout", 15 * 60 * 1000); } public static int defaultConnectionTTL() { 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 f567dcf4f9..ebb38f4d1d 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 @@ -361,7 +361,7 @@ public long getTimeout(FilterChainContext ctx) { HttpTransactionContext.get(ctx.getConnection()); if (context != null) { if (context.isWSRequest) { - return clientConfig.getWebSocketReadTimeout(); + return clientConfig.getWebSocketTimeout(); } final long timeout = context.request.getRequestTimeout(); if (timeout > 0) { @@ -1407,7 +1407,7 @@ protected void onHttpHeadersParsed(HttpHeader httpHeader, context.protocolHandler, ws); ((WebSocketUpgradeHandler) context.handler).onSuccess(context.webSocket); - final int wsTimeout = context.provider.clientConfig.getWebSocketReadTimeout(); + final int wsTimeout = context.provider.clientConfig.getWebSocketTimeout(); IdleTimeoutFilter.setCustomTimeout(ctx.getConnection(), ((wsTimeout <= 0) ? IdleTimeoutFilter.FOREVER From 655b8d987e8c4038939c83f90ac5a7d2f0d2583f Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 17 Jul 2014 23:20:22 +0200 Subject: [PATCH 443/701] Typo --- .../java/com/ning/http/client/AsyncHttpClientConfig.java | 8 ++++---- .../com/ning/http/client/AsyncHttpClientConfigBean.java | 6 +++--- .../ning/http/client/AsyncHttpClientConfigDefaults.java | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java b/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java index a8dd36d587..07f9466cf6 100644 --- a/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java @@ -75,7 +75,7 @@ public class AsyncHttpClientConfig { protected List responseFilters; protected List ioExceptionFilters; protected int maxRequestRetry; - protected boolean disableUrlEncodingForBoundedRequests; + protected boolean disableUrlEncodingForBoundRequests; protected int ioThreadMultiplier; protected TimeConverter timeConverter; protected AsyncHttpProviderConfig providerConfig; @@ -142,7 +142,7 @@ private AsyncHttpClientConfig(int connectionTimeout,// this.responseFilters = responseFilters; this.ioExceptionFilters = ioExceptionFilters; this.maxRequestRetry = maxRequestRetry; - this.disableUrlEncodingForBoundedRequests = disableUrlEncodingForBoundedRequests; + this.disableUrlEncodingForBoundRequests = disableUrlEncodingForBoundedRequests; this.ioThreadMultiplier = ioThreadMultiplier; this.timeConverter = timeConverter; this.providerConfig = providerConfig; @@ -353,7 +353,7 @@ public boolean isAllowPoolingSslConnections() { * @return the disableUrlEncodingForBoundedRequests */ public boolean isDisableUrlEncodingForBoundedRequests() { - return disableUrlEncodingForBoundedRequests; + return disableUrlEncodingForBoundRequests; } /** @@ -481,7 +481,7 @@ public static class Builder { private final List responseFilters = new LinkedList(); private final List ioExceptionFilters = new LinkedList(); private int maxRequestRetry = defaultMaxRequestRetry(); - private boolean disableUrlEncodingForBoundedRequests = defaultDisableUrlEncodingForBoundedRequests(); + private boolean disableUrlEncodingForBoundedRequests = defaultDisableUrlEncodingForBoundRequests(); private int ioThreadMultiplier = defaultIoThreadMultiplier(); private TimeConverter timeConverter; private AsyncHttpProviderConfig providerConfig; diff --git a/src/main/java/com/ning/http/client/AsyncHttpClientConfigBean.java b/src/main/java/com/ning/http/client/AsyncHttpClientConfigBean.java index 86e51162bf..397748b19c 100644 --- a/src/main/java/com/ning/http/client/AsyncHttpClientConfigBean.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClientConfigBean.java @@ -62,7 +62,7 @@ void configureDefaults() { maxRequestRetry = defaultMaxRequestRetry(); ioThreadMultiplier = defaultIoThreadMultiplier(); allowPoolingSslConnections = defaultAllowPoolingSslConnections(); - disableUrlEncodingForBoundedRequests = defaultDisableUrlEncodingForBoundedRequests(); + disableUrlEncodingForBoundRequests = defaultDisableUrlEncodingForBoundRequests(); removeQueryParamOnRedirect = defaultRemoveQueryParamOnRedirect(); strict302Handling = defaultStrict302Handling(); hostnameVerifier = defaultHostnameVerifier(); @@ -208,8 +208,8 @@ public AsyncHttpClientConfigBean setAllowSslConnectionPool(boolean allowSslConne return this; } - public AsyncHttpClientConfigBean setDisableUrlEncodingForBoundedRequests(boolean disableUrlEncodingForBoundedRequests) { - this.disableUrlEncodingForBoundedRequests = disableUrlEncodingForBoundedRequests; + public AsyncHttpClientConfigBean setDisableUrlEncodingForBoundRequests(boolean disableUrlEncodingForBoundRequests) { + this.disableUrlEncodingForBoundRequests = disableUrlEncodingForBoundRequests; return this; } diff --git a/src/main/java/com/ning/http/client/AsyncHttpClientConfigDefaults.java b/src/main/java/com/ning/http/client/AsyncHttpClientConfigDefaults.java index 41ad0997c6..4e2f5f74b1 100644 --- a/src/main/java/com/ning/http/client/AsyncHttpClientConfigDefaults.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClientConfigDefaults.java @@ -105,8 +105,8 @@ public static boolean defaultAllowPoolingSslConnections() { return getBoolean(ASYNC_CLIENT + "allowPoolingSslConnections", true); } - public static boolean defaultDisableUrlEncodingForBoundedRequests() { - return Boolean.getBoolean(ASYNC_CLIENT + "disableUrlEncodingForBoundedRequests"); + public static boolean defaultDisableUrlEncodingForBoundRequests() { + return Boolean.getBoolean(ASYNC_CLIENT + "disableUrlEncodingForBoundRequests"); } public static boolean defaultRemoveQueryParamOnRedirect() { From 6c503b59d4782cd8d7ce4973a577c2c2edaa0a66 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 17 Jul 2014 23:22:54 +0200 Subject: [PATCH 444/701] minor clean up --- src/main/java/com/ning/http/client/AsyncHttpClient.java | 4 ++-- 1 file changed, 2 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 efe4fd50c5..7226e16c69 100755 --- a/src/main/java/com/ning/http/client/AsyncHttpClient.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClient.java @@ -136,12 +136,12 @@ *

    * Finally, you can configure the AsyncHttpClient using an {@link AsyncHttpClientConfig} instance

    *
    - *      AsyncHttpClient c = new AsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeoutInMs(...).build());
    + *      AsyncHttpClient c = new AsyncHttpClient(new AsyncHttpClientConfig.Builder().setRequestTimeout(...).build());
      *      Future f = c.prepareGet(TARGET_URL).execute();
      *      Response r = f.get();
      * 
    *

    - * An instance of this class will cache every HTTP 1.1 connections and close them when the {@link AsyncHttpClientConfig#getIdleConnectionTimeoutInMs()} + * An instance of this class will cache every HTTP 1.1 connections and close them when the {@link AsyncHttpClientConfig#getIdleConnectionTimeout()} * expires. This object can hold many persistent connections to different host. */ public class AsyncHttpClient implements Closeable { From 21f59b4988b744f9e211030bcd0689d4656649f5 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 18 Jul 2014 15:53:41 +0200 Subject: [PATCH 445/701] [maven-release-plugin] prepare release async-http-client-1.9.0-BETA2 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 5a3a81753d..3ed46087d4 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.9.0-SNAPSHOT + 1.9.0-BETA2 jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From dd9a8f8dac1c3bc0a7bff624d160def1d7465aef Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 18 Jul 2014 15:53:45 +0200 Subject: [PATCH 446/701] [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 3ed46087d4..5a3a81753d 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.9.0-BETA2 + 1.9.0-SNAPSHOT jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From d88deafc2843c442c5ab15eb2dc4cceb93308ead Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 18 Jul 2014 16:40:31 +0200 Subject: [PATCH 447/701] Unused parameter --- .../http/client/providers/netty/pool/DefaultChannelPool.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/pool/DefaultChannelPool.java b/src/main/java/com/ning/http/client/providers/netty/pool/DefaultChannelPool.java index e09e478ba0..7849092510 100644 --- a/src/main/java/com/ning/http/client/providers/netty/pool/DefaultChannelPool.java +++ b/src/main/java/com/ning/http/client/providers/netty/pool/DefaultChannelPool.java @@ -53,15 +53,13 @@ public final class DefaultChannelPool implements ChannelPool { private final long cleanerPeriod; public DefaultChannelPool(AsyncHttpClientConfig config, Timer hashedWheelTimer) { - this(config.getMaxConnectionsPerHost(),// - config.getPooledConnectionIdleTimeout(),// + this(config.getPooledConnectionIdleTimeout(),// config.getConnectionTTL(),// config.isAllowPoolingSslConnections(),// hashedWheelTimer); } public DefaultChannelPool(// - int maxConnectionPerHost,// long maxIdleTime,// int maxConnectionTTL,// boolean sslConnectionPoolEnabled,// From 876db0ed7465c5ad1cb3db8d53af015599e11822 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 21 Jul 2014 13:39:36 +0200 Subject: [PATCH 448/701] Optimize stack scan, close #635 --- .../netty/NettyAsyncHttpProvider.java | 69 +------------------ .../providers/netty/NettyConnectListener.java | 3 +- .../providers/netty/StackTraceInspector.java | 55 +++++++++++++++ 3 files changed, 58 insertions(+), 69 deletions(-) create mode 100644 src/main/java/com/ning/http/client/providers/netty/StackTraceInspector.java 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 5b5b1f6e23..0f6cf4b99c 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 @@ -1365,7 +1365,7 @@ public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws } } - if (abortOnReadCloseException(cause) || abortOnWriteCloseException(cause)) { + if (StackTraceInspector.abortOnReadOrWriteException(cause)) { LOGGER.debug("Trying to recover from dead Channel: {}", channel); return; } @@ -1392,71 +1392,6 @@ public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws ctx.sendUpstream(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")) { - return true; - } - } - - if (cause.getCause() != null) { - return abortOnConnectCloseException(cause.getCause()); - } - - } catch (Throwable t) { - } - return false; - } - - 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")) { - return true; - } - } - - if (cause.getCause() != null) { - return abortOnConnectCloseException(cause.getCause()); - } - - } catch (Throwable t) { - } - return false; - } - - protected static boolean abortOnReadCloseException(Throwable cause) { - - for (StackTraceElement element : cause.getStackTrace()) { - if (element.getClassName().equals("sun.nio.ch.SocketDispatcher") && element.getMethodName().equals("read")) { - return true; - } - } - - if (cause.getCause() != null) { - return abortOnReadCloseException(cause.getCause()); - } - - return false; - } - - protected static boolean abortOnWriteCloseException(Throwable cause) { - - for (StackTraceElement element : cause.getStackTrace()) { - if (element.getClassName().equals("sun.nio.ch.SocketDispatcher") && element.getMethodName().equals("write")) { - return true; - } - } - - if (cause.getCause() != null) { - return abortOnWriteCloseException(cause.getCause()); - } - - return false; - } - public static NettyResponseFuture newFuture(UriComponents uri, Request request, AsyncHandler asyncHandler, HttpRequest nettyRequest, AsyncHttpClientConfig config, ProxyServer proxyServer) { @@ -1503,7 +1438,7 @@ public void operationComplete(ChannelFuture cf) { return; } - if (cause instanceof ClosedChannelException || abortOnReadCloseException(cause) || abortOnWriteCloseException(cause)) { + if (cause instanceof ClosedChannelException || StackTraceInspector.abortOnReadOrWriteException(cause)) { if (LOGGER.isDebugEnabled()) { LOGGER.debug(cf.getCause() == null ? "" : cf.getCause().getMessage(), cf.getCause()); 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 6eb82e76ae..6f4910d8be 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 @@ -129,8 +129,7 @@ public void operationComplete(ChannelFuture handshakeFuture) throws Exception { LOGGER.debug("Trying to recover a dead cached channel {} with a retry value of {} ", f.getChannel(), canRetry); if (canRetry && cause != null - && (NettyAsyncHttpProvider.abortOnDisconnectException(cause) || cause instanceof ClosedChannelException || future - .getState() != NettyResponseFuture.STATE.NEW)) { + && (cause instanceof ClosedChannelException || future.getState() != NettyResponseFuture.STATE.NEW || StackTraceInspector.abortOnDisconnectException(cause))) { LOGGER.debug("Retrying {} ", nettyRequest); if (!provider.retry(channel, future)) diff --git a/src/main/java/com/ning/http/client/providers/netty/StackTraceInspector.java b/src/main/java/com/ning/http/client/providers/netty/StackTraceInspector.java new file mode 100644 index 0000000000..59e6afcb8a --- /dev/null +++ b/src/main/java/com/ning/http/client/providers/netty/StackTraceInspector.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2014 AsyncHttpClient Project. 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.providers.netty; + +public class StackTraceInspector { + + private static boolean exceptionInMethod(Throwable t, String className, String methodName) { + try { + for (StackTraceElement element : t.getStackTrace()) { + if (element.getClassName().equals(className) && element.getMethodName().equals(methodName)) + return true; + } + } catch (Throwable ignore) { + } + return false; + } + + private static boolean abortOnConnectCloseException(Throwable t) { + return exceptionInMethod(t, "sun.nio.ch.SocketChannelImpl", "checkConnect") + || (t.getCause() != null && abortOnConnectCloseException(t.getCause())); + } + + public static boolean abortOnDisconnectException(Throwable t) { + return exceptionInMethod(t, "org.jboss.netty.handler.ssl.SslHandler", "channelDisconnected") + || (t.getCause() != null && abortOnConnectCloseException(t.getCause())); + } + + public static boolean abortOnReadOrWriteException(Throwable t) { + + try { + for (StackTraceElement element : t.getStackTrace()) { + String className = element.getClassName(); + String methodName = element.getMethodName(); + if (className.equals("sun.nio.ch.SocketDispatcher") && (methodName.equals("read") || methodName.equals("write"))) + return true; + } + } catch (Throwable ignore) { + } + + if (t.getCause() != null) + return abortOnReadOrWriteException(t.getCause()); + + return false; + } +} \ No newline at end of file From 22b922a4c5819dc2f1678a3bfcc7eabf3f5efd00 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 21 Jul 2014 14:31:00 +0200 Subject: [PATCH 449/701] NettyResponseFuture.get should always block on the latch, close #489 --- .../http/client/providers/netty/NettyResponseFuture.java | 5 ++--- 1 file changed, 2 insertions(+), 3 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 b7bbc23e8e..beb2293b73 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 @@ -157,8 +157,7 @@ public boolean cancel(boolean force) { * {@inheritDoc} */ public V get() throws InterruptedException, ExecutionException { - if (!isDone()) - latch.await(); + latch.await(); return getContent(); } @@ -166,7 +165,7 @@ public V get() throws InterruptedException, ExecutionException { * {@inheritDoc} */ public V get(long l, TimeUnit tu) throws InterruptedException, TimeoutException, ExecutionException { - if (!isDone() && !latch.await(l, tu)) + if (!latch.await(l, tu)) throw new TimeoutException(); return getContent(); } From 9578c5f0d92cc8cddd251e1df2a8a4186e4ceaee Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 21 Jul 2014 15:04:18 +0200 Subject: [PATCH 450/701] Minor clean up --- .../ning/http/util/AuthenticatorUtils.java | 33 ++++++++++--------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/ning/http/util/AuthenticatorUtils.java b/src/main/java/com/ning/http/util/AuthenticatorUtils.java index 7e491acff5..0d3859f448 100644 --- a/src/main/java/com/ning/http/util/AuthenticatorUtils.java +++ b/src/main/java/com/ning/http/util/AuthenticatorUtils.java @@ -51,27 +51,30 @@ private static String computeRealmURI(Realm realm) { public static String computeDigestAuthentication(Realm realm) throws NoSuchAlgorithmException, UnsupportedEncodingException { StringBuilder builder = new StringBuilder().append("Digest "); - construct(builder, "username", realm.getPrincipal()); - construct(builder, "realm", realm.getRealmName()); - construct(builder, "nonce", realm.getNonce()); - construct(builder, "uri", computeRealmURI(realm)); - builder.append("algorithm").append('=').append(realm.getAlgorithm()).append(", "); + append(builder, "username", realm.getPrincipal(), true); + append(builder, "realm", realm.getRealmName(), true); + append(builder, "nonce", realm.getNonce(), true); + append(builder, "uri", computeRealmURI(realm), true); + append(builder, "algorithm", realm.getAlgorithm(), false); - construct(builder, "response", realm.getResponse()); + append(builder, "response", realm.getResponse(), true); 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(", "); - construct(builder, "cnonce", realm.getCnonce(), true); + append(builder, "opaque", realm.getOpaque(), true); + append(builder, "qop", realm.getQop(), false); + append(builder, "nc", realm.getNc(), false); + append(builder, "cnonce", realm.getCnonce(), true); + builder.setLength(builder.length() - 2); // remove tailing ", " return new String(builder.toString().getBytes("ISO-8859-1")); } - private static StringBuilder construct(StringBuilder builder, String name, String value) { - return construct(builder, name, value, false); - } + private static StringBuilder append(StringBuilder builder, String name, String value, boolean quoted) { + builder.append(name).append('='); + if (quoted) + builder.append('"').append(value).append('"'); + else + builder.append(value); - private static StringBuilder construct(StringBuilder builder, String name, String value, boolean tail) { - return builder.append(name).append('=').append('"').append(value).append(tail ? "\"" : "\", "); + return builder.append(", "); } } From 501b5b4eb04e0934012632082e5edf77e2446735 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 21 Jul 2014 15:10:09 +0200 Subject: [PATCH 451/701] Backport StandardCharsets --- .../com/ning/http/client/ProxyServer.java | 4 ++- src/main/java/com/ning/http/client/Realm.java | 3 +- .../java/com/ning/http/client/StringPart.java | 4 ++- .../consumers/AppendableBodyConsumer.java | 3 +- .../oauth/OAuthSignatureCalculator.java | 4 +-- .../http/client/oauth/ThreadSafeHMAC.java | 4 +-- .../grizzly/GrizzlyAsyncHttpProvider.java | 2 -- .../netty/NettyAsyncHttpProvider.java | 5 ++- .../PropertiesBasedResumableProcessor.java | 6 ++-- .../ning/http/util/AuthenticatorUtils.java | 4 +-- .../java/com/ning/http/util/MiscUtils.java | 5 +-- .../com/ning/http/util/StandardCharsets.java | 27 ++++++++++++++ .../java/com/ning/http/util/UTF8Codec.java | 35 ------------------- 13 files changed, 52 insertions(+), 54 deletions(-) create mode 100644 src/main/java/com/ning/http/util/StandardCharsets.java delete mode 100644 src/main/java/com/ning/http/util/UTF8Codec.java diff --git a/src/main/java/com/ning/http/client/ProxyServer.java b/src/main/java/com/ning/http/client/ProxyServer.java index e069ea0ace..57e006c5ef 100644 --- a/src/main/java/com/ning/http/client/ProxyServer.java +++ b/src/main/java/com/ning/http/client/ProxyServer.java @@ -16,6 +16,8 @@ */ package com.ning.http.client; +import com.ning.http.util.StandardCharsets; + import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -51,7 +53,7 @@ public String toString() { private final String password; private final int port; private final String url; - private String encoding = "UTF-8"; + private String encoding = StandardCharsets.UTF_8.name(); private String ntlmDomain = System.getProperty("http.auth.ntlm.domain", ""); public ProxyServer(final Protocol protocol, final String host, final int port, String principal, String password) { diff --git a/src/main/java/com/ning/http/client/Realm.java b/src/main/java/com/ning/http/client/Realm.java index 3d42e1afb0..48fe4a0297 100644 --- a/src/main/java/com/ning/http/client/Realm.java +++ b/src/main/java/com/ning/http/client/Realm.java @@ -19,6 +19,7 @@ import static com.ning.http.util.MiscUtils.isNonEmpty; import com.ning.http.client.uri.UriComponents; +import com.ning.http.util.StandardCharsets; import java.io.UnsupportedEncodingException; import java.security.MessageDigest; @@ -297,7 +298,7 @@ public static class RealmBuilder { private String methodName = "GET"; private boolean usePreemptive = false; private String ntlmDomain = System.getProperty("http.auth.ntlm.domain", ""); - private String enc = "UTF-8"; + private String enc = StandardCharsets.UTF_8.name(); private String host = "localhost"; private boolean messageType2Received = false; private boolean useAbsoluteURI = true; diff --git a/src/main/java/com/ning/http/client/StringPart.java b/src/main/java/com/ning/http/client/StringPart.java index acdb49b192..120d08cc17 100644 --- a/src/main/java/com/ning/http/client/StringPart.java +++ b/src/main/java/com/ning/http/client/StringPart.java @@ -16,6 +16,8 @@ */ package com.ning.http.client; +import com.ning.http.util.StandardCharsets; + /** * A string multipart part. */ @@ -33,7 +35,7 @@ public StringPart(String name, String value, String charset) { public StringPart(String name, String value) { this.name = name; this.value = value; - this.charset = "UTF-8"; + this.charset = StandardCharsets.UTF_8.name(); } /** 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 a1e9dc5ade..6522a744db 100644 --- a/src/main/java/com/ning/http/client/consumers/AppendableBodyConsumer.java +++ b/src/main/java/com/ning/http/client/consumers/AppendableBodyConsumer.java @@ -13,6 +13,7 @@ package com.ning.http.client.consumers; import com.ning.http.client.BodyConsumer; +import com.ning.http.util.StandardCharsets; import java.io.Closeable; import java.io.IOException; @@ -33,7 +34,7 @@ public AppendableBodyConsumer(Appendable appendable, String encoding) { public AppendableBodyConsumer(Appendable appendable) { this.appendable = appendable; - this.encoding = "UTF-8"; + this.encoding = StandardCharsets.UTF_8.name(); } /** 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 8884a6a828..e538e6e07b 100644 --- a/src/main/java/com/ning/http/client/oauth/OAuthSignatureCalculator.java +++ b/src/main/java/com/ning/http/client/oauth/OAuthSignatureCalculator.java @@ -24,7 +24,7 @@ import com.ning.http.client.SignatureCalculator; import com.ning.http.client.uri.UriComponents; import com.ning.http.util.Base64; -import com.ning.http.util.UTF8Codec; +import com.ning.http.util.StandardCharsets; import com.ning.http.util.UTF8UrlEncoder; import java.util.ArrayList; @@ -153,7 +153,7 @@ else if (scheme.equals("https")) signedText.append('&'); UTF8UrlEncoder.appendEncoded(signedText, encodedParams); - byte[] rawBase = UTF8Codec.toUTF8(signedText.toString()); + byte[] rawBase = signedText.toString().getBytes(StandardCharsets.UTF_8); byte[] rawSignature = mac.digest(rawBase); // and finally, base64 encoded... phew! return Base64.encode(rawSignature); 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 d5529a31cc..2f47afc11c 100644 --- a/src/main/java/com/ning/http/client/oauth/ThreadSafeHMAC.java +++ b/src/main/java/com/ning/http/client/oauth/ThreadSafeHMAC.java @@ -16,7 +16,7 @@ */ package com.ning.http.client.oauth; -import com.ning.http.util.UTF8Codec; +import com.ning.http.util.StandardCharsets; import com.ning.http.util.UTF8UrlEncoder; import javax.crypto.Mac; @@ -41,7 +41,7 @@ public ThreadSafeHMAC(ConsumerKey consumerAuth, RequestToken userAuth) { UTF8UrlEncoder.appendEncoded(sb, consumerAuth.getSecret()); sb.append('&'); UTF8UrlEncoder.appendEncoded(sb, userAuth.getSecret()); - byte[] keyBytes = UTF8Codec.toUTF8(sb.toString()); + byte[] keyBytes = sb.toString().getBytes(StandardCharsets.UTF_8); SecretKeySpec signingKey = new SecretKeySpec(keyBytes, HMAC_SHA1_ALGORITHM); // Get an hmac_sha1 instance and initialize with the signing key 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 ebb38f4d1d..19ed204317 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 @@ -1609,8 +1609,6 @@ public boolean handleStatus(final HttpResponsePacket responsePacket, AuthenticatorUtils.computeDigestAuthentication(realm)); } catch (NoSuchAlgorithmException e) { throw new IllegalStateException("Digest authentication not supported", e); - } catch (UnsupportedEncodingException e) { - throw new IllegalStateException("Unsupported encoding.", e); } } else { throw new IllegalStateException("Unsupported authorization method: " + auth); 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 0f6cf4b99c..dda5e598e3 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 @@ -30,7 +30,6 @@ 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; @@ -136,6 +135,7 @@ import com.ning.http.util.AuthenticatorUtils; import com.ning.http.util.ProxyUtils; import com.ning.http.util.SslUtils; +import com.ning.http.util.StandardCharsets; public class NettyAsyncHttpProvider extends SimpleChannelUpstreamHandler implements AsyncHttpProvider { @@ -156,7 +156,6 @@ public class NettyAsyncHttpProvider extends SimpleChannelUpstreamHandler impleme private static final String HTTP = "http"; private static final String WEBSOCKET = "ws"; private static final String WEBSOCKET_SSL = "wss"; - private static final Charset UTF8 = Charset.forName("UTF-8"); private final ClientBootstrap plainBootstrap; private final ClientBootstrap secureBootstrap; @@ -2161,7 +2160,7 @@ public void setContent(ChannelBuffer content) { if (pendingOpcode == OPCODE_BINARY) { webSocket.onBinaryFragment(rp.getBodyPartBytes(), frame.isFinalFragment()); } else if (pendingOpcode == OPCODE_TEXT) { - webSocket.onTextFragment(frame.getBinaryData().toString(UTF8), frame.isFinalFragment()); + webSocket.onTextFragment(frame.getBinaryData().toString(StandardCharsets.UTF_8), frame.isFinalFragment()); } if (frame instanceof CloseWebSocketFrame) { 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 c9ae94af6e..7d027b9ac3 100644 --- a/src/main/java/com/ning/http/client/resumable/PropertiesBasedResumableProcessor.java +++ b/src/main/java/com/ning/http/client/resumable/PropertiesBasedResumableProcessor.java @@ -15,6 +15,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.ning.http.util.StandardCharsets; + import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; @@ -74,7 +76,7 @@ public void save(Map map) { os = new FileOutputStream(f); for (Map.Entry e : properties.entrySet()) { - os.write((append(e)).getBytes("UTF-8")); + os.write((append(e)).getBytes(StandardCharsets.UTF_8)); } os.flush(); } catch (Throwable e) { @@ -100,7 +102,7 @@ private static String append(Map.Entry e) { public Map load() { Scanner scan = null; try { - scan = new Scanner(new File(TMP, storeName), "UTF-8"); + scan = new Scanner(new File(TMP, storeName), StandardCharsets.UTF_8.name()); scan.useDelimiter("[=\n]"); String key; diff --git a/src/main/java/com/ning/http/util/AuthenticatorUtils.java b/src/main/java/com/ning/http/util/AuthenticatorUtils.java index 0d3859f448..dc2f2d68f8 100644 --- a/src/main/java/com/ning/http/util/AuthenticatorUtils.java +++ b/src/main/java/com/ning/http/util/AuthenticatorUtils.java @@ -48,7 +48,7 @@ private static String computeRealmURI(Realm realm) { } } - public static String computeDigestAuthentication(Realm realm) throws NoSuchAlgorithmException, UnsupportedEncodingException { + public static String computeDigestAuthentication(Realm realm) throws NoSuchAlgorithmException { StringBuilder builder = new StringBuilder().append("Digest "); append(builder, "username", realm.getPrincipal(), true); @@ -65,7 +65,7 @@ public static String computeDigestAuthentication(Realm realm) throws NoSuchAlgor append(builder, "cnonce", realm.getCnonce(), true); builder.setLength(builder.length() - 2); // remove tailing ", " - return new String(builder.toString().getBytes("ISO-8859-1")); + return new String(builder.toString().getBytes(StandardCharsets.ISO_8859_1)); } private static StringBuilder append(StringBuilder builder, String name, String value, boolean quoted) { diff --git a/src/main/java/com/ning/http/util/MiscUtils.java b/src/main/java/com/ning/http/util/MiscUtils.java index dab4d5df95..f5839a0d0a 100644 --- a/src/main/java/com/ning/http/util/MiscUtils.java +++ b/src/main/java/com/ning/http/util/MiscUtils.java @@ -1,9 +1,10 @@ /* - * Copyright (c) 2010-2012 Sonatype, Inc. All rights reserved. + * Copyright (c) 2014 AsyncHttpClient Project. 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. + * 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 diff --git a/src/main/java/com/ning/http/util/StandardCharsets.java b/src/main/java/com/ning/http/util/StandardCharsets.java new file mode 100644 index 0000000000..627ba051ea --- /dev/null +++ b/src/main/java/com/ning/http/util/StandardCharsets.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2014 AsyncHttpClient Project. 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.nio.charset.Charset; + +public final class StandardCharsets { + + public static final Charset US_ASCII = Charset.forName("US-ASCII"); + public static final Charset UTF_8 = Charset.forName("UTF-8"); + public static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1"); + public static final Charset UNICODE_LITTLE_UNMARKED = Charset.forName("UnicodeLittleUnmarked"); + + private StandardCharsets() { + } +} diff --git a/src/main/java/com/ning/http/util/UTF8Codec.java b/src/main/java/com/ning/http/util/UTF8Codec.java deleted file mode 100644 index 01768d3d9a..0000000000 --- a/src/main/java/com/ning/http/util/UTF8Codec.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * 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.util; - -import java.io.UnsupportedEncodingException; - -/** - * Wrapper class for more convenient (and possibly more efficient in future) - * UTF-8 encoding and decoding. - */ -public class UTF8Codec { - private final static String ENCODING_UTF8 = "UTF-8"; - - // Until we target JDK6+ - public static byte[] toUTF8(String input) { - try { - return input.getBytes(ENCODING_UTF8); - } catch (UnsupportedEncodingException e) { // never happens, but since it's declared... - throw new IllegalStateException(); - } - } -} From da26da02444b9e6c1313233e5ef65ace9b7f1950 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 21 Jul 2014 15:28:04 +0200 Subject: [PATCH 452/701] minor clean up --- src/main/java/com/ning/http/client/Realm.java | 10 +++++----- .../providers/apache/ApacheAsyncHttpProvider.java | 7 ++++--- .../http/client/providers/apache/ApacheResponse.java | 3 ++- .../client/providers/jdk/JDKAsyncHttpProvider.java | 2 +- .../ning/http/client/providers/jdk/JDKResponse.java | 3 ++- .../providers/netty/NettyAsyncHttpProvider.java | 3 ++- .../http/client/providers/netty/NettyResponse.java | 3 ++- .../com/ning/http/util/AsyncHttpProviderUtils.java | 3 ++- src/test/java/com/ning/http/client/RealmTest.java | 3 ++- .../http/client/async/AsyncProvidersBasicTest.java | 3 ++- .../ning/http/client/async/MultipartUploadTest.java | 11 +++++++---- 11 files changed, 31 insertions(+), 20 deletions(-) diff --git a/src/main/java/com/ning/http/client/Realm.java b/src/main/java/com/ning/http/client/Realm.java index 48fe4a0297..46053c082e 100644 --- a/src/main/java/com/ning/http/client/Realm.java +++ b/src/main/java/com/ning/http/client/Realm.java @@ -530,7 +530,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(System.currentTimeMillis()).getBytes(StandardCharsets.ISO_8859_1)); cnonce = toHexString(b); } catch (Exception e) { throw new SecurityException(e); @@ -577,7 +577,7 @@ private void newResponse() throws UnsupportedEncodingException { .append(realmName) .append(":") .append(password) - .toString().getBytes("ISO-8859-1")); + .toString().getBytes(StandardCharsets.ISO_8859_1)); byte[] ha1 = md.digest(); md.reset(); @@ -585,7 +585,7 @@ private void newResponse() throws UnsupportedEncodingException { //HA2 if qop is auth-int is methodName:url:md5(entityBody) md.update(new StringBuilder(methodName) .append(':') - .append(uri).toString().getBytes("ISO-8859-1")); + .append(uri).toString().getBytes(StandardCharsets.ISO_8859_1)); byte[] ha2 = md.digest(); if(qop==null || qop.equals("")) { @@ -593,7 +593,7 @@ private void newResponse() throws UnsupportedEncodingException { .append(':') .append(nonce) .append(':') - .append(toBase16(ha2)).toString().getBytes("ISO-8859-1")); + .append(toBase16(ha2)).toString().getBytes(StandardCharsets.ISO_8859_1)); } else { //qop ="auth" or "auth-int" @@ -607,7 +607,7 @@ private void newResponse() throws UnsupportedEncodingException { .append(':') .append(qop) .append(':') - .append(toBase16(ha2)).toString().getBytes("ISO-8859-1")); + .append(toBase16(ha2)).toString().getBytes(StandardCharsets.ISO_8859_1)); } byte[] digest = md.digest(); 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 af0d4091f4..8065e15f16 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 @@ -45,6 +45,7 @@ import com.ning.http.client.uri.UriComponents; import com.ning.http.util.AsyncHttpProviderUtils; import com.ning.http.util.ProxyUtils; +import com.ning.http.util.StandardCharsets; import com.ning.http.util.UTF8UrlEncoder; import org.apache.commons.httpclient.CircularRedirectException; @@ -251,9 +252,9 @@ private HttpMethodBase createMethod(HttpClient client, Request request) throws I if (methodName.equalsIgnoreCase("POST") || methodName.equalsIgnoreCase("PUT")) { EntityEnclosingMethod post = methodName.equalsIgnoreCase("POST") ? new PostMethod(request.getURI().toUrl()) : new PutMethod(request.getURI().toUrl()); - String bodyCharset = request.getBodyEncoding() == null ? DEFAULT_CHARSET : request.getBodyEncoding(); + String bodyCharset = request.getBodyEncoding() == null ? DEFAULT_CHARSET.name() : request.getBodyEncoding(); - post.getParams().setContentCharset("ISO-8859-1"); + post.getParams().setContentCharset(StandardCharsets.ISO_8859_1.name()); if (request.getByteData() != null) { post.setRequestEntity(new ByteArrayRequestEntity(request.getByteData())); post.setRequestHeader("Content-Length", String.valueOf(request.getByteData().length)); @@ -279,7 +280,7 @@ private HttpMethodBase createMethod(HttpClient client, Request request) throws I } post.setRequestHeader("Content-Length", String.valueOf(sb.length())); - post.setRequestEntity(new StringRequestEntity(sb.toString(), "text/xml", "ISO-8859-1")); + post.setRequestEntity(new StringRequestEntity(sb.toString(), "text/xml", StandardCharsets.ISO_8859_1.name())); if (!request.getHeaders().containsKey("Content-Type")) { post.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); 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 fdbe511e52..0d46249390 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 @@ -31,9 +31,10 @@ import com.ning.http.client.cookie.CookieDecoder; import com.ning.http.client.uri.UriComponents; import com.ning.http.util.AsyncHttpProviderUtils; +import com.ning.http.util.StandardCharsets; public class ApacheResponse implements Response { - private final static String DEFAULT_CHARSET = "ISO-8859-1"; + private final static String DEFAULT_CHARSET = StandardCharsets.ISO_8859_1.name(); private final UriComponents uri; private final List 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 055a63a9aa..65a7a59440 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 @@ -545,7 +545,7 @@ private void configure(UriComponents uri, HttpURLConnection urlConnection, Reque if ("POST".equals(reqType) || "PUT".equals(reqType)) { urlConnection.setRequestProperty("Content-Length", "0"); urlConnection.setDoOutput(true); - String bodyCharset = request.getBodyEncoding() == null ? DEFAULT_CHARSET : request.getBodyEncoding(); + String bodyCharset = request.getBodyEncoding() == null ? DEFAULT_CHARSET.name() : request.getBodyEncoding(); if (cachedBytes != null) { urlConnection.setRequestProperty("Content-Length", String.valueOf(cachedBytesLenght)); 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 d2c09aa5bd..c876cb6dbd 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 @@ -33,10 +33,11 @@ import com.ning.http.client.cookie.CookieDecoder; import com.ning.http.client.uri.UriComponents; import com.ning.http.util.AsyncHttpProviderUtils; +import com.ning.http.util.StandardCharsets; public class JDKResponse implements Response { - private final static String DEFAULT_CHARSET = "ISO-8859-1"; + private final static String DEFAULT_CHARSET = StandardCharsets.ISO_8859_1.name(); private final UriComponents uri; private final List 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 dda5e598e3..619b4c2514 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 @@ -30,6 +30,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; @@ -697,7 +698,7 @@ private static HttpRequest construct(AsyncHttpClientConfig config, Request reque nettyRequestHeaders.set(HttpHeaders.Names.COOKIE, CookieEncoder.encode(request.getCookies())); } - String bodyCharset = request.getBodyEncoding() == null ? DEFAULT_CHARSET : request.getBodyEncoding(); + Charset bodyCharset = request.getBodyEncoding() == null ? DEFAULT_CHARSET : Charset.forName(request.getBodyEncoding()); // We already have processed the body. if (buffer != null && buffer.writerIndex() != 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 9ce67470c2..6a5337c104 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 @@ -39,12 +39,13 @@ import com.ning.http.client.cookie.CookieDecoder; import com.ning.http.client.uri.UriComponents; import com.ning.http.util.AsyncHttpProviderUtils; +import com.ning.http.util.StandardCharsets; /** * Wrapper around the {@link com.ning.http.client.Response} API. */ public class NettyResponse implements Response { - private final static Charset DEFAULT_CHARSET = Charset.forName("ISO-8859-1"); + private final static Charset DEFAULT_CHARSET = StandardCharsets.ISO_8859_1; private final List bodyParts; private final 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 f015963bdb..d86125078c 100644 --- a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java +++ b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java @@ -35,6 +35,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; +import java.nio.charset.Charset; import java.util.List; /** @@ -44,7 +45,7 @@ */ public class AsyncHttpProviderUtils { - public final static String DEFAULT_CHARSET = "ISO-8859-1"; + public final static Charset DEFAULT_CHARSET = StandardCharsets.ISO_8859_1; static final byte[] EMPTY_BYTE_ARRAY = "".getBytes(); diff --git a/src/test/java/com/ning/http/client/RealmTest.java b/src/test/java/com/ning/http/client/RealmTest.java index df2d4f75d4..5d6e319b27 100644 --- a/src/test/java/com/ning/http/client/RealmTest.java +++ b/src/test/java/com/ning/http/client/RealmTest.java @@ -15,6 +15,7 @@ import com.ning.http.client.Realm.AuthScheme; import com.ning.http.client.Realm.RealmBuilder; import com.ning.http.client.uri.UriComponents; +import com.ning.http.util.StandardCharsets; import org.testng.Assert; @@ -110,7 +111,7 @@ public void testStrongDigest() { private String getMd5(String what) { try { MessageDigest md = MessageDigest.getInstance("MD5"); - md.update(what.getBytes("ISO-8859-1")); + md.update(what.getBytes(StandardCharsets.ISO_8859_1)); byte[] hash = md.digest(); BigInteger bi = new BigInteger(1, hash); String result = bi.toString(16); 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 0dabb230cd..b14cef7f7e 100755 --- a/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java +++ b/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java @@ -60,6 +60,7 @@ import com.ning.http.client.Response; import com.ning.http.client.StringPart; import com.ning.http.client.cookie.Cookie; +import com.ning.http.util.StandardCharsets; public abstract class AsyncProvidersBasicTest extends AbstractBasicTest { private static final String UTF_8 = "text/html;charset=UTF-8"; @@ -535,7 +536,7 @@ public void asyncDoPostBodyIsoTest() throws Throwable { 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")); + assertEquals(r.getResponseBody().getBytes(StandardCharsets.ISO_8859_1), "\u017D\u017D\u017D\u017D\u017D\u017D".getBytes(StandardCharsets.ISO_8859_1)); } finally { 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 6e647f6336..861c58bd66 100644 --- a/src/test/java/com/ning/http/client/async/MultipartUploadTest.java +++ b/src/test/java/com/ning/http/client/async/MultipartUploadTest.java @@ -20,6 +20,8 @@ import com.ning.http.client.Response; import com.ning.http.client.StringPart; import com.ning.http.util.AsyncHttpProviderUtils; +import com.ning.http.util.StandardCharsets; + import org.apache.commons.fileupload.FileItemIterator; import org.apache.commons.fileupload.FileItemStream; import org.apache.commons.fileupload.FileUploadException; @@ -40,6 +42,7 @@ import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; + import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; @@ -221,11 +224,11 @@ public void testSendingSmallFilesAndByteArray() { builder.addBodyPart(new StringPart("Name", "Dominic")); builder.addBodyPart(new FilePart("file3", testResource3File, "text/plain", "UTF-8")); - builder.addBodyPart(new StringPart("Age", "3", AsyncHttpProviderUtils.DEFAULT_CHARSET)); - builder.addBodyPart(new StringPart("Height", "shrimplike", AsyncHttpProviderUtils.DEFAULT_CHARSET)); - builder.addBodyPart(new StringPart("Hair", "ridiculous", AsyncHttpProviderUtils.DEFAULT_CHARSET)); + builder.addBodyPart(new StringPart("Age", "3", AsyncHttpProviderUtils.DEFAULT_CHARSET.name())); + builder.addBodyPart(new StringPart("Height", "shrimplike", AsyncHttpProviderUtils.DEFAULT_CHARSET.name())); + builder.addBodyPart(new StringPart("Hair", "ridiculous", AsyncHttpProviderUtils.DEFAULT_CHARSET.name())); - builder.addBodyPart(new ByteArrayPart("file4", "bytearray.txt", expectedContents.getBytes("UTF-8"), "text/plain", "UTF-8")); + builder.addBodyPart(new ByteArrayPart("file4", "bytearray.txt", expectedContents.getBytes(StandardCharsets.UTF_8), "text/plain", StandardCharsets.UTF_8.name())); com.ning.http.client.Request r = builder.build(); From b86ca63c239e726cccb5f7045dba6886cd108d8f Mon Sep 17 00:00:00 2001 From: oleksiys Date: Mon, 21 Jul 2014 18:28:42 -0700 Subject: [PATCH 453/701] [1.9.x] + fix issue #637 https://github.com/AsyncHttpClient/async-http-client/issues/637 "AHC with Grizzly provider not handling SSL Connect/tunnelling with Proxy" --- .../grizzly/GrizzlyAsyncHttpProvider.java | 16 ++++++++++++++++ 1 file changed, 16 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 19ed204317..7aec7a91e0 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 @@ -1440,6 +1440,22 @@ protected void onHttpHeadersParsed(HttpHeader httpHeader, } + @Override + protected boolean onHttpHeaderParsed(final HttpHeader httpHeader, + final Buffer buffer, final FilterChainContext ctx) { + super.onHttpHeaderParsed(httpHeader, buffer, ctx); + + final HttpRequestPacket request = ((HttpResponsePacket) httpHeader).getRequest(); + if (Method.CONNECT.equals(request.getMethod())) { + // finish request/response processing, because Grizzly itself + // treats CONNECT traffic as part of request-response processing + // and we don't want it be treated like that + httpHeader.setExpectContent(false); + } + + return false; + } + @SuppressWarnings({"unchecked"}) @Override From 8348ff7f7e6f2aff7e8c65fb5e9aafbde9a309b2 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 22 Jul 2014 10:44:53 +0200 Subject: [PATCH 454/701] Drop JDK5 support and target JDK6, close #639 --- pom.xml | 59 ++++++--------- .../http/client/AsyncCompletionHandler.java | 23 ++---- .../client/AsyncCompletionHandlerBase.java | 8 +- .../com/ning/http/client/ByteArrayPart.java | 5 +- .../java/com/ning/http/client/FilePart.java | 4 +- .../FluentCaseInsensitiveStringsMap.java | 65 ++++------------- .../ning/http/client/FluentStringsMap.java | 65 ++++------------- .../http/client/SimpleAsyncHttpClient.java | 6 -- .../java/com/ning/http/client/StringPart.java | 5 +- .../consumers/AppendableBodyConsumer.java | 10 +-- .../consumers/ByteBufferBodyConsumer.java | 10 +-- .../client/consumers/FileBodyConsumer.java | 20 +---- .../consumers/OutputStreamBodyConsumer.java | 10 +-- .../ResumableRandomAccessFileListener.java | 9 +-- .../client/extra/ThrottleRequestFilter.java | 25 ++----- .../generators/ByteArrayBodyGenerator.java | 8 +- .../client/generators/FileBodyGenerator.java | 12 +-- .../generators/InputStreamBodyGenerator.java | 9 ++- .../listener/TransferCompletionHandler.java | 18 ++--- .../oauth/OAuthSignatureCalculator.java | 6 +- .../apache/ApacheAsyncHttpProvider.java | 28 +++---- .../providers/apache/ApacheResponse.java | 54 +++++--------- .../apache/ApacheResponseBodyPart.java | 9 --- .../apache/ApacheResponseFuture.java | 11 +-- .../grizzly/FeedableBodyGenerator.java | 10 +-- .../grizzly/GrizzlyAsyncHttpProvider.java | 19 ++--- .../GrizzlyAsyncHttpProviderConfig.java | 11 --- .../grizzly/GrizzlyConnectionPool.java | 24 ++---- .../providers/grizzly/GrizzlyResponse.java | 73 +++++-------------- .../grizzly/GrizzlyResponseBodyPart.java | 18 ----- .../grizzly/GrizzlyResponseHeaders.java | 3 - .../grizzly/GrizzlyResponseStatus.java | 18 ----- .../http/client/providers/jdk/JDKFuture.java | 16 +--- .../client/providers/jdk/JDKResponse.java | 52 ++++--------- .../providers/jdk/ResponseBodyPart.java | 9 --- .../netty/NettyAsyncHttpProvider.java | 18 ++--- .../client/providers/netty/NettyResponse.java | 53 +++++--------- .../providers/netty/NettyResponseFuture.java | 36 +++------ .../providers/netty/NettyWebSocket.java | 23 +++--- .../providers/netty/ResponseBodyPart.java | 9 --- .../netty/pool/DefaultChannelPool.java | 18 +---- .../PropertiesBasedResumableProcessor.java | 20 +---- .../resumable/ResumableAsyncHandler.java | 30 +++----- .../webdav/WebDavCompletionHandlerBase.java | 25 ++----- .../http/client/webdav/WebDavResponse.java | 2 +- .../websocket/DefaultWebSocketListener.java | 27 ------- .../websocket/WebSocketUpgradeHandler.java | 21 ------ .../http/client/async/AbstractBasicTest.java | 14 ++-- .../client/async/AsyncProvidersBasicTest.java | 18 ++--- .../client/async/ByteBufferCapacityTest.java | 2 +- .../client/async/HostnameVerifierTest.java | 2 +- .../client/async/PostRedirectGetTest.java | 6 +- .../http/client/async/PostWithQSTest.java | 6 +- .../http/client/async/WebDavBasicTest.java | 7 +- .../websocket/CloseCodeReasonMessageTest.java | 6 +- 55 files changed, 285 insertions(+), 790 deletions(-) diff --git a/pom.xml b/pom.xml index 5a3a81753d..ca87757d98 100644 --- a/pom.xml +++ b/pom.xml @@ -81,13 +81,26 @@ io.netty netty - 3.9.2.Final + ${netty.version} + + + + org.glassfish.grizzly + grizzly-websockets + ${grizzly.version} + true + + + org.glassfish.grizzly + grizzly-http-server + ${grizzly.version} + test org.slf4j slf4j-api - 1.7.5 + 1.7.7 @@ -101,7 +114,7 @@ ch.qos.logback logback-classic - 1.0.13 + 1.1.2 test @@ -257,13 +270,13 @@ org.codehaus.mojo.signature - java15 + java16 1.0 - check-java-1.5-compat + check-java-1.6-compat process-classes check @@ -319,7 +332,7 @@ 2.0.9 - 1.5 + 1.6 @@ -474,32 +487,6 @@ - - grizzly - - [1.6,) - - - asdfasfd/** - asdfasdf/** - asdfasdf - 1.5 - - - - org.glassfish.grizzly - grizzly-websockets - ${grizzly.version} - true - - - org.glassfish.grizzly - grizzly-http-server - ${grizzly.version} - test - - - release-sign-artifacts @@ -588,12 +575,10 @@ http://oss.sonatype.org/content/repositories/snapshots true - com/ning/http/client/providers/grizzly/*.java - com/ning/http/client/async/grizzly/*.java - com.ning.http.client.providers.grizzly + 3.9.2.Final 2.3.16 - 1.5 - 1.5 + 1.6 + 1.6 2.12 diff --git a/src/main/java/com/ning/http/client/AsyncCompletionHandler.java b/src/main/java/com/ning/http/client/AsyncCompletionHandler.java index ebc171d07c..402972cbf7 100644 --- a/src/main/java/com/ning/http/client/AsyncCompletionHandler.java +++ b/src/main/java/com/ning/http/client/AsyncCompletionHandler.java @@ -31,41 +31,31 @@ public abstract class AsyncCompletionHandler implements AsyncHandler, Prog private final Logger log = LoggerFactory.getLogger(AsyncCompletionHandlerBase.class); private final Response.ResponseBuilder builder = new Response.ResponseBuilder(); - /** - * {@inheritDoc} - */ + @Override public STATE onBodyPartReceived(final HttpResponseBodyPart content) throws Exception { builder.accumulate(content); return STATE.CONTINUE; } - /** - * {@inheritDoc} - */ + @Override public STATE onStatusReceived(final HttpResponseStatus status) throws Exception { builder.reset(); builder.accumulate(status); return STATE.CONTINUE; } - /** - * {@inheritDoc} - */ + @Override public STATE onHeadersReceived(final HttpResponseHeaders headers) throws Exception { builder.accumulate(headers); return STATE.CONTINUE; } - /** - * {@inheritDoc} - */ + @Override public final T onCompleted() throws Exception { return onCompleted(builder.build()); } - /** - * {@inheritDoc} - */ + @Override public void onThrowable(Throwable t) { log.debug(t.getMessage(), t); } @@ -88,6 +78,7 @@ public void onThrowable(Throwable t) { * * @return a {@link com.ning.http.client.AsyncHandler.STATE} telling to CONTINUE or ABORT the current processing. */ + @Override public STATE onHeaderWriteCompleted() { return STATE.CONTINUE; } @@ -98,6 +89,7 @@ public STATE onHeaderWriteCompleted() { * * @return a {@link com.ning.http.client.AsyncHandler.STATE} telling to CONTINUE or ABORT the current processing. */ + @Override public STATE onContentWriteCompleted() { return STATE.CONTINUE; } @@ -110,6 +102,7 @@ public STATE onContentWriteCompleted() { * @param total The total number of bytes transferred * @return a {@link com.ning.http.client.AsyncHandler.STATE} telling to CONTINUE or ABORT the current processing. */ + @Override public STATE onContentWriteProgress(long amount, long current, long total) { return STATE.CONTINUE; } diff --git a/src/main/java/com/ning/http/client/AsyncCompletionHandlerBase.java b/src/main/java/com/ning/http/client/AsyncCompletionHandlerBase.java index 434d086e70..e310c5fe43 100644 --- a/src/main/java/com/ning/http/client/AsyncCompletionHandlerBase.java +++ b/src/main/java/com/ning/http/client/AsyncCompletionHandlerBase.java @@ -25,18 +25,12 @@ public class AsyncCompletionHandlerBase extends AsyncCompletionHandler { private final Logger log = LoggerFactory.getLogger(AsyncCompletionHandlerBase.class); - /** - * {@inheritDoc} - */ @Override public Response onCompleted(Response response) throws Exception { return response; } - /** - * {@inheritDoc} - */ - /* @Override */ + @Override public void onThrowable(Throwable t) { log.debug(t.getMessage(), t); } diff --git a/src/main/java/com/ning/http/client/ByteArrayPart.java b/src/main/java/com/ning/http/client/ByteArrayPart.java index 41ae3c5abe..1660accc81 100644 --- a/src/main/java/com/ning/http/client/ByteArrayPart.java +++ b/src/main/java/com/ning/http/client/ByteArrayPart.java @@ -31,10 +31,7 @@ public ByteArrayPart(String name, String fileName, byte[] data, String mimeType, this.charSet = charSet; } - /** - * {@inheritDoc} - */ - /* @Override */ + @Override public String getName() { return name; } diff --git a/src/main/java/com/ning/http/client/FilePart.java b/src/main/java/com/ning/http/client/FilePart.java index c74571ef15..92824799db 100644 --- a/src/main/java/com/ning/http/client/FilePart.java +++ b/src/main/java/com/ning/http/client/FilePart.java @@ -34,9 +34,7 @@ public FilePart(String name, File file, String mimeType, String charSet) { this.charSet = charSet; } - /** - * {@inheritDoc} - */ + @Override public String getName() { return name; } diff --git a/src/main/java/com/ning/http/client/FluentCaseInsensitiveStringsMap.java b/src/main/java/com/ning/http/client/FluentCaseInsensitiveStringsMap.java index 46671f21d4..bc6e6c715f 100644 --- a/src/main/java/com/ning/http/client/FluentCaseInsensitiveStringsMap.java +++ b/src/main/java/com/ning/http/client/FluentCaseInsensitiveStringsMap.java @@ -248,10 +248,7 @@ public FluentCaseInsensitiveStringsMap replaceAll(Map put(String key, List value) { if (key == null) { throw new NullPointerException("Null keys are not allowed"); @@ -263,10 +260,7 @@ public List put(String key, List value) { return oldValue; } - /** - * {@inheritDoc} - */ - /* @Override */ + @Override public void putAll(Map> values) { replaceAll(values); } @@ -319,10 +313,7 @@ public FluentCaseInsensitiveStringsMap deleteAll(Collection keys) { return this; } - /** - * {@inheritDoc} - */ - /* @Override */ + @Override public List remove(Object key) { if (key == null) { return null; @@ -334,67 +325,43 @@ public List remove(Object key) { } } - /** - * {@inheritDoc} - */ - /* @Override */ + @Override public void clear() { keyLookup.clear(); values.clear(); } - /** - * {@inheritDoc} - */ - /* @Override */ + @Override public Iterator>> iterator() { return Collections.unmodifiableSet(values.entrySet()).iterator(); } - /** - * {@inheritDoc} - */ - /* @Override */ + @Override public Set keySet() { return new LinkedHashSet(keyLookup.values()); } - /** - * {@inheritDoc} - */ - /* @Override */ + @Override public Set>> entrySet() { return values.entrySet(); } - /** - * {@inheritDoc} - */ - /* @Override */ + @Override public int size() { return values.size(); } - /** - * {@inheritDoc} - */ - /* @Override */ + @Override public boolean isEmpty() { return values.isEmpty(); } - /** - * {@inheritDoc} - */ - /* @Override */ + @Override public boolean containsKey(Object key) { return key == null ? false : keyLookup.containsKey(key.toString().toLowerCase(Locale.ENGLISH)); } - /** - * {@inheritDoc} - */ - /* @Override */ + @Override public boolean containsValue(Object value) { return values.containsValue(value); } @@ -444,10 +411,7 @@ public String getJoinedValue(String key, String delimiter) { } } - /** - * {@inheritDoc} - */ - /* @Override */ + @Override public List get(Object key) { if (key == null) { return null; @@ -463,10 +427,7 @@ public List get(Object key) { } } - /** - * {@inheritDoc} - */ - /* @Override */ + @Override public Collection> values() { return values.values(); } diff --git a/src/main/java/com/ning/http/client/FluentStringsMap.java b/src/main/java/com/ning/http/client/FluentStringsMap.java index 0a6bba1b77..3a9a07a9ef 100644 --- a/src/main/java/com/ning/http/client/FluentStringsMap.java +++ b/src/main/java/com/ning/http/client/FluentStringsMap.java @@ -192,10 +192,7 @@ public FluentStringsMap replaceAll(Map put(String key, List value) { if (key == null) { throw new NullPointerException("Null keys are not allowed"); @@ -207,10 +204,7 @@ public List put(String key, List value) { return oldValue; } - /** - * {@inheritDoc} - */ - /* @Override */ + @Override public void putAll(Map> values) { replaceAll(values); } @@ -256,10 +250,7 @@ public FluentStringsMap deleteAll(Collection keys) { return this; } - /** - * {@inheritDoc} - */ - /* @Override */ + @Override public List remove(Object key) { if (key == null) { return null; @@ -271,66 +262,42 @@ public List remove(Object key) { } } - /** - * {@inheritDoc} - */ - /* @Override */ + @Override public void clear() { values.clear(); } - /** - * {@inheritDoc} - */ - /* @Override */ + @Override public Iterator>> iterator() { return Collections.unmodifiableSet(values.entrySet()).iterator(); } - /** - * {@inheritDoc} - */ - /* @Override */ + @Override public Set keySet() { return Collections.unmodifiableSet(values.keySet()); } - /** - * {@inheritDoc} - */ - /* @Override */ + @Override public Set>> entrySet() { return values.entrySet(); } - /** - * {@inheritDoc} - */ - /* @Override */ + @Override public int size() { return values.size(); } - /** - * {@inheritDoc} - */ - /* @Override */ + @Override public boolean isEmpty() { return values.isEmpty(); } - /** - * {@inheritDoc} - */ - /* @Override */ + @Override public boolean containsKey(Object key) { return key == null ? false : values.containsKey(key.toString()); } - /** - * {@inheritDoc} - */ - /* @Override */ + @Override public boolean containsValue(Object value) { return values.containsValue(value); } @@ -380,10 +347,7 @@ public String getJoinedValue(String key, String delimiter) { } } - /** - * {@inheritDoc} - */ - /* @Override */ + @Override public List get(Object key) { if (key == null) { return null; @@ -392,10 +356,7 @@ public List get(Object key) { return values.get(key.toString()); } - /** - * {@inheritDoc} - */ - /* @Override */ + @Override public Collection> values() { return values.values(); } diff --git a/src/main/java/com/ning/http/client/SimpleAsyncHttpClient.java b/src/main/java/com/ning/http/client/SimpleAsyncHttpClient.java index 19986c6974..98c65b3a90 100644 --- a/src/main/java/com/ning/http/client/SimpleAsyncHttpClient.java +++ b/src/main/java/com/ning/http/client/SimpleAsyncHttpClient.java @@ -740,9 +740,6 @@ public void onThrowable(Throwable t) { } } - /** - * {@inheritDoc} - */ public STATE onBodyPartReceived(final HttpResponseBodyPart content) throws Exception { fireReceived(content); if (omitBody) { @@ -758,9 +755,6 @@ public STATE onBodyPartReceived(final HttpResponseBodyPart content) throws Excep } - /** - * {@inheritDoc} - */ @Override public Response onCompleted(Response response) throws Exception { fireCompleted(response); diff --git a/src/main/java/com/ning/http/client/StringPart.java b/src/main/java/com/ning/http/client/StringPart.java index 120d08cc17..54d9672b90 100644 --- a/src/main/java/com/ning/http/client/StringPart.java +++ b/src/main/java/com/ning/http/client/StringPart.java @@ -38,10 +38,7 @@ public StringPart(String name, String value) { this.charset = StandardCharsets.UTF_8.name(); } - /** - * {@inheritDoc} - */ - /* @Override */ + @Override public String getName() { return name; } 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 6522a744db..25c6c41bd7 100644 --- a/src/main/java/com/ning/http/client/consumers/AppendableBodyConsumer.java +++ b/src/main/java/com/ning/http/client/consumers/AppendableBodyConsumer.java @@ -37,10 +37,7 @@ public AppendableBodyConsumer(Appendable appendable) { this.encoding = StandardCharsets.UTF_8.name(); } - /** - * {@inheritDoc} - */ - /* @Override */ + @Override public void consume(ByteBuffer byteBuffer) throws IOException { appendable.append(new String(byteBuffer.array(), byteBuffer.arrayOffset() + byteBuffer.position(), @@ -48,10 +45,7 @@ public void consume(ByteBuffer byteBuffer) throws IOException { encoding)); } - /** - * {@inheritDoc} - */ - /* @Override */ + @Override public void close() throws IOException { if (appendable instanceof Closeable) { Closeable.class.cast(appendable).close(); diff --git a/src/main/java/com/ning/http/client/consumers/ByteBufferBodyConsumer.java b/src/main/java/com/ning/http/client/consumers/ByteBufferBodyConsumer.java index e1d07bbaa4..46975575b5 100644 --- a/src/main/java/com/ning/http/client/consumers/ByteBufferBodyConsumer.java +++ b/src/main/java/com/ning/http/client/consumers/ByteBufferBodyConsumer.java @@ -28,18 +28,12 @@ public ByteBufferBodyConsumer(ByteBuffer byteBuffer) { this.byteBuffer = byteBuffer; } - /** - * {@inheritDoc} - */ - /* @Override */ + @Override public void consume(ByteBuffer byteBuffer) throws IOException { byteBuffer.put(byteBuffer); } - /** - * {@inheritDoc} - */ - /* @Override */ + @Override public void close() throws IOException { byteBuffer.flip(); } 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 02a12d65fd..1eb7e151ae 100644 --- a/src/main/java/com/ning/http/client/consumers/FileBodyConsumer.java +++ b/src/main/java/com/ning/http/client/consumers/FileBodyConsumer.java @@ -29,10 +29,7 @@ public FileBodyConsumer(RandomAccessFile file) { this.file = file; } - /** - * {@inheritDoc} - */ - /* @Override */ + @Override public void consume(ByteBuffer byteBuffer) throws IOException { // TODO: Channel.transferFrom may be a good idea to investigate. file.write(byteBuffer.array(), @@ -40,26 +37,17 @@ public void consume(ByteBuffer byteBuffer) throws IOException { byteBuffer.remaining()); } - /** - * {@inheritDoc} - */ - /* @Override */ + @Override public void close() throws IOException { file.close(); } - /** - * {@inheritDoc} - */ - /* @Override */ + @Override public long getTransferredBytes() throws IOException { return file.length(); } - /** - * {@inheritDoc} - */ - /* @Override */ + @Override public void resume() throws IOException { file.seek(getTransferredBytes()); } 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 9f8c93aec1..7c7a5747ad 100644 --- a/src/main/java/com/ning/http/client/consumers/OutputStreamBodyConsumer.java +++ b/src/main/java/com/ning/http/client/consumers/OutputStreamBodyConsumer.java @@ -29,20 +29,14 @@ public OutputStreamBodyConsumer(OutputStream outputStream) { this.outputStream = outputStream; } - /** - * {@inheritDoc} - */ - /* @Override */ + @Override public void consume(ByteBuffer byteBuffer) throws IOException { outputStream.write(byteBuffer.array(), byteBuffer.arrayOffset() + byteBuffer.position(), byteBuffer.remaining()); } - /** - * {@inheritDoc} - */ - /* @Override */ + @Override public void close() throws IOException { outputStream.close(); } diff --git a/src/main/java/com/ning/http/client/extra/ResumableRandomAccessFileListener.java b/src/main/java/com/ning/http/client/extra/ResumableRandomAccessFileListener.java index 042baf1552..ec68f7ea1b 100644 --- a/src/main/java/com/ning/http/client/extra/ResumableRandomAccessFileListener.java +++ b/src/main/java/com/ning/http/client/extra/ResumableRandomAccessFileListener.java @@ -13,6 +13,7 @@ package com.ning.http.client.extra; import com.ning.http.client.resumable.ResumableListener; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -38,14 +39,13 @@ public ResumableRandomAccessFileListener(RandomAccessFile file) { * @param buffer a {@link ByteBuffer} * @throws IOException */ + @Override public void onBytesReceived(ByteBuffer buffer) throws IOException { file.seek(file.length()); file.write(buffer.array()); } - /** - * {@inheritDoc} - */ + @Override public void onAllBytesReceived() { if (file != null) { try { @@ -56,9 +56,6 @@ public void onAllBytesReceived() { } } - /** - * {@inheritDoc} - */ public long length() { try { return file.length(); diff --git a/src/main/java/com/ning/http/client/extra/ThrottleRequestFilter.java b/src/main/java/com/ning/http/client/extra/ThrottleRequestFilter.java index 1e5674ffd9..2bdb9b6eae 100644 --- a/src/main/java/com/ning/http/client/extra/ThrottleRequestFilter.java +++ b/src/main/java/com/ning/http/client/extra/ThrottleRequestFilter.java @@ -45,10 +45,7 @@ public ThrottleRequestFilter(int maxConnections, int maxWait) { available = new Semaphore(maxConnections, true); } - /** - * {@inheritDoc} - */ - /* @Override */ + @Override public FilterContext filter(FilterContext ctx) throws FilterException { try { @@ -85,9 +82,7 @@ private void complete() { } } - /** - * {@inheritDoc} - */ + @Override public void onThrowable(Throwable t) { try { asyncHandler.onThrowable(t); @@ -96,30 +91,22 @@ public void onThrowable(Throwable t) { } } - /** - * {@inheritDoc} - */ + @Override public STATE onBodyPartReceived(HttpResponseBodyPart bodyPart) throws Exception { return asyncHandler.onBodyPartReceived(bodyPart); } - /** - * {@inheritDoc} - */ + @Override public STATE onStatusReceived(HttpResponseStatus responseStatus) throws Exception { return asyncHandler.onStatusReceived(responseStatus); } - /** - * {@inheritDoc} - */ + @Override public STATE onHeadersReceived(HttpResponseHeaders headers) throws Exception { return asyncHandler.onHeadersReceived(headers); } - /** - * {@inheritDoc} - */ + @Override public T onCompleted() throws Exception { try { return asyncHandler.onCompleted(); diff --git a/src/main/java/com/ning/http/client/generators/ByteArrayBodyGenerator.java b/src/main/java/com/ning/http/client/generators/ByteArrayBodyGenerator.java index c56893d0a1..307404b87b 100644 --- a/src/main/java/com/ning/http/client/generators/ByteArrayBodyGenerator.java +++ b/src/main/java/com/ning/http/client/generators/ByteArrayBodyGenerator.java @@ -33,10 +33,12 @@ protected final class ByteBody implements Body { private boolean eof = false; private int lastPosition = 0; + @Override public long getContentLength() { return bytes.length; } + @Override public long read(ByteBuffer byteBuffer) throws IOException { if (eof) { @@ -55,16 +57,14 @@ public long read(ByteBuffer byteBuffer) throws IOException { } } + @Override public void close() throws IOException { lastPosition = 0; eof = false; } } - /** - * {@inheritDoc} - */ - /* @Override */ + @Override public Body createBody() throws IOException { return new ByteBody(); } diff --git a/src/main/java/com/ning/http/client/generators/FileBodyGenerator.java b/src/main/java/com/ning/http/client/generators/FileBodyGenerator.java index 4c81a7271e..7b8dce4d22 100644 --- a/src/main/java/com/ning/http/client/generators/FileBodyGenerator.java +++ b/src/main/java/com/ning/http/client/generators/FileBodyGenerator.java @@ -48,10 +48,7 @@ public FileBodyGenerator(File file, long regionSeek, long regionLength) { this.regionSeek = regionSeek; } - /** - * {@inheritDoc} - */ - /* @Override */ + @Override public RandomAccessBody createBody() throws IOException { return new FileBody(file, regionSeek, regionLength); @@ -83,15 +80,18 @@ public FileBody(File file, long regionSeek, long regionLength) } } + @Override public long getContentLength() { return length; } + @Override public long read(ByteBuffer buffer) throws IOException { return channel.read(buffer); } + @Override public long transferTo(long position, long count, WritableByteChannel target) throws IOException { if (count > length) { @@ -100,11 +100,11 @@ public long transferTo(long position, long count, WritableByteChannel target) return channel.transferTo(position, count, target); } + @Override public void close() throws IOException { file.close(); } - } - } + 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 799a74615a..94b02ec507 100644 --- a/src/main/java/com/ning/http/client/generators/InputStreamBodyGenerator.java +++ b/src/main/java/com/ning/http/client/generators/InputStreamBodyGenerator.java @@ -15,6 +15,7 @@ import com.ning.http.client.Body; import com.ning.http.client.BodyGenerator; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -47,10 +48,7 @@ public InputStreamBodyGenerator(InputStream inputStream) { } } - /** - * {@inheritDoc} - */ - /* @Override */ + @Override public Body createBody() throws IOException { return new ISBody(); } @@ -60,10 +58,12 @@ protected class ISBody implements Body { private int endDataCount = 0; private byte[] chunk; + @Override public long getContentLength() { return -1; } + @Override public long read(ByteBuffer buffer) throws IOException { // To be safe. @@ -126,6 +126,7 @@ public long read(ByteBuffer buffer) throws IOException { return read; } + @Override public void close() throws IOException { inputStream.close(); } 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 bf1ccf0e59..4ff443bc85 100644 --- a/src/main/java/com/ning/http/client/listener/TransferCompletionHandler.java +++ b/src/main/java/com/ning/http/client/listener/TransferCompletionHandler.java @@ -17,6 +17,7 @@ import com.ning.http.client.HttpResponseBodyPart; import com.ning.http.client.HttpResponseHeaders; import com.ning.http.client.Response; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -116,10 +117,7 @@ public void transferAdapter(TransferAdapter transferAdapter) { this.transferAdapter = transferAdapter; } - /** - * {@inheritDoc} - */ - /* @Override */ + @Override public STATE onHeadersReceived(final HttpResponseHeaders headers) throws Exception { fireOnHeaderReceived(headers.getHeaders()); return super.onHeadersReceived(headers); @@ -141,9 +139,7 @@ public Response onCompleted(Response response) throws Exception { return response; } - /** - * {@inheritDoc} - */ + @Override public STATE onHeaderWriteCompleted() { List list = transferAdapter.getHeaders().get("Content-Length"); if (isNonEmpty(list) && list.get(0) != "") { @@ -154,16 +150,12 @@ public STATE onHeaderWriteCompleted() { return STATE.CONTINUE; } - /** - * {@inheritDoc} - */ + @Override public STATE onContentWriteCompleted() { return STATE.CONTINUE; } - /** - * {@inheritDoc} - */ + @Override public STATE onContentWriteProgress(long amount, long current, long total) { if (bytesTransferred.get() == -1) { return STATE.CONTINUE; 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 e538e6e07b..7058ae927f 100644 --- a/src/main/java/com/ning/http/client/oauth/OAuthSignatureCalculator.java +++ b/src/main/java/com/ning/http/client/oauth/OAuthSignatureCalculator.java @@ -81,8 +81,7 @@ public OAuthSignatureCalculator(ConsumerKey consumerAuth, RequestToken userAuth) random = new Random(System.identityHashCode(this) + System.currentTimeMillis()); } - //@Override // silly 1.5; doesn't allow this for interfaces - + @Override public void calculateAndAddSignature(Request request, RequestBuilderBase requestBuilder) { String nonce = generateNonce(); long timestamp = System.currentTimeMillis() / 1000L; @@ -248,8 +247,7 @@ public String value() { return value; } - //@Override // silly 1.5; doesn't allow this for interfaces - + @Override public int compareTo(Parameter other) { int diff = key.compareTo(other.key); if (diff == 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 8065e15f16..50518dff0b 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 @@ -763,14 +763,18 @@ public Socket createSocket(Socket socket, String s, int i, boolean b) throws IOE } private static class TrustEveryoneTrustManager implements X509TrustManager { + + @Override public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException { // do nothing } + @Override public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException { // do nothing } + @Override public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; } @@ -788,9 +792,7 @@ public void setScheduledFuture(Future scheduledFuture) { this.scheduledFuture = scheduledFuture; } - /** - * @Override - */ + @Override public synchronized boolean cancel(boolean mayInterruptIfRunning) { //cleanup references to allow gc to reclaim memory independently //of this Future lifecycle @@ -798,39 +800,29 @@ public synchronized boolean cancel(boolean mayInterruptIfRunning) { return this.scheduledFuture.cancel(mayInterruptIfRunning); } - /** - * @Override - */ + @Override public Object get() throws InterruptedException, ExecutionException { return this.scheduledFuture.get(); } - /** - * @Override - */ + @Override public Object get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { return this.scheduledFuture.get(timeout, unit); } - /** - * @Override - */ + @Override public boolean isCancelled() { return this.scheduledFuture.isCancelled(); } - /** - * @Override - */ + @Override public boolean isDone() { return this.scheduledFuture.isDone(); } - /** - * @Override - */ + @Override public synchronized void run() { if (this.apacheResponseFuture != null && this.apacheResponseFuture.hasExpired()) { logger.debug("Request Timeout expired for " + this.apacheResponseFuture); 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 0d46249390..c9378c0b82 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 @@ -53,19 +53,17 @@ public ApacheResponse(HttpResponseStatus status, uri = this.status.getUri(); } - /* @Override */ - + @Override public int getStatusCode() { return status.getStatusCode(); } - /* @Override */ - + @Override public String getStatusText() { return status.getStatusText(); } - /* @Override */ + @Override public byte[] getResponseBodyAsBytes() throws IOException { return AsyncHttpProviderUtils.contentToByte(bodyParts); } @@ -74,7 +72,7 @@ public ByteBuffer getResponseBodyAsByteBuffer() throws IOException { return ByteBuffer.wrap(getResponseBodyAsBytes()); } - /* @Override */ + @Override public String getResponseBody() throws IOException { return getResponseBody(DEFAULT_CHARSET); } @@ -83,19 +81,17 @@ public String getResponseBody(String charset) throws IOException { return AsyncHttpProviderUtils.contentToString(bodyParts, computeCharset(charset)); } - /* @Override */ + @Override public InputStream getResponseBodyAsStream() throws IOException { return AsyncHttpProviderUtils.contentToInputStream(bodyParts); } - /* @Override */ - + @Override public String getResponseBodyExcerpt(int maxLength) throws IOException { return getResponseBodyExcerpt(maxLength, DEFAULT_CHARSET); } - /* @Override */ - + @Override public String getResponseBodyExcerpt(int maxLength, String charset) throws IOException { charset = computeCharset(charset); @@ -112,38 +108,32 @@ private String computeCharset(String charset) { return charset != null? charset: DEFAULT_CHARSET; } - /* @Override */ - + @Override public UriComponents getUri() { return uri; } - /* @Override */ - + @Override public String getContentType() { return getHeader("Content-Type"); } - /* @Override */ - + @Override public String getHeader(String name) { return headers != null? headers.getHeaders().getFirstValue(name): null; } - /* @Override */ - + @Override public List getHeaders(String name) { return headers != null? headers.getHeaders().get(name): Collections. emptyList(); } - /* @Override */ - + @Override public FluentCaseInsensitiveStringsMap getHeaders() { return headers != null? headers.getHeaders(): new FluentCaseInsensitiveStringsMap(); } - /* @Override */ - + @Override public boolean isRedirected() { switch (status.getStatusCode()) { case 301: @@ -157,8 +147,7 @@ public boolean isRedirected() { } } - /* @Override */ - + @Override public List getCookies() { if (headers == null) { return Collections.emptyList(); @@ -180,26 +169,17 @@ public List getCookies() { return cookies; } - /** - * {@inheritDoc} - */ - /* @Override */ + @Override public boolean hasResponseStatus() { return bodyParts != null; } - /** - * {@inheritDoc} - */ - /* @Override */ + @Override public boolean hasResponseHeaders() { return headers != null; } - /** - * {@inheritDoc} - */ - /* @Override */ + @Override public boolean hasResponseBody() { return isNonEmpty(bodyParts); } diff --git a/src/main/java/com/ning/http/client/providers/apache/ApacheResponseBodyPart.java b/src/main/java/com/ning/http/client/providers/apache/ApacheResponseBodyPart.java index 395d8e1aeb..3050b35631 100644 --- a/src/main/java/com/ning/http/client/providers/apache/ApacheResponseBodyPart.java +++ b/src/main/java/com/ning/http/client/providers/apache/ApacheResponseBodyPart.java @@ -55,25 +55,16 @@ public ByteBuffer getBodyByteBuffer() { return ByteBuffer.wrap(chunk); } - /** - * {@inheritDoc} - */ @Override public boolean isLast() { return isLast; } - /** - * {@inheritDoc} - */ @Override public void markUnderlyingConnectionAsClosed() { closeConnection = true; } - /** - * {@inheritDoc} - */ @Override public boolean closeUnderlyingConnection() { return closeConnection; 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 f91c5d9f04..e5a7bc7606 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 @@ -17,6 +17,7 @@ import com.ning.http.client.AsyncHandler; import com.ning.http.client.Request; import com.ning.http.client.listenable.AbstractListenableFuture; + import org.apache.commons.httpclient.HttpMethodBase; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -210,20 +211,14 @@ public Request getRequest() { } - /** - * {@inheritDoc} - */ - /* @Override */ + @Override public boolean getAndSetWriteHeaders(boolean writeHeaders) { boolean b = this.writeHeaders; this.writeHeaders = writeHeaders; return b; } - /** - * {@inheritDoc} - */ - /* @Override */ + @Override public boolean getAndSetWriteBody(boolean writeBody) { boolean b = this.writeBody; this.writeBody = writeBody; 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 57e20bf5aa..208cd40b30 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 @@ -82,9 +82,6 @@ public class FeedableBodyGenerator implements BodyGenerator { // ---------------------------------------------- Methods from BodyGenerator - /** - * {@inheritDoc} - */ @Override public Body createBody() throws IOException { return EMPTY_BODY; @@ -320,10 +317,8 @@ protected BaseFeeder(FeedableBodyGenerator feedableBodyGenerator) { // --------------------------------------------- Package Private Methods - /** - * {@inheritDoc} - */ @SuppressWarnings("UnusedDeclaration") + @Override public final synchronized void feed(final Buffer buffer, final boolean last) throws IOException { if (buffer == null) { @@ -511,9 +506,6 @@ public NonBlockingFeeder(final FeedableBodyGenerator feedableBodyGenerator) { // ------------------------------------------------- Methods from Feeder - /** - * {@inheritDoc} - */ @Override public synchronized void flush() throws IOException { final Connection c = feedableBodyGenerator.context.getConnection(); 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 7aec7a91e0..49e9ec34d7 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 @@ -53,12 +53,16 @@ import com.ning.http.multipart.MultipartBody; import com.ning.http.multipart.MultipartRequestEntity; import com.ning.http.util.AsyncHttpProviderUtils; + import static com.ning.http.util.AsyncHttpProviderUtils.getNonEmptyPath; + import com.ning.http.util.AuthenticatorUtils; + import static com.ning.http.util.MiscUtils.isNonEmpty; import com.ning.http.util.ProxyUtils; import com.ning.http.util.SslUtils; + import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; @@ -83,8 +87,10 @@ import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; + import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLContext; + import org.glassfish.grizzly.Buffer; import org.glassfish.grizzly.CloseListener; import org.glassfish.grizzly.CloseType; @@ -148,6 +154,7 @@ 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; + import org.glassfish.grizzly.nio.RoundRobinConnectionDistributor; import org.glassfish.grizzly.threadpool.ThreadPoolConfig; @@ -213,10 +220,8 @@ public GrizzlyAsyncHttpProvider(final AsyncHttpClientConfig clientConfig) { // ------------------------------------------ Methods from AsyncHttpProvider - /** - * {@inheritDoc} - */ @SuppressWarnings({"unchecked"}) + @Override public ListenableFuture execute(final Request request, final AsyncHandler handler) throws IOException { @@ -275,9 +280,7 @@ public void updated(final Connection c) { return future; } - /** - * {@inheritDoc} - */ + @Override public void close() { try { @@ -296,9 +299,7 @@ public void close() { } - /** - * {@inheritDoc} - */ + @Override public Response prepareResponse(HttpResponseStatus status, HttpResponseHeaders headers, List bodyParts) { 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 73a9d6a7cf..24a1ba1598 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 @@ -97,8 +97,6 @@ boolean hasDefaultValue() { // ------------------------------------ Methods from AsyncHttpProviderConfig /** - * {@inheritDoc} - * * @throws IllegalArgumentException if the type of the specified value * does not match the expected type of the specified {@link Property}. */ @@ -127,9 +125,6 @@ public AsyncHttpProviderConfig addProperty(Property name, Object value) { return this; } - /** - * {@inheritDoc} - */ @Override public Object getProperty(Property name) { Object ret = attributes.get(name); @@ -141,9 +136,6 @@ public Object getProperty(Property name) { return ret; } - /** - * {@inheritDoc} - */ @Override public Object removeProperty(Property name) { if (name == null) { @@ -152,9 +144,6 @@ public Object removeProperty(Property name) { return attributes.remove(name); } - /** - * {@inheritDoc} - */ @Override public Set> propertiesSet() { return attributes.entrySet(); diff --git a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyConnectionPool.java b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyConnectionPool.java index 8b83c0f0d5..8ec5791720 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyConnectionPool.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyConnectionPool.java @@ -125,10 +125,7 @@ public GrizzlyConnectionPool(final AsyncHttpClientConfig config) { // -------------------------------------------- Methods from ConnectionsPool - - /** - * {@inheritDoc} - */ + @Override public boolean offer(String uri, Connection connection) { if (isSecure(uri) && !cacheSSLConnections) { @@ -169,10 +166,7 @@ public boolean offer(String uri, Connection connection) { return false; } - - /** - * {@inheritDoc} - */ + @Override public Connection poll(String uri) { if (!cacheSSLConnections && isSecure(uri)) { @@ -213,10 +207,7 @@ public Connection poll(String uri) { } - - /** - * {@inheritDoc} - */ + @Override public boolean removeAll(Connection connection) { if (connection == null || closed.get()) { @@ -235,10 +226,7 @@ public boolean removeAll(Connection connection) { } - - /** - * {@inheritDoc} - */ + @Override public boolean canCacheConnection() { return !(!closed.get() @@ -247,9 +235,7 @@ public boolean canCacheConnection() { } - /** - * {@inheritDoc} - */ + @Override public void destroy() { if (closed.getAndSet(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 863c8a9fe0..19f3fa0cdd 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 @@ -94,9 +94,7 @@ public GrizzlyResponse(final HttpResponseStatus status, // --------------------------------------------------- Methods from Response - /** - * {@inheritDoc} - */ + @Override public int getStatusCode() { return status.getStatusCode(); @@ -104,9 +102,7 @@ public int getStatusCode() { } - /** - * {@inheritDoc} - */ + @Override public String getStatusText() { return status.getStatusText(); @@ -114,9 +110,7 @@ public String getStatusText() { } - /** - * {@inheritDoc} - */ + @Override public InputStream getResponseBodyAsStream() throws IOException { return new BufferInputStream(responseBody); @@ -124,9 +118,7 @@ public InputStream getResponseBodyAsStream() throws IOException { } - /** - * {@inheritDoc} - */ + @Override public String getResponseBodyExcerpt(int maxLength, String charset) throws IOException { final int len = Math.min(responseBody.remaining(), maxLength); @@ -136,9 +128,7 @@ public String getResponseBodyExcerpt(int maxLength, String charset) throws IOExc } - /** - * {@inheritDoc} - */ + @Override public String getResponseBody(String charset) throws IOException { return responseBody.toStringContent(getCharset(charset)); @@ -146,9 +136,7 @@ public String getResponseBody(String charset) throws IOException { } - /** - * {@inheritDoc} - */ + @Override public String getResponseBodyExcerpt(int maxLength) throws IOException { // TODO FIX NULL @@ -157,9 +145,7 @@ public String getResponseBodyExcerpt(int maxLength) throws IOException { } - /** - * {@inheritDoc} - */ + @Override public String getResponseBody() throws IOException { return getResponseBody(null); @@ -167,9 +153,7 @@ public String getResponseBody() throws IOException { } - /** - * {@inheritDoc} - */ + @Override public byte[] getResponseBodyAsBytes() throws IOException { final byte[] responseBodyBytes = new byte[responseBody.remaining()]; final int origPos = responseBody.position(); @@ -178,6 +162,7 @@ public byte[] getResponseBodyAsBytes() throws IOException { return responseBodyBytes; } + @Override public ByteBuffer getResponseBodyAsByteBuffer() throws IOException { return responseBody.toByteBuffer(); } @@ -193,9 +178,7 @@ private Buffer getResponseBodyAsBuffer() { } - /** - * {@inheritDoc} - */ + @Override public UriComponents getUri() { return status.getUri(); @@ -203,9 +186,7 @@ public UriComponents getUri() { } - /** - * {@inheritDoc} - */ + @Override public String getContentType() { return headers.getHeaders().getFirstValue("Content-Type"); @@ -213,9 +194,7 @@ public String getContentType() { } - /** - * {@inheritDoc} - */ + @Override public String getHeader(String name) { return headers.getHeaders().getFirstValue(name); @@ -223,9 +202,7 @@ public String getHeader(String name) { } - /** - * {@inheritDoc} - */ + @Override public List getHeaders(String name) { return headers.getHeaders().get(name); @@ -233,9 +210,7 @@ public List getHeaders(String name) { } - /** - * {@inheritDoc} - */ + @Override public FluentCaseInsensitiveStringsMap getHeaders() { return headers.getHeaders(); @@ -243,9 +218,7 @@ public FluentCaseInsensitiveStringsMap getHeaders() { } - /** - * {@inheritDoc} - */ + @Override public boolean isRedirected() { switch (status.getStatusCode()) { case 301: @@ -260,9 +233,7 @@ public boolean isRedirected() { } - /** - * {@inheritDoc} - */ + @Override public List getCookies() { if (headers == null) { @@ -288,25 +259,19 @@ public List getCookies() { } - /** - * {@inheritDoc} - */ + @Override public boolean hasResponseStatus() { return (status != null); } - /** - * {@inheritDoc} - */ + @Override public boolean hasResponseHeaders() { return headers != null && !headers.getHeaders().isEmpty(); } - /** - * {@inheritDoc} - */ + @Override public boolean hasResponseBody() { return isNonEmpty(bodyParts); } diff --git a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponseBodyPart.java b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponseBodyPart.java index d269f20a53..6fe3937ef7 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponseBodyPart.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponseBodyPart.java @@ -60,9 +60,6 @@ public GrizzlyResponseBodyPart(final HttpContent content, // --------------------------------------- Methods from HttpResponseBodyPart - /** - * {@inheritDoc} - */ @Override public byte[] getBodyPartBytes() { @@ -82,9 +79,6 @@ public byte[] getBodyPartBytes() { } - /** - * {@inheritDoc} - */ @Override public int writeTo(OutputStream outputStream) throws IOException { @@ -95,9 +89,6 @@ public int writeTo(OutputStream outputStream) throws IOException { } - /** - * {@inheritDoc} - */ @Override public ByteBuffer getBodyByteBuffer() { @@ -105,25 +96,16 @@ public ByteBuffer getBodyByteBuffer() { } - /** - * {@inheritDoc} - */ @Override public boolean isLast() { return content.isLast(); } - /** - * {@inheritDoc} - */ @Override public void markUnderlyingConnectionAsClosed() { markConnectionAsDoNotCache(connection); } - /** - * {@inheritDoc} - */ @Override public boolean closeUnderlyingConnection() { return !isConnectionCacheable(connection); diff --git a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponseHeaders.java b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponseHeaders.java index 9720a78964..7027573547 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponseHeaders.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponseHeaders.java @@ -51,9 +51,6 @@ public GrizzlyResponseHeaders(final HttpResponsePacket response, // ---------------------------------------- Methods from HttpResponseHeaders - /** - * {@inheritDoc} - */ @Override public FluentCaseInsensitiveStringsMap getHeaders() { if (!initialized) { diff --git a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponseStatus.java b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponseStatus.java index c6f4d747f8..8676cd1f0b 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponseStatus.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponseStatus.java @@ -47,9 +47,6 @@ public GrizzlyResponseStatus(final HttpResponsePacket response, // ----------------------------------------- Methods from HttpResponseStatus - /** - * {@inheritDoc} - */ @Override public int getStatusCode() { @@ -58,9 +55,6 @@ public int getStatusCode() { } - /** - * {@inheritDoc} - */ @Override public String getStatusText() { @@ -69,9 +63,6 @@ public String getStatusText() { } - /** - * {@inheritDoc} - */ @Override public String getProtocolName() { @@ -80,9 +71,6 @@ public String getProtocolName() { } - /** - * {@inheritDoc} - */ @Override public int getProtocolMajorVersion() { @@ -91,9 +79,6 @@ public int getProtocolMajorVersion() { } - /** - * {@inheritDoc} - */ @Override public int getProtocolMinorVersion() { @@ -102,9 +87,6 @@ public int getProtocolMinorVersion() { } - /** - * {@inheritDoc} - */ @Override public String getProtocolText() { return response.getProtocolString(); 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 9a45e2faab..3e7d808a5f 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 @@ -16,6 +16,7 @@ import com.ning.http.client.AsyncHandler; import com.ning.http.client.listenable.AbstractListenableFuture; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -153,28 +154,19 @@ public boolean hasExpired() { return responseTimeoutInMs != -1 && ((millisTime() - touch.get()) > responseTimeoutInMs); } - /** - * {@inheritDoc} - */ - /* @Override */ + @Override public void touch() { touch.set(millisTime()); } - /** - * {@inheritDoc} - */ - /* @Override */ + @Override public boolean getAndSetWriteHeaders(boolean writeHeaders) { boolean b = this.writeHeaders; this.writeHeaders = writeHeaders; return b; } - /** - * {@inheritDoc} - */ - /* @Override */ + @Override public boolean getAndSetWriteBody(boolean writeBody) { boolean b = this.writeBody; this.writeBody = writeBody; 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 c876cb6dbd..8cca8c09e9 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 @@ -58,25 +58,22 @@ public JDKResponse(HttpResponseStatus status, uri = this.status.getUri(); } - /* @Override */ - + @Override public int getStatusCode() { return status.getStatusCode(); } - /* @Override */ - + @Override public String getStatusText() { return status.getStatusText(); } - /* @Override */ - + @Override public String getResponseBody() throws IOException { return getResponseBody(DEFAULT_CHARSET); } - /* @Override */ + @Override public byte[] getResponseBodyAsBytes() throws IOException { return AsyncHttpProviderUtils.contentToByte(bodyParts); } @@ -93,7 +90,7 @@ public String getResponseBody(String charset) throws IOException { return content; } - /* @Override */ + @Override public InputStream getResponseBodyAsStream() throws IOException { if (contentComputed.get()) { return new ByteArrayInputStream(content.getBytes(DEFAULT_CHARSET)); @@ -102,8 +99,7 @@ public InputStream getResponseBodyAsStream() throws IOException { return AsyncHttpProviderUtils.contentToInputStream(bodyParts); } - /* @Override */ - + @Override public String getResponseBodyExcerpt(int maxLength) throws IOException { return getResponseBodyExcerpt(maxLength, DEFAULT_CHARSET); } @@ -127,38 +123,32 @@ private String computeCharset(String charset) { return charset != null? charset: DEFAULT_CHARSET; } - /* @Override */ - + @Override public UriComponents getUri() { return uri; } - /* @Override */ - + @Override public String getContentType() { return getHeader("Content-Type"); } - /* @Override */ - + @Override public String getHeader(String name) { return headers != null? headers.getHeaders().getFirstValue(name): null; } - /* @Override */ - + @Override public List getHeaders(String name) { return headers != null? headers.getHeaders().get(name): Collections. emptyList(); } - /* @Override */ - + @Override public FluentCaseInsensitiveStringsMap getHeaders() { return headers != null? headers.getHeaders(): new FluentCaseInsensitiveStringsMap(); } - /* @Override */ - + @Override public boolean isRedirected() { switch (status.getStatusCode()) { case 301: @@ -172,8 +162,7 @@ public boolean isRedirected() { } } - /* @Override */ - + @Override public List getCookies() { if (headers == null) { return Collections.emptyList(); @@ -194,26 +183,17 @@ public List getCookies() { return cookies; } - /** - * {@inheritDoc} - */ - /* @Override */ + @Override public boolean hasResponseStatus() { return bodyParts != null; } - /** - * {@inheritDoc} - */ - /* @Override */ + @Override public boolean hasResponseHeaders() { return headers != null; } - /** - * {@inheritDoc} - */ - /* @Override */ + @Override public boolean hasResponseBody() { return isNonEmpty(bodyParts); } diff --git a/src/main/java/com/ning/http/client/providers/jdk/ResponseBodyPart.java b/src/main/java/com/ning/http/client/providers/jdk/ResponseBodyPart.java index c0f03de905..7410532529 100644 --- a/src/main/java/com/ning/http/client/providers/jdk/ResponseBodyPart.java +++ b/src/main/java/com/ning/http/client/providers/jdk/ResponseBodyPart.java @@ -55,25 +55,16 @@ public ByteBuffer getBodyByteBuffer() { return ByteBuffer.wrap(chunk); } - /** - * {@inheritDoc} - */ @Override public boolean isLast() { return isLast; } - /** - * {@inheritDoc} - */ @Override public void markUnderlyingConnectionAsClosed() { closeConnection = true; } - /** - * {@inheritDoc} - */ @Override public boolean closeUnderlyingConnection() { return closeConnection; 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 619b4c2514..d24a1081c3 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 @@ -766,15 +766,13 @@ public void close() { } } - /* @Override */ - + @Override public Response prepareResponse(final HttpResponseStatus status, final HttpResponseHeaders headers, final List bodyParts) { return new NettyResponse(status, headers, bodyParts); } - /* @Override */ - + @Override public ListenableFuture execute(Request request, final AsyncHandler asyncHandler) throws IOException { return doConnect(request, asyncHandler, null, true, false); } @@ -2038,7 +2036,7 @@ private void invokeOnSucces(Channel channel, WebSocketUpgradeHandler h) { } } - // @Override + @Override public void handle(Channel channel, MessageEvent e, final NettyResponseFuture future) throws Exception { WebSocketUpgradeHandler wsUpgradeHandler = (WebSocketUpgradeHandler) future.getAsyncHandler(); @@ -2134,17 +2132,17 @@ public void handle(Channel channel, MessageEvent e, final NettyResponseFuture fu HttpChunk webSocketChunk = new HttpChunk() { private ChannelBuffer content; - // @Override + @Override public boolean isLast() { return false; } - // @Override + @Override public ChannelBuffer getContent() { return content; } - // @Override + @Override public void setContent(ChannelBuffer content) { this.content = content; } @@ -2182,7 +2180,7 @@ public void setContent(ChannelBuffer content) { } } - // @Override + @Override public void onError(Channel channel, ExceptionEvent e) { try { Object attachment = Channels.getAttachment(channel); @@ -2204,7 +2202,7 @@ public void onError(Channel channel, ExceptionEvent e) { } } - // @Override + @Override public void onClose(Channel channel, ChannelStateEvent e) { LOGGER.trace("onClose {}", e); 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 6a5337c104..25764d4fe6 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 @@ -61,28 +61,27 @@ public NettyResponse(HttpResponseStatus status, this.bodyParts = bodyParts; } - /* @Override */ - + @Override public int getStatusCode() { return status.getStatusCode(); } - /* @Override */ - + @Override public String getStatusText() { return status.getStatusText(); } - /* @Override */ + @Override public byte[] getResponseBodyAsBytes() throws IOException { return ChannelBufferUtil.channelBuffer2bytes(getResponseBodyAsChannelBuffer()); } + @Override public ByteBuffer getResponseBodyAsByteBuffer() throws IOException { return getResponseBodyAsChannelBuffer().toByteBuffer(); } - /* @Override */ + @Override public String getResponseBody() throws IOException { return getResponseBody(null); } @@ -91,7 +90,7 @@ public String getResponseBody(String charset) throws IOException { return getResponseBodyAsChannelBuffer().toString(computeCharset(charset)); } - /* @Override */ + @Override public InputStream getResponseBodyAsStream() throws IOException { return new ChannelBufferInputStream(getResponseBodyAsChannelBuffer()); } @@ -116,8 +115,7 @@ public ChannelBuffer getResponseBodyAsChannelBuffer() throws IOException { return b; } - /* @Override */ - + @Override public String getResponseBodyExcerpt(int maxLength) throws IOException { return getResponseBodyExcerpt(maxLength, null); } @@ -136,38 +134,32 @@ private Charset computeCharset(String charset) { return charset != null ? Charset.forName(charset) : DEFAULT_CHARSET; } - /* @Override */ - + @Override public UriComponents getUri() { return status.getUri(); } - /* @Override */ - + @Override public String getContentType() { return getHeader("Content-Type"); } - /* @Override */ - + @Override public String getHeader(String name) { return headers != null ? headers.getHeaders().getFirstValue(name) : null; } - /* @Override */ - + @Override public List getHeaders(String name) { return headers != null ? headers.getHeaders().get(name) : Collections. emptyList(); } - /* @Override */ - + @Override public FluentCaseInsensitiveStringsMap getHeaders() { return headers != null ? headers.getHeaders() : new FluentCaseInsensitiveStringsMap(); } - /* @Override */ - + @Override public boolean isRedirected() { switch (status.getStatusCode()) { case 301: @@ -181,8 +173,7 @@ public boolean isRedirected() { } } - /* @Override */ - + @Override public List getCookies() { if (headers == null) { return Collections.emptyList(); @@ -203,28 +194,18 @@ public List getCookies() { return cookies; } - /** - * {@inheritDoc} - */ - /* @Override */ + @Override public boolean hasResponseStatus() { return status != null; } - /** - * {@inheritDoc} - */ - /* @Override */ + @Override public boolean hasResponseHeaders() { return headers != null; } - /** - * {@inheritDoc} - */ - /* @Override */ + @Override public boolean hasResponseBody() { return isNonEmpty(bodyParts); } - } 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 beb2293b73..a9f6255965 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 @@ -109,23 +109,17 @@ public NettyResponseFuture(UriComponents uri,// /** java.util.concurrent.Future **/ /*********************************************/ - /** - * {@inheritDoc} - */ + @Override public boolean isDone() { return isDone.get() || isCancelled.get(); } - /** - * {@inheritDoc} - */ + @Override public boolean isCancelled() { return isCancelled.get(); } - /** - * {@inheritDoc} - */ + @Override public boolean cancel(boolean force) { cancelTimeouts(); @@ -153,17 +147,13 @@ public boolean cancel(boolean force) { return true; } - /** - * {@inheritDoc} - */ + @Override public V get() throws InterruptedException, ExecutionException { latch.await(); return getContent(); } - /** - * {@inheritDoc} - */ + @Override public V get(long l, TimeUnit tu) throws InterruptedException, TimeoutException, ExecutionException { if (!latch.await(l, tu)) throw new TimeoutException(); @@ -204,6 +194,7 @@ V getContent() throws ExecutionException { /*********************************************/ /** com.ning.http.clientListenableFuture **/ /*********************************************/ + @Override public final void done() { cancelTimeouts(); @@ -227,6 +218,7 @@ public final void done() { runListeners(); } + @Override public final void abort(final Throwable t) { cancelTimeouts(); @@ -247,13 +239,12 @@ public final void abort(final Throwable t) { runListeners(); } + @Override public void content(V v) { content.set(v); } - /** - * {@inheritDoc} - */ + @Override public void touch() { touch.set(millisTime()); } @@ -262,18 +253,14 @@ public long getLastTouch() { return touch.get(); } - /** - * {@inheritDoc} - */ + @Override public boolean getAndSetWriteHeaders(boolean writeHeaders) { boolean b = this.writeHeaders; this.writeHeaders = writeHeaders; return b; } - /** - * {@inheritDoc} - */ + @Override public boolean getAndSetWriteBody(boolean writeBody) { boolean b = this.writeBody; this.writeBody = writeBody; @@ -449,5 +436,4 @@ public String toString() { ",\n\ttouch=" + touch + // '}'; } - } 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 84bd9c45ed..b093330dd4 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 @@ -47,52 +47,52 @@ public NettyWebSocket(Channel channel) { this.channel = channel; } - // @Override + @Override public WebSocket sendMessage(byte[] message) { channel.write(new BinaryWebSocketFrame(wrappedBuffer(message))); return this; } - // @Override + @Override public WebSocket stream(byte[] fragment, boolean last) { throw new UnsupportedOperationException("Streaming currently only supported by the Grizzly provider."); } - // @Override + @Override public WebSocket stream(byte[] fragment, int offset, int len, boolean last) { throw new UnsupportedOperationException("Streaming currently only supported by the Grizzly provider."); } - // @Override + @Override public WebSocket sendTextMessage(String message) { channel.write(new TextWebSocketFrame(message)); return this; } - // @Override + @Override public WebSocket streamText(String fragment, boolean last) { throw new UnsupportedOperationException("Streaming currently only supported by the Grizzly provider."); } - // @Override + @Override public WebSocket sendPing(byte[] payload) { channel.write(new PingWebSocketFrame(wrappedBuffer(payload))); return this; } - // @Override + @Override public WebSocket sendPong(byte[] payload) { channel.write(new PongWebSocketFrame(wrappedBuffer(payload))); return this; } - // @Override + @Override public WebSocket addWebSocketListener(WebSocketListener l) { listeners.add(l); return this; } - // @Override + @Override public WebSocket removeWebSocketListener(WebSocketListener l) { listeners.remove(l); return this; @@ -109,12 +109,12 @@ public void setMaxBufferSize(int bufferSize) { maxBufferSize = 8192; } - // @Override + @Override public boolean isOpen() { return channel.isOpen(); } - // @Override + @Override public void close() { if (channel.isOpen()) { onClose(); @@ -123,7 +123,6 @@ public void close() { } } - // @Override public void close(int statusCode, String reason) { onClose(statusCode, reason); listeners.clear(); 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 2820d877b0..0c3bbaf689 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 @@ -86,25 +86,16 @@ public ByteBuffer getBodyByteBuffer() { return ByteBuffer.wrap(getBodyPartBytes()); } - /** - * {@inheritDoc} - */ @Override public boolean isLast() { return isLast; } - /** - * {@inheritDoc} - */ @Override public void markUnderlyingConnectionAsClosed() { closeConnection = true; } - /** - * {@inheritDoc} - */ @Override public boolean closeUnderlyingConnection() { return closeConnection; diff --git a/src/main/java/com/ning/http/client/providers/netty/pool/DefaultChannelPool.java b/src/main/java/com/ning/http/client/providers/netty/pool/DefaultChannelPool.java index 7849092510..b563990698 100644 --- a/src/main/java/com/ning/http/client/providers/netty/pool/DefaultChannelPool.java +++ b/src/main/java/com/ning/http/client/providers/netty/pool/DefaultChannelPool.java @@ -233,9 +233,6 @@ private ConcurrentLinkedQueue getPoolForKey(String key) { return pool; } - /** - * {@inheritDoc} - */ public boolean offer(Channel channel, String poolKey) { if (isClosed.get() || (!sslConnectionPoolEnabled && poolKey.startsWith("https"))) return false; @@ -252,9 +249,6 @@ public boolean offer(Channel channel, String poolKey) { return added; } - /** - * {@inheritDoc} - */ public Channel poll(String poolKey) { if (!sslConnectionPoolEnabled && poolKey.startsWith("https")) return null; @@ -277,24 +271,18 @@ else if (isRemotelyClosed(idleChannel.channel)) { return idleChannel != null ? idleChannel.channel : null; } - /** - * {@inheritDoc} - */ + @Override public boolean removeAll(Channel channel) { ChannelCreation creation = channelId2Creation.remove(channel.getId()); return !isClosed.get() && creation != null && poolsPerKey.get(creation.poolKey).remove(channel); } - /** - * {@inheritDoc} - */ + @Override public boolean isOpen() { return !isClosed.get(); } - /** - * {@inheritDoc} - */ + @Override public void destroy() { if (isClosed.getAndSet(true)) return; 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 7d027b9ac3..bbf600692c 100644 --- a/src/main/java/com/ning/http/client/resumable/PropertiesBasedResumableProcessor.java +++ b/src/main/java/com/ning/http/client/resumable/PropertiesBasedResumableProcessor.java @@ -35,28 +35,19 @@ public class PropertiesBasedResumableProcessor implements ResumableAsyncHandler. private final static String storeName = "ResumableAsyncHandler.properties"; private final ConcurrentHashMap properties = new ConcurrentHashMap(); - /** - * {@inheritDoc} - */ - /* @Override */ + @Override public void put(String url, long transferredBytes) { properties.put(url, transferredBytes); } - /** - * {@inheritDoc} - */ - /* @Override */ + @Override public void remove(String uri) { if (uri != null) { properties.remove(uri); } } - /** - * {@inheritDoc} - */ - /* @Override */ + @Override public void save(Map map) { log.debug("Saving current download state {}", properties.toString()); FileOutputStream os = null; @@ -95,10 +86,7 @@ private static String append(Map.Entry e) { return new StringBuilder(e.getKey()).append("=").append(e.getValue()).append("\n").toString(); } - /** - * {@inheritDoc} - */ - /* @Override */ + @Override public Map load() { Scanner scan = null; try { 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 a788e3b346..1f34c04e4e 100644 --- a/src/main/java/com/ning/http/client/resumable/ResumableAsyncHandler.java +++ b/src/main/java/com/ning/http/client/resumable/ResumableAsyncHandler.java @@ -20,6 +20,7 @@ import com.ning.http.client.RequestBuilder; import com.ning.http.client.Response.ResponseBuilder; import com.ning.http.client.listener.TransferCompletionHandler; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -97,10 +98,7 @@ public ResumableAsyncHandler(ResumableProcessor resumableProcessor, boolean accu this(0, resumableProcessor, null, accumulateBody); } - /** - * {@inheritDoc} - */ - /* @Override */ + @Override public AsyncHandler.STATE onStatusReceived(final HttpResponseStatus status) throws Exception { responseBuilder.accumulate(status); if (status.getStatusCode() == 200 || status.getStatusCode() == 206) { @@ -116,10 +114,7 @@ public AsyncHandler.STATE onStatusReceived(final HttpResponseStatus status) thro return AsyncHandler.STATE.CONTINUE; } - /** - * {@inheritDoc} - */ - /* @Override */ + @Override public void onThrowable(Throwable t) { if (decoratedAsyncHandler != null) { decoratedAsyncHandler.onThrowable(t); @@ -128,10 +123,7 @@ public void onThrowable(Throwable t) { } } - /** - * {@inheritDoc} - */ - /* @Override */ + @Override public AsyncHandler.STATE onBodyPartReceived(HttpResponseBodyPart bodyPart) throws Exception { if (accumulateBody) { @@ -155,10 +147,7 @@ public AsyncHandler.STATE onBodyPartReceived(HttpResponseBodyPart bodyPart) thro return state; } - /** - * {@inheritDoc} - */ - /* @Override */ + @Override public T onCompleted() throws Exception { resumableProcessor.remove(url); resumableListener.onAllBytesReceived(); @@ -170,10 +159,7 @@ public T onCompleted() throws Exception { return (T) responseBuilder.build(); } - /** - * {@inheritDoc} - */ - /* @Override */ + @Override public AsyncHandler.STATE onHeadersReceived(HttpResponseHeaders headers) throws Exception { responseBuilder.accumulate(headers); String contentLengthHeader = headers.getHeaders().getFirstValue("Content-Length"); @@ -283,15 +269,19 @@ public static interface ResumableProcessor { private static class NULLResumableHandler implements ResumableProcessor { + @Override public void put(String url, long transferredBytes) { } + @Override public void remove(String uri) { } + @Override public void save(Map map) { } + @Override public Map load() { return new HashMap(); } 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 dc7981190b..809e7ba4ad 100644 --- a/src/main/java/com/ning/http/client/webdav/WebDavCompletionHandlerBase.java +++ b/src/main/java/com/ning/http/client/webdav/WebDavCompletionHandlerBase.java @@ -48,37 +48,25 @@ public abstract class WebDavCompletionHandlerBase implements AsyncHandler private HttpResponseStatus status; private HttpResponseHeaders headers; - /** - * {@inheritDoc} - */ - /* @Override */ + @Override public final STATE onBodyPartReceived(final HttpResponseBodyPart content) throws Exception { bodies.add(content); return STATE.CONTINUE; } - /** - * {@inheritDoc} - */ - /* @Override */ + @Override public final STATE onStatusReceived(final HttpResponseStatus status) throws Exception { this.status = status; return STATE.CONTINUE; } - /** - * {@inheritDoc} - */ - /* @Override */ + @Override public final STATE onHeadersReceived(final HttpResponseHeaders headers) throws Exception { this.headers = headers; return STATE.CONTINUE; } - /** - * {@inheritDoc} - */ - /* @Override */ + @Override public final T onCompleted() throws Exception { if (status != null) { Response response = status.provider().prepareResponse(status, headers, bodies); @@ -92,10 +80,7 @@ public final T onCompleted() throws Exception { } } - /** - * {@inheritDoc} - */ - /* @Override */ + @Override public void onThrowable(Throwable t) { logger.debug(t.getMessage(), t); } 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 8f52ef6f2a..bfc14eebe2 100644 --- a/src/main/java/com/ning/http/client/webdav/WebDavResponse.java +++ b/src/main/java/com/ning/http/client/webdav/WebDavResponse.java @@ -45,7 +45,7 @@ public String getStatusText() { return response.getStatusText(); } - /* @Override */ + @Override public byte[] getResponseBodyAsBytes() throws IOException { return response.getResponseBodyAsBytes(); } 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 767b89df33..19797a349a 100644 --- a/src/main/java/com/ning/http/client/websocket/DefaultWebSocketListener.java +++ b/src/main/java/com/ning/http/client/websocket/DefaultWebSocketListener.java @@ -26,16 +26,10 @@ public class DefaultWebSocketListener implements WebSocketByteListener, WebSock // -------------------------------------- Methods from WebSocketByteListener - /** - * {@inheritDoc} - */ @Override public void onMessage(byte[] message) { } - /** - * {@inheritDoc} - */ @Override public void onFragment(byte[] fragment, boolean last) { } @@ -43,9 +37,6 @@ public void onFragment(byte[] fragment, boolean last) { // -------------------------------------- Methods from WebSocketPingListener - /** - * {@inheritDoc} - */ @Override public void onPing(byte[] message) { } @@ -53,9 +44,6 @@ public void onPing(byte[] message) { // -------------------------------------- Methods from WebSocketPongListener - /** - * {@inheritDoc} - */ @Override public void onPong(byte[] message) { } @@ -64,16 +52,10 @@ public void onPong(byte[] message) { // -------------------------------------- Methods from WebSocketTextListener - /** - * {@inheritDoc} - */ @Override public void onMessage(String message) { } - /** - * {@inheritDoc} - */ @Override public void onFragment(String fragment, boolean last) { } @@ -81,25 +63,16 @@ public void onFragment(String fragment, boolean last) { // ------------------------------------------ Methods from WebSocketListener - /** - * {@inheritDoc} - */ @Override public void onOpen(WebSocket websocket) { this.webSocket = websocket; } - /** - * {@inheritDoc} - */ @Override public void onClose(WebSocket websocket) { this.webSocket = null; } - /** - * {@inheritDoc} - */ @Override public void onError(Throwable t) { } 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 2daab0f0cb..e72ce81c46 100644 --- a/src/main/java/com/ning/http/client/websocket/WebSocketUpgradeHandler.java +++ b/src/main/java/com/ning/http/client/websocket/WebSocketUpgradeHandler.java @@ -42,9 +42,6 @@ protected WebSocketUpgradeHandler(Builder b) { maxTextSize = b.maxTextSize; } - /** - * {@inheritDoc} - */ @Override public void onThrowable(Throwable t) { onFailure(t); @@ -58,17 +55,11 @@ public void resetSuccess() { onSuccessCalled.set(false); } - /** - * {@inheritDoc} - */ @Override public STATE onBodyPartReceived(HttpResponseBodyPart bodyPart) throws Exception { return STATE.CONTINUE; } - /** - * {@inheritDoc} - */ @Override public STATE onStatusReceived(HttpResponseStatus responseStatus) throws Exception { status = responseStatus.getStatusCode(); @@ -79,17 +70,11 @@ public STATE onStatusReceived(HttpResponseStatus responseStatus) throws Exceptio } } - /** - * {@inheritDoc} - */ @Override public STATE onHeadersReceived(HttpResponseHeaders headers) throws Exception { return STATE.CONTINUE; } - /** - * {@inheritDoc} - */ @Override public WebSocket onCompleted() throws Exception { @@ -106,9 +91,6 @@ public WebSocket onCompleted() throws Exception { return webSocket; } - /** - * {@inheritDoc} - */ @Override public void onSuccess(WebSocket webSocket) { this.webSocket = webSocket; @@ -119,9 +101,6 @@ public void onSuccess(WebSocket webSocket) { ok.set(true); } - /** - * {@inheritDoc} - */ @Override public void onFailure(Throwable t) { for (WebSocketListener w : l) { diff --git a/src/test/java/com/ning/http/client/async/AbstractBasicTest.java b/src/test/java/com/ning/http/client/async/AbstractBasicTest.java index c2f1a5e236..7fcd64bd2f 100644 --- a/src/test/java/com/ning/http/client/async/AbstractBasicTest.java +++ b/src/test/java/com/ning/http/client/async/AbstractBasicTest.java @@ -56,7 +56,7 @@ public abstract class AbstractBasicTest { public static class EchoHandler extends AbstractHandler { - /* @Override */ + @Override public void handle(String pathInContext, Request request, HttpServletRequest httpRequest, @@ -212,7 +212,7 @@ public Response onCompleted(Response response) throws Exception { return response; } - /* @Override */ + @Override public void onThrowable(Throwable t) { t.printStackTrace(); Assert.fail("Unexpected exception: " + t.getMessage(), t); @@ -223,28 +223,28 @@ public void onThrowable(Throwable t) { public static class AsyncHandlerAdapter implements AsyncHandler { - /* @Override */ + @Override public void onThrowable(Throwable t) { t.printStackTrace(); Assert.fail("Unexpected exception", t); } - /* @Override */ + @Override public STATE onBodyPartReceived(final HttpResponseBodyPart content) throws Exception { return STATE.CONTINUE; } - /* @Override */ + @Override public STATE onStatusReceived(final HttpResponseStatus responseStatus) throws Exception { return STATE.CONTINUE; } - /* @Override */ + @Override public STATE onHeadersReceived(final HttpResponseHeaders headers) throws Exception { return STATE.CONTINUE; } - /* @Override */ + @Override public String onCompleted() throws Exception { return ""; } 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 b14cef7f7e..45e3b1e192 100755 --- a/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java +++ b/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java @@ -78,7 +78,7 @@ public String onCompleted(Response response) throws Exception { return response.getUri().toString(); } - /* @Override */ + @Override public void onThrowable(Throwable t) { t.printStackTrace(); Assert.fail("Unexpected exception: " + t.getMessage(), t); @@ -104,7 +104,7 @@ public String onCompleted(Response response) throws Exception { return response.getUri().toString(); } - /* @Override */ + @Override public void onThrowable(Throwable t) { t.printStackTrace(); Assert.fail("Unexpected exception: " + t.getMessage(), t); @@ -130,7 +130,7 @@ public String onCompleted(Response response) throws Exception { return response.getUri().toString(); } - /* @Override */ + @Override public void onThrowable(Throwable t) { t.printStackTrace(); Assert.fail("Unexpected exception: " + t.getMessage(), t); @@ -1005,7 +1005,7 @@ public void asyncConnectInvalidFuture() throws Throwable { for (int i = 0; i < 20; i++) { try { Response response = client.preparePost(String.format("http://127.0.0.1:%d/", dummyPort)).execute(new AsyncCompletionHandlerAdapter() { - /* @Override */ + @Override public void onThrowable(Throwable t) { count.incrementAndGet(); } @@ -1031,7 +1031,7 @@ public void asyncConnectInvalidPortFuture() throws Throwable { int dummyPort = findFreePort(); try { Response response = client.preparePost(String.format("http://127.0.0.1:%d/", dummyPort)).execute(new AsyncCompletionHandlerAdapter() { - /* @Override */ + @Override public void onThrowable(Throwable t) { t.printStackTrace(); } @@ -1057,7 +1057,7 @@ public void asyncConnectInvalidPort() throws Throwable { try { Response response = client.preparePost(String.format("http://127.0.0.1:%d/", port)).execute(new AsyncCompletionHandlerAdapter() { - /* @Override */ + @Override public void onThrowable(Throwable t) { t.printStackTrace(); } @@ -1079,7 +1079,7 @@ public void asyncConnectInvalidHandlerPort() throws Throwable { int port = findFreePort(); client.prepareGet(String.format("http://127.0.0.1:%d/", port)).execute(new AsyncCompletionHandlerAdapter() { - /* @Override */ + @Override public void onThrowable(Throwable t) { try { assertEquals(t.getClass(), ConnectException.class); @@ -1104,7 +1104,7 @@ public void asyncConnectInvalidHandlerHost() throws Throwable { final CountDownLatch l = new CountDownLatch(1); client.prepareGet("http://null.apache.org:9999/").execute(new AsyncCompletionHandlerAdapter() { - /* @Override */ + @Override public void onThrowable(Throwable t) { if (t != null) { if (t.getClass().equals(ConnectException.class)) { @@ -1548,7 +1548,7 @@ public void idleRequestTimeoutTest() throws Exception { try { client.prepareGet(getTargetUrl()).setHeaders(h).setUrl(getTargetUrl()).execute(new AsyncHandlerAdapter() { - /* @Override */ + @Override public void onThrowable(Throwable t) { // t.printStackTrace(); } 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 1b36abc4e1..244bc9b078 100644 --- a/src/test/java/com/ning/http/client/async/ByteBufferCapacityTest.java +++ b/src/test/java/com/ning/http/client/async/ByteBufferCapacityTest.java @@ -86,7 +86,7 @@ public void basicByteBufferTest() throws Throwable { try { Response response = client.preparePut(getTargetUrl()).setBody(largeFile).execute(new AsyncCompletionHandlerAdapter() { - /* @Override */ + @Override public STATE onBodyPartReceived(final HttpResponseBodyPart content) throws Exception { byteReceived.addAndGet(content.getBodyByteBuffer().capacity()); return super.onBodyPartReceived(content); 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 6ee99cb0d8..f27e9063b3 100644 --- a/src/test/java/com/ning/http/client/async/HostnameVerifierTest.java +++ b/src/test/java/com/ning/http/client/async/HostnameVerifierTest.java @@ -53,7 +53,7 @@ public abstract class HostnameVerifierTest extends AbstractBasicTest { public static class EchoHandler extends AbstractHandler { - /* @Override */ + @Override public void handle(String pathInContext, Request r, HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws ServletException, IOException { httpResponse.setContentType("text/html; charset=utf-8"); 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 bfdfa552be..35ca5d2562 100644 --- a/src/test/java/com/ning/http/client/async/PostRedirectGetTest.java +++ b/src/test/java/com/ning/http/client/async/PostRedirectGetTest.java @@ -91,7 +91,7 @@ public Integer onCompleted(Response response) throws Exception { return response.getStatusCode(); } - /* @Override */ + @Override public void onThrowable(Throwable t) { t.printStackTrace(); Assert.fail("Unexpected exception: " + t.getMessage(), t); @@ -125,7 +125,7 @@ public Integer onCompleted(Response response) throws Exception { return response.getStatusCode(); } - /* @Override */ + @Override public void onThrowable(Throwable t) { t.printStackTrace(); Assert.fail("Unexpected exception: " + t.getMessage(), t); @@ -145,7 +145,7 @@ public static class PostRedirectGetHandler extends AbstractHandler { final AtomicInteger counter = new AtomicInteger(); - /* @Override */ + @Override 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); 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 4873e3a446..f8d6a30c7a 100644 --- a/src/test/java/com/ning/http/client/async/PostWithQSTest.java +++ b/src/test/java/com/ning/http/client/async/PostWithQSTest.java @@ -90,7 +90,7 @@ public void postWithNulParamQS() throws IOException, ExecutionException, Timeout try { Future f = client.preparePost("http://127.0.0.1:" + port1 + "/?a=").setBody("abc".getBytes()).execute(new AsyncCompletionHandlerBase() { - /* @Override */ + @Override public STATE onStatusReceived(final HttpResponseStatus status) throws Exception { if (!status.getUri().toString().equals("http://127.0.0.1:" + port1 + "/?a=")) { throw new IOException(status.getUri().toString()); @@ -113,7 +113,7 @@ 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 */ + @Override public STATE onStatusReceived(final HttpResponseStatus status) throws Exception { if (!status.getUri().toString().equals("http://127.0.0.1:" + port1 + "/?a=b&c&d=e")) { throw new IOException("failed to parse the query properly"); @@ -136,7 +136,7 @@ public void postWithEmptyParamsQS() throws IOException, ExecutionException, Time try { Future f = client.preparePost("http://127.0.0.1:" + port1 + "/?a=b&c=&d=e").setBody("abc".getBytes()).execute(new AsyncCompletionHandlerBase() { - /* @Override */ + @Override public STATE onStatusReceived(final HttpResponseStatus status) throws Exception { if (!status.getUri().toString().equals("http://127.0.0.1:" + port1 + "/?a=b&c=&d=e")) { throw new IOException("failed to parse the query properly"); 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 ed4b2c573c..794549dd90 100644 --- a/src/test/java/com/ning/http/client/async/WebDavBasicTest.java +++ b/src/test/java/com/ning/http/client/async/WebDavBasicTest.java @@ -18,6 +18,7 @@ import com.ning.http.client.Response; import com.ning.http.client.webdav.WebDavCompletionHandlerBase; import com.ning.http.client.webdav.WebDavResponse; + import org.apache.catalina.Context; import org.apache.catalina.Engine; import org.apache.catalina.Host; @@ -168,12 +169,8 @@ public void propFindCompletionHandlerWebDavTest() throws InterruptedException, I Request propFindRequest = new RequestBuilder("PROPFIND").setUrl(getTargetUrl()).build(); WebDavResponse webDavResponse = client.executeRequest(propFindRequest, new WebDavCompletionHandlerBase() { - /** - * {@inheritDoc} - */ - /* @Override */ + @Override public void onThrowable(Throwable t) { - t.printStackTrace(); } 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 8b4e618bd4..6b6792b3d5 100644 --- a/src/test/java/com/ning/http/client/websocket/CloseCodeReasonMessageTest.java +++ b/src/test/java/com/ning/http/client/websocket/CloseCodeReasonMessageTest.java @@ -74,11 +74,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) { } @@ -87,7 +87,7 @@ public void onClose(WebSocket websocket, int code, String reason) { latch.countDown(); } - // @Override + @Override public void onError(Throwable t) { t.printStackTrace(); latch.countDown(); From da41854262f84c10486c1cd91cb49025a0620013 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 22 Jul 2014 10:50:42 +0200 Subject: [PATCH 455/701] Extract and rename AsyncCallable into callback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Don’t make it implement Callable --- .../http/client/providers/netty/Callback.java | 29 +++++++++++++ .../netty/NettyAsyncHttpProvider.java | 42 ++++++------------- 2 files changed, 41 insertions(+), 30 deletions(-) create mode 100644 src/main/java/com/ning/http/client/providers/netty/Callback.java diff --git a/src/main/java/com/ning/http/client/providers/netty/Callback.java b/src/main/java/com/ning/http/client/providers/netty/Callback.java new file mode 100644 index 0000000000..4f093d8f74 --- /dev/null +++ b/src/main/java/com/ning/http/client/providers/netty/Callback.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2014 AsyncHttpClient Project. 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.providers.netty; + +public abstract class Callback { + + private final NettyResponseFuture future; + + public Callback(NettyResponseFuture future) { + this.future = future; + } + + abstract public void call() throws Exception; + + public NettyResponseFuture future() { + return future; + } +} 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 d24a1081c3..432d1c1352 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 @@ -36,7 +36,6 @@ import java.util.ArrayList; import java.util.List; import java.util.Map.Entry; -import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.RejectedExecutionException; @@ -974,9 +973,9 @@ public void messageReceived(final ChannelHandlerContext ctx, MessageEvent e) thr if (attachment == DiscardEvent.INSTANCE) { // discard - } else if (attachment instanceof AsyncCallable) { + } else if (attachment instanceof Callback) { Object message = e.getMessage(); - AsyncCallable ac = (AsyncCallable) attachment; + Callback ac = (Callback) attachment; if (message instanceof HttpChunk) { // the AsyncCallable is to be processed on the last chunk if (HttpChunk.class.cast(message).isLast()) @@ -1205,8 +1204,8 @@ public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws Object attachment = Channels.getAttachment(channel); LOGGER.debug("Channel Closed: {} with attachment {}", channel, attachment); - if (attachment instanceof AsyncCallable) { - AsyncCallable ac = (AsyncCallable) attachment; + if (attachment instanceof Callback) { + Callback ac = (Callback) attachment; Channels.setAttachment(channel, ac.future()); ac.call(); @@ -1367,8 +1366,8 @@ public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws LOGGER.debug("Trying to recover from dead Channel: {}", channel); return; } - } else if (attachment instanceof AsyncCallable) { - future = ((AsyncCallable) attachment).future(); + } else if (attachment instanceof Callback) { + future = ((Callback) attachment).future(); } } catch (Throwable t) { cause = t; @@ -1480,21 +1479,6 @@ public void operationProgressed(ChannelFuture cf, long amount, long current, lon } } - private abstract class AsyncCallable implements Callable { - - private final NettyResponseFuture future; - - public AsyncCallable(NettyResponseFuture future) { - this.future = future; - } - - abstract public Object call() throws Exception; - - public NettyResponseFuture future() { - return future; - } - } - public static class ThreadLocalBoolean extends ThreadLocal { private final boolean defaultValue; @@ -1657,7 +1641,7 @@ private boolean exitAfterHandlingRedirect(Channel channel, NettyResponseFuture future, final Channel channel, final boolean keepAlive, + private final Callback newDrainCallable(final NettyResponseFuture future, final Channel channel, final boolean keepAlive, final String poolKey) { - return new AsyncCallable(future) { - public Object call() throws Exception { + return new Callback(future) { + public void call() throws Exception { channelManager.tryToOfferChannelToPool(channel, keepAlive, poolKey); - return null; } }; } @@ -1762,12 +1745,11 @@ private final boolean exitAfterHandling401(// LOGGER.debug("Sending authentication to {}", request.getURI()); final Request nextRequest = requestBuilder.setHeaders(requestHeaders).setRealm(nr).build(); - AsyncCallable ac = new AsyncCallable(future) { - public Object call() throws Exception { + Callback ac = new Callback(future) { + public void call() throws Exception { // not waiting for the channel to be drained, so we might ended up pooling the initial channel and creating a new one drainChannel(channel, future); nextRequest(nextRequest, future); - return null; } }; From bbf45d7ff804fbd82e954ba94701c42907e1a6fd Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 22 Jul 2014 11:14:01 +0200 Subject: [PATCH 456/701] Move 1.9 Netty provider classes to AHC2 structure, close #640 --- pom.xml | 20 +-- .../http/client/providers/netty/Callback.java | 2 + .../client/providers/netty/DiscardEvent.java | 21 +++ .../netty/NettyAsyncHttpProvider.java | 122 ++++-------------- .../netty/NettyAsyncHttpProviderConfig.java | 2 +- .../http/client/providers/netty/Protocol.java | 2 + .../{pool => channel}/ChannelManager.java | 8 +- .../netty/{ => channel}/Channels.java | 4 +- .../netty/{ => channel}/SslInitializer.java | 4 +- .../netty/{ => channel}/pool/ChannelPool.java | 2 +- .../pool/DefaultChannelPool.java | 8 +- .../{ => channel}/pool/NoopChannelPool.java | 2 +- .../{ => future}/NettyResponseFuture.java | 47 +++---- .../{ => future}/StackTraceInspector.java | 2 +- .../{ => request}/NettyConnectListener.java | 10 +- .../netty/request/ProgressListener.java | 103 +++++++++++++++ .../{ => request/body}/BodyChunkedInput.java | 4 +- .../{ => request/body}/BodyFileRegion.java | 4 +- .../timeout/ReadTimeoutTimerTask.java | 4 +- .../timeout/RequestTimeoutTimerTask.java | 4 +- .../timeout/TimeoutTimerTask.java | 4 +- .../{ => request}/timeout/TimeoutsHolder.java | 2 +- .../netty/{ => response}/NettyResponse.java | 3 +- .../{ => response}/ResponseBodyPart.java | 3 +- .../netty/{ => response}/ResponseHeaders.java | 2 +- .../netty/{ => response}/ResponseStatus.java | 2 +- .../netty/{ => util}/ChannelBufferUtil.java | 2 +- .../netty/{ => util}/CleanupChannelGroup.java | 2 +- .../netty/{ => ws}/NettyWebSocket.java | 10 +- .../netty/{ => ws}/WebSocketUtil.java | 2 +- .../async/netty/NettyConnectionPoolTest.java | 2 +- .../netty/NettyAsyncResponseTest.java | 2 + 32 files changed, 237 insertions(+), 174 deletions(-) create mode 100644 src/main/java/com/ning/http/client/providers/netty/DiscardEvent.java rename src/main/java/com/ning/http/client/providers/netty/{pool => channel}/ChannelManager.java (95%) rename src/main/java/com/ning/http/client/providers/netty/{ => channel}/Channels.java (90%) rename src/main/java/com/ning/http/client/providers/netty/{ => channel}/SslInitializer.java (93%) rename src/main/java/com/ning/http/client/providers/netty/{ => channel}/pool/ChannelPool.java (97%) rename src/main/java/com/ning/http/client/providers/netty/{ => channel}/pool/DefaultChannelPool.java (97%) rename src/main/java/com/ning/http/client/providers/netty/{ => channel}/pool/NoopChannelPool.java (95%) rename src/main/java/com/ning/http/client/providers/netty/{ => future}/NettyResponseFuture.java (91%) rename src/main/java/com/ning/http/client/providers/netty/{ => future}/StackTraceInspector.java (97%) rename src/main/java/com/ning/http/client/providers/netty/{ => request}/NettyConnectListener.java (92%) create mode 100644 src/main/java/com/ning/http/client/providers/netty/request/ProgressListener.java rename src/main/java/com/ning/http/client/providers/netty/{ => request/body}/BodyChunkedInput.java (95%) rename src/main/java/com/ning/http/client/providers/netty/{ => request/body}/BodyFileRegion.java (94%) rename src/main/java/com/ning/http/client/providers/netty/{ => request}/timeout/ReadTimeoutTimerTask.java (95%) rename src/main/java/com/ning/http/client/providers/netty/{ => request}/timeout/RequestTimeoutTimerTask.java (92%) rename src/main/java/com/ning/http/client/providers/netty/{ => request}/timeout/TimeoutTimerTask.java (92%) rename src/main/java/com/ning/http/client/providers/netty/{ => request}/timeout/TimeoutsHolder.java (95%) rename src/main/java/com/ning/http/client/providers/netty/{ => response}/NettyResponse.java (98%) rename src/main/java/com/ning/http/client/providers/netty/{ => response}/ResponseBodyPart.java (96%) rename src/main/java/com/ning/http/client/providers/netty/{ => response}/ResponseHeaders.java (97%) rename src/main/java/com/ning/http/client/providers/netty/{ => response}/ResponseStatus.java (97%) rename src/main/java/com/ning/http/client/providers/netty/{ => util}/ChannelBufferUtil.java (95%) rename src/main/java/com/ning/http/client/providers/netty/{ => util}/CleanupChannelGroup.java (98%) rename src/main/java/com/ning/http/client/providers/netty/{ => ws}/NettyWebSocket.java (96%) rename src/main/java/com/ning/http/client/providers/netty/{ => ws}/WebSocketUtil.java (97%) diff --git a/pom.xml b/pom.xml index ca87757d98..824c0acaff 100644 --- a/pom.xml +++ b/pom.xml @@ -243,15 +243,7 @@ maven-compiler-plugin 2.3.2 - ${source.property} - ${target.property} 1024m - - ${compiler.exclude} - - - ${test.compiler.exclude} - @@ -332,7 +324,7 @@ 2.0.9 - 1.6 + ${maven.compiler.source} @@ -389,13 +381,12 @@ 2.8.1 true - 1.6 + ${maven.compiler.source} UTF-8 1g http://java.sun.com/javase/6/docs/api/ - ${javadoc.package.exclude} @@ -449,13 +440,12 @@ 2.8.1 true - 1.6 + ${maven.compiler.source} UTF-8 1g http://java.sun.com/javase/6/docs/api/ - ${javadoc.package.exclude} ${sun.boot.class.path} com.google.doclava.Doclava false @@ -577,8 +567,8 @@ true 3.9.2.Final 2.3.16 - 1.6 - 1.6 + 1.6 + 1.6 2.12 diff --git a/src/main/java/com/ning/http/client/providers/netty/Callback.java b/src/main/java/com/ning/http/client/providers/netty/Callback.java index 4f093d8f74..f622c4f824 100644 --- a/src/main/java/com/ning/http/client/providers/netty/Callback.java +++ b/src/main/java/com/ning/http/client/providers/netty/Callback.java @@ -13,6 +13,8 @@ */ package com.ning.http.client.providers.netty; +import com.ning.http.client.providers.netty.future.NettyResponseFuture; + public abstract class Callback { private final NettyResponseFuture future; diff --git a/src/main/java/com/ning/http/client/providers/netty/DiscardEvent.java b/src/main/java/com/ning/http/client/providers/netty/DiscardEvent.java new file mode 100644 index 0000000000..47f23efd33 --- /dev/null +++ b/src/main/java/com/ning/http/client/providers/netty/DiscardEvent.java @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2014 AsyncHttpClient Project. 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.providers.netty; + +/** + * Simple marker for stopping publishing bytes + */ +public enum DiscardEvent { + INSTANCE +} 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 432d1c1352..4e9afdc422 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 @@ -49,7 +49,6 @@ import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFuture; -import org.jboss.netty.channel.ChannelFutureProgressListener; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipelineFactory; @@ -102,7 +101,6 @@ import com.ning.http.client.HttpResponseStatus; import com.ning.http.client.ListenableFuture; import com.ning.http.client.MaxRedirectException; -import com.ning.http.client.ProgressAsyncHandler; import com.ning.http.client.ProxyServer; import com.ning.http.client.RandomAccessBody; import com.ning.http.client.Realm; @@ -119,14 +117,28 @@ 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.pool.ChannelManager; -import com.ning.http.client.providers.netty.pool.ChannelPool; -import com.ning.http.client.providers.netty.pool.DefaultChannelPool; -import com.ning.http.client.providers.netty.pool.NoopChannelPool; +import com.ning.http.client.providers.netty.channel.ChannelManager; +import com.ning.http.client.providers.netty.channel.Channels; +import com.ning.http.client.providers.netty.channel.SslInitializer; +import com.ning.http.client.providers.netty.channel.pool.ChannelPool; +import com.ning.http.client.providers.netty.channel.pool.DefaultChannelPool; +import com.ning.http.client.providers.netty.channel.pool.NoopChannelPool; +import com.ning.http.client.providers.netty.future.NettyResponseFuture; +import com.ning.http.client.providers.netty.future.StackTraceInspector; +import com.ning.http.client.providers.netty.request.NettyConnectListener; +import com.ning.http.client.providers.netty.request.ProgressListener; +import com.ning.http.client.providers.netty.request.body.BodyChunkedInput; +import com.ning.http.client.providers.netty.request.body.BodyFileRegion; +import com.ning.http.client.providers.netty.request.timeout.ReadTimeoutTimerTask; +import com.ning.http.client.providers.netty.request.timeout.RequestTimeoutTimerTask; +import com.ning.http.client.providers.netty.request.timeout.TimeoutsHolder; +import com.ning.http.client.providers.netty.response.NettyResponse; +import com.ning.http.client.providers.netty.response.ResponseBodyPart; +import com.ning.http.client.providers.netty.response.ResponseHeaders; +import com.ning.http.client.providers.netty.response.ResponseStatus; import com.ning.http.client.providers.netty.spnego.SpnegoEngine; -import com.ning.http.client.providers.netty.timeout.ReadTimeoutTimerTask; -import com.ning.http.client.providers.netty.timeout.RequestTimeoutTimerTask; -import com.ning.http.client.providers.netty.timeout.TimeoutsHolder; +import com.ning.http.client.providers.netty.ws.NettyWebSocket; +import com.ning.http.client.providers.netty.ws.WebSocketUtil; import com.ning.http.client.uri.UriComponents; import com.ning.http.client.websocket.WebSocketUpgradeHandler; import com.ning.http.multipart.MultipartBody; @@ -139,7 +151,7 @@ public class NettyAsyncHttpProvider extends SimpleChannelUpstreamHandler implements AsyncHttpProvider { - private static final Logger LOGGER = LoggerFactory.getLogger(NettyAsyncHttpProvider.class); + static final Logger LOGGER = LoggerFactory.getLogger(NettyAsyncHttpProvider.class); public static final String GZIP_DEFLATE = HttpHeaders.Values.GZIP + "," + HttpHeaders.Values.DEFLATE; @@ -299,7 +311,7 @@ public ChannelPipeline getPipeline() throws Exception { }); } - SslHandler createSslHandler(String peerHost, int peerPort) throws GeneralSecurityException, IOException { + public SslHandler createSslHandler(String peerHost, int peerPort) throws GeneralSecurityException, IOException { SSLEngine sslEngine = SslUtils.getInstance().createClientSSLEngine(config, peerHost, peerPort); return handshakeTimeoutInMillis > 0 ? new SslHandler(sslEngine, getDefaultBufferPool(), false, nettyTimer, handshakeTimeoutInMillis) : new SslHandler(sslEngine); @@ -347,7 +359,7 @@ private Channel verifyChannelPipeline(Channel channel, String scheme) throws IOE return channel; } - protected final void writeRequest(final Channel channel, final AsyncHttpClientConfig config, final NettyResponseFuture future) { + public final void writeRequest(final Channel channel, final AsyncHttpClientConfig config, final NettyResponseFuture future) { HttpRequest nettyRequest = future.getNettyRequest(); HttpHeaders nettyRequestHeaders = nettyRequest.headers(); @@ -421,7 +433,7 @@ protected final void writeRequest(final Channel channel, final AsyncHttpClie if (future.getAsyncHandler() instanceof AsyncHandlerExtensions) AsyncHandlerExtensions.class.cast(future.getAsyncHandler()).onRequestSent(); - channel.write(nettyRequest).addListener(new ProgressListener(true, future.getAsyncHandler(), future)); + channel.write(nettyRequest).addListener(new ProgressListener(config, true, future.getAsyncHandler(), future)); } catch (Throwable cause) { LOGGER.debug(cause.getMessage(), cause); try { @@ -449,7 +461,7 @@ protected final void writeRequest(final Channel channel, final AsyncHttpClie final FileRegion region = new OptimizedFileRegion(raf, 0, raf.length()); writeFuture = channel.write(region); } - writeFuture.addListener(new ProgressListener(false, future.getAsyncHandler(), future) { + writeFuture.addListener(new ProgressListener(config, false, future.getAsyncHandler(), future) { public void operationComplete(ChannelFuture cf) { try { raf.close(); @@ -479,7 +491,7 @@ public void operationComplete(ChannelFuture cf) { BodyFileRegion bodyFileRegion = new BodyFileRegion((RandomAccessBody) body); writeFuture = channel.write(bodyFileRegion); } - writeFuture.addListener(new ProgressListener(false, future.getAsyncHandler(), future) { + writeFuture.addListener(new ProgressListener(config, false, future.getAsyncHandler(), future) { public void operationComplete(ChannelFuture cf) { try { b.close(); @@ -1235,7 +1247,7 @@ else if (!retry(ctx.getChannel(), future)) } } - protected boolean retry(Channel channel, NettyResponseFuture future) { + public boolean retry(Channel channel, NettyResponseFuture future) { if (isClose()) return false; @@ -1309,12 +1321,6 @@ private final boolean updateBodyAndInterrupt(final NettyResponseFuture future return state; } - // Simple marker for stopping publishing bytes. - - enum DiscardEvent { - INSTANCE - } - @Override public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { Channel channel = ctx.getChannel(); @@ -1407,78 +1413,6 @@ public static NettyResponseFuture newFuture(UriComponents uri, Request re return f; } - private class ProgressListener implements ChannelFutureProgressListener { - - private final boolean notifyHeaders; - private final AsyncHandler asyncHandler; - private final NettyResponseFuture future; - - public ProgressListener(boolean notifyHeaders, AsyncHandler asyncHandler, NettyResponseFuture future) { - this.notifyHeaders = notifyHeaders; - this.asyncHandler = asyncHandler; - this.future = future; - } - - public void operationComplete(ChannelFuture cf) { - // The write operation failed. If the channel was cached, it means it got asynchronously closed. - // Let's retry a second time. - Throwable cause = cf.getCause(); - if (cause != null && future.getState() != NettyResponseFuture.STATE.NEW) { - - if (cause instanceof IllegalStateException) { - LOGGER.debug(cause.getMessage(), cause); - try { - cf.getChannel().close(); - } catch (RuntimeException ex) { - LOGGER.debug(ex.getMessage(), ex); - } - return; - } - - if (cause instanceof ClosedChannelException || StackTraceInspector.abortOnReadOrWriteException(cause)) { - - if (LOGGER.isDebugEnabled()) { - LOGGER.debug(cf.getCause() == null ? "" : cf.getCause().getMessage(), cf.getCause()); - } - - try { - cf.getChannel().close(); - } catch (RuntimeException ex) { - LOGGER.debug(ex.getMessage(), ex); - } - return; - } else { - future.abort(cause); - } - return; - } - 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. - */ - Realm realm = future.getRequest().getRealm() != null ? future.getRequest().getRealm() : NettyAsyncHttpProvider.this.getConfig() - .getRealm(); - boolean startPublishing = future.isInAuth() || realm == null || realm.getUsePreemptiveAuth(); - - if (startPublishing && asyncHandler instanceof ProgressAsyncHandler) { - if (notifyHeaders) { - ProgressAsyncHandler.class.cast(asyncHandler).onHeaderWriteCompleted(); - } else { - ProgressAsyncHandler.class.cast(asyncHandler).onContentWriteCompleted(); - } - } - } - - public void operationProgressed(ChannelFuture cf, long amount, long current, long total) { - future.touch(); - if (asyncHandler instanceof ProgressAsyncHandler) { - ProgressAsyncHandler.class.cast(asyncHandler).onContentWriteProgress(amount, current, total); - } - } - } - public static class ThreadLocalBoolean extends ThreadLocal { private final boolean defaultValue; 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 6c6e1ffa1a..d9a512d2c1 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 @@ -20,7 +20,7 @@ import org.jboss.netty.util.Timer; import com.ning.http.client.AsyncHttpProviderConfig; -import com.ning.http.client.providers.netty.pool.ChannelPool; +import com.ning.http.client.providers.netty.channel.pool.ChannelPool; import java.util.Map; import java.util.Set; diff --git a/src/main/java/com/ning/http/client/providers/netty/Protocol.java b/src/main/java/com/ning/http/client/providers/netty/Protocol.java index 76bb54c548..97bee0f6d2 100644 --- a/src/main/java/com/ning/http/client/providers/netty/Protocol.java +++ b/src/main/java/com/ning/http/client/providers/netty/Protocol.java @@ -17,6 +17,8 @@ import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.MessageEvent; +import com.ning.http.client.providers.netty.future.NettyResponseFuture; + public interface Protocol { void handle(Channel channel, MessageEvent e, NettyResponseFuture future) throws Exception; diff --git a/src/main/java/com/ning/http/client/providers/netty/pool/ChannelManager.java b/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java similarity index 95% rename from src/main/java/com/ning/http/client/providers/netty/pool/ChannelManager.java rename to src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java index a53dad6b82..1d5c29a82a 100644 --- a/src/main/java/com/ning/http/client/providers/netty/pool/ChannelManager.java +++ b/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java @@ -11,7 +11,7 @@ * "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.providers.netty.pool; +package com.ning.http.client.providers.netty.channel; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.group.ChannelGroup; @@ -19,9 +19,9 @@ import org.slf4j.LoggerFactory; import com.ning.http.client.AsyncHttpClientConfig; -import com.ning.http.client.providers.netty.Channels; -import com.ning.http.client.providers.netty.CleanupChannelGroup; -import com.ning.http.client.providers.netty.NettyResponseFuture; +import com.ning.http.client.providers.netty.channel.pool.ChannelPool; +import com.ning.http.client.providers.netty.future.NettyResponseFuture; +import com.ning.http.client.providers.netty.util.CleanupChannelGroup; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Semaphore; diff --git a/src/main/java/com/ning/http/client/providers/netty/Channels.java b/src/main/java/com/ning/http/client/providers/netty/channel/Channels.java similarity index 90% rename from src/main/java/com/ning/http/client/providers/netty/Channels.java rename to src/main/java/com/ning/http/client/providers/netty/channel/Channels.java index 7527d7a1b6..ced352b1a3 100644 --- a/src/main/java/com/ning/http/client/providers/netty/Channels.java +++ b/src/main/java/com/ning/http/client/providers/netty/channel/Channels.java @@ -11,11 +11,11 @@ * "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.providers.netty; +package com.ning.http.client.providers.netty.channel; import org.jboss.netty.channel.Channel; -import com.ning.http.client.providers.netty.NettyAsyncHttpProvider.DiscardEvent; +import com.ning.http.client.providers.netty.DiscardEvent; public final class Channels { diff --git a/src/main/java/com/ning/http/client/providers/netty/SslInitializer.java b/src/main/java/com/ning/http/client/providers/netty/channel/SslInitializer.java similarity index 93% rename from src/main/java/com/ning/http/client/providers/netty/SslInitializer.java rename to src/main/java/com/ning/http/client/providers/netty/channel/SslInitializer.java index 29c90299a6..eb4d458c7d 100644 --- a/src/main/java/com/ning/http/client/providers/netty/SslInitializer.java +++ b/src/main/java/com/ning/http/client/providers/netty/channel/SslInitializer.java @@ -13,13 +13,15 @@ * License for the specific language governing permissions and limitations * under the License. */ -package com.ning.http.client.providers.netty; +package com.ning.http.client.providers.netty.channel; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.SimpleChannelDownstreamHandler; import org.jboss.netty.handler.ssl.SslHandler; +import com.ning.http.client.providers.netty.NettyAsyncHttpProvider; + import java.net.InetSocketAddress; /** diff --git a/src/main/java/com/ning/http/client/providers/netty/pool/ChannelPool.java b/src/main/java/com/ning/http/client/providers/netty/channel/pool/ChannelPool.java similarity index 97% rename from src/main/java/com/ning/http/client/providers/netty/pool/ChannelPool.java rename to src/main/java/com/ning/http/client/providers/netty/channel/pool/ChannelPool.java index 5617e1fa31..c01195bfdb 100644 --- a/src/main/java/com/ning/http/client/providers/netty/pool/ChannelPool.java +++ b/src/main/java/com/ning/http/client/providers/netty/channel/pool/ChannelPool.java @@ -11,7 +11,7 @@ * "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.providers.netty.pool; +package com.ning.http.client.providers.netty.channel.pool; import org.jboss.netty.channel.Channel; diff --git a/src/main/java/com/ning/http/client/providers/netty/pool/DefaultChannelPool.java b/src/main/java/com/ning/http/client/providers/netty/channel/pool/DefaultChannelPool.java similarity index 97% rename from src/main/java/com/ning/http/client/providers/netty/pool/DefaultChannelPool.java rename to src/main/java/com/ning/http/client/providers/netty/channel/pool/DefaultChannelPool.java index b563990698..dde0e362e5 100644 --- a/src/main/java/com/ning/http/client/providers/netty/pool/DefaultChannelPool.java +++ b/src/main/java/com/ning/http/client/providers/netty/channel/pool/DefaultChannelPool.java @@ -11,7 +11,7 @@ * "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.providers.netty.pool; +package com.ning.http.client.providers.netty.channel.pool; import static com.ning.http.util.DateUtils.millisTime; @@ -31,11 +31,11 @@ import org.slf4j.LoggerFactory; import com.ning.http.client.AsyncHttpClientConfig; -import com.ning.http.client.providers.netty.Channels; -import com.ning.http.client.providers.netty.NettyResponseFuture; +import com.ning.http.client.providers.netty.channel.Channels; +import com.ning.http.client.providers.netty.future.NettyResponseFuture; /** - * A simple implementation of {@link com.ning.http.client.providers.netty.pool.ChannelPool} based on a {@link java.util.concurrent.ConcurrentHashMap} + * A simple implementation of {@link com.ning.http.client.providers.netty.channel.pool.ChannelPool} based on a {@link java.util.concurrent.ConcurrentHashMap} */ public final class DefaultChannelPool implements ChannelPool { diff --git a/src/main/java/com/ning/http/client/providers/netty/pool/NoopChannelPool.java b/src/main/java/com/ning/http/client/providers/netty/channel/pool/NoopChannelPool.java similarity index 95% rename from src/main/java/com/ning/http/client/providers/netty/pool/NoopChannelPool.java rename to src/main/java/com/ning/http/client/providers/netty/channel/pool/NoopChannelPool.java index d9f3006f61..6449e0c105 100644 --- a/src/main/java/com/ning/http/client/providers/netty/pool/NoopChannelPool.java +++ b/src/main/java/com/ning/http/client/providers/netty/channel/pool/NoopChannelPool.java @@ -11,7 +11,7 @@ * "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.providers.netty.pool; +package com.ning.http.client.providers.netty.channel.pool; import org.jboss.netty.channel.Channel; diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyResponseFuture.java b/src/main/java/com/ning/http/client/providers/netty/future/NettyResponseFuture.java similarity index 91% rename from src/main/java/com/ning/http/client/providers/netty/NettyResponseFuture.java rename to src/main/java/com/ning/http/client/providers/netty/future/NettyResponseFuture.java index a9f6255965..70d7289dca 100755 --- a/src/main/java/com/ning/http/client/providers/netty/NettyResponseFuture.java +++ b/src/main/java/com/ning/http/client/providers/netty/future/NettyResponseFuture.java @@ -13,7 +13,7 @@ * License for the specific language governing permissions and limitations * under the License. */ -package com.ning.http.client.providers.netty; +package com.ning.http.client.providers.netty.future; import static com.ning.http.util.DateUtils.millisTime; @@ -40,7 +40,8 @@ import com.ning.http.client.ProxyServer; import com.ning.http.client.Request; import com.ning.http.client.listenable.AbstractListenableFuture; -import com.ning.http.client.providers.netty.timeout.TimeoutsHolder; +import com.ning.http.client.providers.netty.channel.Channels; +import com.ning.http.client.providers.netty.request.timeout.TimeoutsHolder; import com.ning.http.client.uri.UriComponents; /** @@ -52,7 +53,7 @@ public final class NettyResponseFuture extends AbstractListenableFuture { private static final Logger LOGGER = LoggerFactory.getLogger(NettyResponseFuture.class); - enum STATE { + public enum STATE { NEW, POOLED, RECONNECTED, CLOSED, } @@ -271,11 +272,11 @@ public boolean getAndSetWriteBody(boolean writeBody) { /** INTERNAL **/ /*********************************************/ - protected UriComponents getURI() { + public UriComponents getURI() { return uri; } - protected void setURI(UriComponents uri) { + public void setURI(UriComponents uri) { this.uri = uri; } @@ -287,7 +288,7 @@ public ProxyServer getProxyServer() { return proxyServer; } - void setAsyncHandler(AsyncHandler asyncHandler) { + public void setAsyncHandler(AsyncHandler asyncHandler) { this.asyncHandler = asyncHandler; } @@ -302,7 +303,7 @@ public void cancelTimeouts() { } } - protected final Request getRequest() { + public final Request getRequest() { return request; } @@ -310,47 +311,47 @@ public final HttpRequest getNettyRequest() { return nettyRequest; } - protected final void setNettyRequest(HttpRequest nettyRequest) { + public final void setNettyRequest(HttpRequest nettyRequest) { this.nettyRequest = nettyRequest; } - protected final AsyncHandler getAsyncHandler() { + public final AsyncHandler getAsyncHandler() { return asyncHandler; } - protected final boolean isKeepAlive() { + public final boolean isKeepAlive() { return keepAlive; } - protected final void setKeepAlive(final boolean keepAlive) { + public final void setKeepAlive(final boolean keepAlive) { this.keepAlive = keepAlive; } - protected final HttpResponse getHttpResponse() { + public final HttpResponse getHttpResponse() { return httpResponse; } - protected final void setHttpResponse(final HttpResponse httpResponse) { + public final void setHttpResponse(final HttpResponse httpResponse) { this.httpResponse = httpResponse; } - protected int incrementAndGetCurrentRedirectCount() { + public int incrementAndGetCurrentRedirectCount() { return redirectCount.incrementAndGet(); } - protected boolean isInAuth() { + public boolean isInAuth() { return inAuth.get(); } - protected boolean getAndSetAuth(boolean inDigestAuth) { + public boolean getAndSetAuth(boolean inDigestAuth) { return inAuth.getAndSet(inDigestAuth); } - protected STATE getState() { + public STATE getState() { return state.get(); } - protected void setState(STATE state) { + public void setState(STATE state) { this.state.set(state); } @@ -358,7 +359,7 @@ public boolean getAndSetStatusReceived(boolean sr) { return statusReceived.getAndSet(sr); } - protected void attachChannel(Channel channel) { + public void attachChannel(Channel channel) { this.channel = channel; } @@ -374,20 +375,20 @@ public void setConnectAllowed(boolean allowConnect) { this.allowConnect = allowConnect; } - protected void attachChannel(Channel channel, boolean reuseChannel) { + public void attachChannel(Channel channel, boolean reuseChannel) { this.channel = channel; this.reuseChannel = reuseChannel; } - protected Channel channel() { + public Channel channel() { return channel; } - protected boolean reuseChannel() { + public boolean reuseChannel() { return reuseChannel; } - protected boolean canRetry() { + public boolean canRetry() { if (currentRetry.incrementAndGet() > maxRetry) { return false; } diff --git a/src/main/java/com/ning/http/client/providers/netty/StackTraceInspector.java b/src/main/java/com/ning/http/client/providers/netty/future/StackTraceInspector.java similarity index 97% rename from src/main/java/com/ning/http/client/providers/netty/StackTraceInspector.java rename to src/main/java/com/ning/http/client/providers/netty/future/StackTraceInspector.java index 59e6afcb8a..a91a547c61 100644 --- a/src/main/java/com/ning/http/client/providers/netty/StackTraceInspector.java +++ b/src/main/java/com/ning/http/client/providers/netty/future/StackTraceInspector.java @@ -10,7 +10,7 @@ * "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.providers.netty; +package com.ning.http.client.providers.netty.future; public class StackTraceInspector { diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyConnectListener.java b/src/main/java/com/ning/http/client/providers/netty/request/NettyConnectListener.java similarity index 92% rename from src/main/java/com/ning/http/client/providers/netty/NettyConnectListener.java rename to src/main/java/com/ning/http/client/providers/netty/request/NettyConnectListener.java index 6f4910d8be..e13a0edd5a 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyConnectListener.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/NettyConnectListener.java @@ -14,7 +14,7 @@ * under the License. * */ -package com.ning.http.client.providers.netty; +package com.ning.http.client.providers.netty.request; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFuture; @@ -25,7 +25,11 @@ import org.slf4j.LoggerFactory; import com.ning.http.client.AsyncHttpClientConfig; -import com.ning.http.client.providers.netty.pool.ChannelManager; +import com.ning.http.client.providers.netty.NettyAsyncHttpProvider; +import com.ning.http.client.providers.netty.channel.ChannelManager; +import com.ning.http.client.providers.netty.channel.Channels; +import com.ning.http.client.providers.netty.future.NettyResponseFuture; +import com.ning.http.client.providers.netty.future.StackTraceInspector; import com.ning.http.util.Base64; import javax.net.ssl.HostnameVerifier; @@ -38,7 +42,7 @@ /** * Non Blocking connect. */ -final class NettyConnectListener implements ChannelFutureListener { +public final class NettyConnectListener implements ChannelFutureListener { private static final Logger LOGGER = LoggerFactory.getLogger(NettyConnectListener.class); private final AsyncHttpClientConfig config; private final NettyResponseFuture future; diff --git a/src/main/java/com/ning/http/client/providers/netty/request/ProgressListener.java b/src/main/java/com/ning/http/client/providers/netty/request/ProgressListener.java new file mode 100644 index 0000000000..189d8b5ffd --- /dev/null +++ b/src/main/java/com/ning/http/client/providers/netty/request/ProgressListener.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2014 AsyncHttpClient Project. 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.providers.netty.request; + +import org.jboss.netty.channel.ChannelFuture; +import org.jboss.netty.channel.ChannelFutureProgressListener; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.ning.http.client.AsyncHandler; +import com.ning.http.client.AsyncHttpClientConfig; +import com.ning.http.client.ProgressAsyncHandler; +import com.ning.http.client.Realm; +import com.ning.http.client.providers.netty.future.NettyResponseFuture; +import com.ning.http.client.providers.netty.future.StackTraceInspector; + +import java.nio.channels.ClosedChannelException; + +public class ProgressListener implements ChannelFutureProgressListener { + + private static final Logger LOGGER = LoggerFactory.getLogger(ProgressListener.class); + + private final AsyncHttpClientConfig config; + private final boolean notifyHeaders; + private final AsyncHandler asyncHandler; + private final NettyResponseFuture future; + + public ProgressListener(AsyncHttpClientConfig config, boolean notifyHeaders, AsyncHandler asyncHandler, NettyResponseFuture future) { + this.config = config; + this.notifyHeaders = notifyHeaders; + this.asyncHandler = asyncHandler; + this.future = future; + } + + public void operationComplete(ChannelFuture cf) { + // The write operation failed. If the channel was cached, it means it got asynchronously closed. + // Let's retry a second time. + Throwable cause = cf.getCause(); + if (cause != null && future.getState() != NettyResponseFuture.STATE.NEW) { + + if (cause instanceof IllegalStateException) { + LOGGER.debug(cause.getMessage(), cause); + try { + cf.getChannel().close(); + } catch (RuntimeException ex) { + LOGGER.debug(ex.getMessage(), ex); + } + return; + } + + if (cause instanceof ClosedChannelException || StackTraceInspector.abortOnReadOrWriteException(cause)) { + + if (LOGGER.isDebugEnabled()) { + LOGGER.debug(cf.getCause() == null ? "" : cf.getCause().getMessage(), cf.getCause()); + } + + try { + cf.getChannel().close(); + } catch (RuntimeException ex) { + LOGGER.debug(ex.getMessage(), ex); + } + return; + } else { + future.abort(cause); + } + return; + } + 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. + */ + Realm realm = future.getRequest().getRealm() != null ? future.getRequest().getRealm() : config.getRealm(); + boolean startPublishing = future.isInAuth() || realm == null || realm.getUsePreemptiveAuth(); + + if (startPublishing && asyncHandler instanceof ProgressAsyncHandler) { + if (notifyHeaders) { + ProgressAsyncHandler.class.cast(asyncHandler).onHeaderWriteCompleted(); + } else { + ProgressAsyncHandler.class.cast(asyncHandler).onContentWriteCompleted(); + } + } + } + + public void operationProgressed(ChannelFuture cf, long amount, long current, long total) { + future.touch(); + if (asyncHandler instanceof ProgressAsyncHandler) { + ProgressAsyncHandler.class.cast(asyncHandler).onContentWriteProgress(amount, current, total); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/ning/http/client/providers/netty/BodyChunkedInput.java b/src/main/java/com/ning/http/client/providers/netty/request/body/BodyChunkedInput.java similarity index 95% rename from src/main/java/com/ning/http/client/providers/netty/BodyChunkedInput.java rename to src/main/java/com/ning/http/client/providers/netty/request/body/BodyChunkedInput.java index 2b0003d21f..22c32bf198 100644 --- a/src/main/java/com/ning/http/client/providers/netty/BodyChunkedInput.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/body/BodyChunkedInput.java @@ -10,7 +10,7 @@ * "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.providers.netty; +package com.ning.http.client.providers.netty.request.body; import com.ning.http.client.Body; import org.jboss.netty.buffer.ChannelBuffers; @@ -21,7 +21,7 @@ /** * Adapts a {@link Body} to Netty's {@link ChunkedInput}. */ -class BodyChunkedInput implements ChunkedInput { +public class BodyChunkedInput implements ChunkedInput { private static final int DEFAULT_CHUNK_SIZE = 8 * 1024; diff --git a/src/main/java/com/ning/http/client/providers/netty/BodyFileRegion.java b/src/main/java/com/ning/http/client/providers/netty/request/body/BodyFileRegion.java similarity index 94% rename from src/main/java/com/ning/http/client/providers/netty/BodyFileRegion.java rename to src/main/java/com/ning/http/client/providers/netty/request/body/BodyFileRegion.java index 267051878c..546e82692e 100644 --- a/src/main/java/com/ning/http/client/providers/netty/BodyFileRegion.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/body/BodyFileRegion.java @@ -10,7 +10,7 @@ * "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.providers.netty; +package com.ning.http.client.providers.netty.request.body; import com.ning.http.client.RandomAccessBody; import org.jboss.netty.channel.FileRegion; @@ -21,7 +21,7 @@ /** * Adapts a {@link RandomAccessBody} to Netty's {@link FileRegion}. */ -class BodyFileRegion +public class BodyFileRegion implements FileRegion { private final RandomAccessBody body; diff --git a/src/main/java/com/ning/http/client/providers/netty/timeout/ReadTimeoutTimerTask.java b/src/main/java/com/ning/http/client/providers/netty/request/timeout/ReadTimeoutTimerTask.java similarity index 95% rename from src/main/java/com/ning/http/client/providers/netty/timeout/ReadTimeoutTimerTask.java rename to src/main/java/com/ning/http/client/providers/netty/request/timeout/ReadTimeoutTimerTask.java index ec397a152d..75e4eb0f39 100644 --- a/src/main/java/com/ning/http/client/providers/netty/timeout/ReadTimeoutTimerTask.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/timeout/ReadTimeoutTimerTask.java @@ -10,14 +10,14 @@ * "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.providers.netty.timeout; +package com.ning.http.client.providers.netty.request.timeout; import static com.ning.http.util.DateUtils.millisTime; import org.jboss.netty.util.Timeout; import com.ning.http.client.providers.netty.NettyAsyncHttpProvider; -import com.ning.http.client.providers.netty.NettyResponseFuture; +import com.ning.http.client.providers.netty.future.NettyResponseFuture; public class ReadTimeoutTimerTask extends TimeoutTimerTask { diff --git a/src/main/java/com/ning/http/client/providers/netty/timeout/RequestTimeoutTimerTask.java b/src/main/java/com/ning/http/client/providers/netty/request/timeout/RequestTimeoutTimerTask.java similarity index 92% rename from src/main/java/com/ning/http/client/providers/netty/timeout/RequestTimeoutTimerTask.java rename to src/main/java/com/ning/http/client/providers/netty/request/timeout/RequestTimeoutTimerTask.java index 1ac1b48fb8..25ffcf834d 100644 --- a/src/main/java/com/ning/http/client/providers/netty/timeout/RequestTimeoutTimerTask.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/timeout/RequestTimeoutTimerTask.java @@ -10,14 +10,14 @@ * "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.providers.netty.timeout; +package com.ning.http.client.providers.netty.request.timeout; import static com.ning.http.util.DateUtils.millisTime; import org.jboss.netty.util.Timeout; import com.ning.http.client.providers.netty.NettyAsyncHttpProvider; -import com.ning.http.client.providers.netty.NettyResponseFuture; +import com.ning.http.client.providers.netty.future.NettyResponseFuture; public class RequestTimeoutTimerTask extends TimeoutTimerTask { diff --git a/src/main/java/com/ning/http/client/providers/netty/timeout/TimeoutTimerTask.java b/src/main/java/com/ning/http/client/providers/netty/request/timeout/TimeoutTimerTask.java similarity index 92% rename from src/main/java/com/ning/http/client/providers/netty/timeout/TimeoutTimerTask.java rename to src/main/java/com/ning/http/client/providers/netty/request/timeout/TimeoutTimerTask.java index 4d5888f810..ceed91777f 100644 --- a/src/main/java/com/ning/http/client/providers/netty/timeout/TimeoutTimerTask.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/timeout/TimeoutTimerTask.java @@ -10,7 +10,7 @@ * "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.providers.netty.timeout; +package com.ning.http.client.providers.netty.request.timeout; import java.util.concurrent.TimeoutException; @@ -19,7 +19,7 @@ import org.slf4j.LoggerFactory; import com.ning.http.client.providers.netty.NettyAsyncHttpProvider; -import com.ning.http.client.providers.netty.NettyResponseFuture; +import com.ning.http.client.providers.netty.future.NettyResponseFuture; public abstract class TimeoutTimerTask implements TimerTask { diff --git a/src/main/java/com/ning/http/client/providers/netty/timeout/TimeoutsHolder.java b/src/main/java/com/ning/http/client/providers/netty/request/timeout/TimeoutsHolder.java similarity index 95% rename from src/main/java/com/ning/http/client/providers/netty/timeout/TimeoutsHolder.java rename to src/main/java/com/ning/http/client/providers/netty/request/timeout/TimeoutsHolder.java index 9855f655cd..e062c45207 100644 --- a/src/main/java/com/ning/http/client/providers/netty/timeout/TimeoutsHolder.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/timeout/TimeoutsHolder.java @@ -10,7 +10,7 @@ * "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.providers.netty.timeout; +package com.ning.http.client.providers.netty.request.timeout; import org.jboss.netty.util.Timeout; diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyResponse.java b/src/main/java/com/ning/http/client/providers/netty/response/NettyResponse.java similarity index 98% rename from src/main/java/com/ning/http/client/providers/netty/NettyResponse.java rename to src/main/java/com/ning/http/client/providers/netty/response/NettyResponse.java index 25764d4fe6..78a8d30f45 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyResponse.java +++ b/src/main/java/com/ning/http/client/providers/netty/response/NettyResponse.java @@ -13,7 +13,7 @@ * License for the specific language governing permissions and limitations * under the License. */ -package com.ning.http.client.providers.netty; +package com.ning.http.client.providers.netty.response; import static com.ning.http.util.MiscUtils.isNonEmpty; @@ -37,6 +37,7 @@ import com.ning.http.client.Response; import com.ning.http.client.cookie.Cookie; import com.ning.http.client.cookie.CookieDecoder; +import com.ning.http.client.providers.netty.util.ChannelBufferUtil; import com.ning.http.client.uri.UriComponents; import com.ning.http.util.AsyncHttpProviderUtils; import com.ning.http.util.StandardCharsets; diff --git a/src/main/java/com/ning/http/client/providers/netty/ResponseBodyPart.java b/src/main/java/com/ning/http/client/providers/netty/response/ResponseBodyPart.java similarity index 96% rename from src/main/java/com/ning/http/client/providers/netty/ResponseBodyPart.java rename to src/main/java/com/ning/http/client/providers/netty/response/ResponseBodyPart.java index 0c3bbaf689..fc4049f154 100644 --- a/src/main/java/com/ning/http/client/providers/netty/ResponseBodyPart.java +++ b/src/main/java/com/ning/http/client/providers/netty/response/ResponseBodyPart.java @@ -13,10 +13,11 @@ * License for the specific language governing permissions and limitations * under the License. */ -package com.ning.http.client.providers.netty; +package com.ning.http.client.providers.netty.response; import com.ning.http.client.AsyncHttpProvider; import com.ning.http.client.HttpResponseBodyPart; +import com.ning.http.client.providers.netty.util.ChannelBufferUtil; import com.ning.http.client.uri.UriComponents; import org.jboss.netty.buffer.ChannelBuffer; diff --git a/src/main/java/com/ning/http/client/providers/netty/ResponseHeaders.java b/src/main/java/com/ning/http/client/providers/netty/response/ResponseHeaders.java similarity index 97% rename from src/main/java/com/ning/http/client/providers/netty/ResponseHeaders.java rename to src/main/java/com/ning/http/client/providers/netty/response/ResponseHeaders.java index 259e852c44..5b2e9ab271 100644 --- a/src/main/java/com/ning/http/client/providers/netty/ResponseHeaders.java +++ b/src/main/java/com/ning/http/client/providers/netty/response/ResponseHeaders.java @@ -13,7 +13,7 @@ * License for the specific language governing permissions and limitations * under the License. */ -package com.ning.http.client.providers.netty; +package com.ning.http.client.providers.netty.response; import com.ning.http.client.AsyncHttpProvider; import com.ning.http.client.FluentCaseInsensitiveStringsMap; diff --git a/src/main/java/com/ning/http/client/providers/netty/ResponseStatus.java b/src/main/java/com/ning/http/client/providers/netty/response/ResponseStatus.java similarity index 97% rename from src/main/java/com/ning/http/client/providers/netty/ResponseStatus.java rename to src/main/java/com/ning/http/client/providers/netty/response/ResponseStatus.java index 9de7f8f928..67452cfe83 100644 --- a/src/main/java/com/ning/http/client/providers/netty/ResponseStatus.java +++ b/src/main/java/com/ning/http/client/providers/netty/response/ResponseStatus.java @@ -14,7 +14,7 @@ * under the License. * */ -package com.ning.http.client.providers.netty; +package com.ning.http.client.providers.netty.response; import com.ning.http.client.AsyncHttpProvider; import com.ning.http.client.HttpResponseStatus; diff --git a/src/main/java/com/ning/http/client/providers/netty/ChannelBufferUtil.java b/src/main/java/com/ning/http/client/providers/netty/util/ChannelBufferUtil.java similarity index 95% rename from src/main/java/com/ning/http/client/providers/netty/ChannelBufferUtil.java rename to src/main/java/com/ning/http/client/providers/netty/util/ChannelBufferUtil.java index e2707f6dfe..d86d7f96ba 100644 --- a/src/main/java/com/ning/http/client/providers/netty/ChannelBufferUtil.java +++ b/src/main/java/com/ning/http/client/providers/netty/util/ChannelBufferUtil.java @@ -13,7 +13,7 @@ * License for the specific language governing permissions and limitations * under the License. */ -package com.ning.http.client.providers.netty; +package com.ning.http.client.providers.netty.util; import org.jboss.netty.buffer.ChannelBuffer; diff --git a/src/main/java/com/ning/http/client/providers/netty/CleanupChannelGroup.java b/src/main/java/com/ning/http/client/providers/netty/util/CleanupChannelGroup.java similarity index 98% rename from src/main/java/com/ning/http/client/providers/netty/CleanupChannelGroup.java rename to src/main/java/com/ning/http/client/providers/netty/util/CleanupChannelGroup.java index 89e50077db..c09f28084e 100644 --- a/src/main/java/com/ning/http/client/providers/netty/CleanupChannelGroup.java +++ b/src/main/java/com/ning/http/client/providers/netty/util/CleanupChannelGroup.java @@ -26,7 +26,7 @@ * limitations under the License. */ -package com.ning.http.client.providers.netty; +package com.ning.http.client.providers.netty.util; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFuture; diff --git a/src/main/java/com/ning/http/client/providers/netty/NettyWebSocket.java b/src/main/java/com/ning/http/client/providers/netty/ws/NettyWebSocket.java similarity index 96% rename from src/main/java/com/ning/http/client/providers/netty/NettyWebSocket.java rename to src/main/java/com/ning/http/client/providers/netty/ws/NettyWebSocket.java index b093330dd4..3ff9f8ff6a 100644 --- a/src/main/java/com/ning/http/client/providers/netty/NettyWebSocket.java +++ b/src/main/java/com/ning/http/client/providers/netty/ws/NettyWebSocket.java @@ -10,7 +10,7 @@ * "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.providers.netty; +package com.ning.http.client.providers.netty.ws; import com.ning.http.client.websocket.WebSocket; import com.ning.http.client.websocket.WebSocketByteListener; @@ -128,7 +128,7 @@ public void close(int statusCode, String reason) { listeners.clear(); } - protected void onBinaryFragment(byte[] message, boolean last) { + public void onBinaryFragment(byte[] message, boolean last) { if (!last) { try { @@ -173,7 +173,7 @@ protected void onBinaryFragment(byte[] message, boolean last) { } } - protected void onTextFragment(String message, boolean last) { + public void onTextFragment(String message, boolean last) { if (!last) { textBuffer.append(message); @@ -212,7 +212,7 @@ protected void onTextFragment(String message, boolean last) { } } - protected void onError(Throwable t) { + public void onError(Throwable t) { for (WebSocketListener l : listeners) { try { l.onError(t); @@ -227,7 +227,7 @@ protected void onClose() { onClose(1000, "Normal closure; the connection successfully completed whatever purpose for which it was created."); } - protected void onClose(int code, String reason) { + public void onClose(int code, String reason) { for (WebSocketListener l : listeners) { try { if (l instanceof WebSocketCloseCodeReasonListener) { diff --git a/src/main/java/com/ning/http/client/providers/netty/WebSocketUtil.java b/src/main/java/com/ning/http/client/providers/netty/ws/WebSocketUtil.java similarity index 97% rename from src/main/java/com/ning/http/client/providers/netty/WebSocketUtil.java rename to src/main/java/com/ning/http/client/providers/netty/ws/WebSocketUtil.java index 5e20a499cf..90bd48269a 100644 --- a/src/main/java/com/ning/http/client/providers/netty/WebSocketUtil.java +++ b/src/main/java/com/ning/http/client/providers/netty/ws/WebSocketUtil.java @@ -10,7 +10,7 @@ * "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.providers.netty; +package com.ning.http.client.providers.netty.ws; import com.ning.http.util.Base64; diff --git a/src/test/java/com/ning/http/client/async/netty/NettyConnectionPoolTest.java b/src/test/java/com/ning/http/client/async/netty/NettyConnectionPoolTest.java index c81aba6a15..e5bf904f59 100644 --- a/src/test/java/com/ning/http/client/async/netty/NettyConnectionPoolTest.java +++ b/src/test/java/com/ning/http/client/async/netty/NettyConnectionPoolTest.java @@ -27,7 +27,7 @@ import com.ning.http.client.async.ConnectionPoolTest; import com.ning.http.client.async.ProviderUtil; import com.ning.http.client.providers.netty.NettyAsyncHttpProviderConfig; -import com.ning.http.client.providers.netty.pool.ChannelPool; +import com.ning.http.client.providers.netty.channel.pool.ChannelPool; import java.net.ConnectException; import java.util.concurrent.TimeUnit; 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 135e13fe0e..1b340032e8 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 @@ -26,6 +26,8 @@ import com.ning.http.client.FluentCaseInsensitiveStringsMap; import com.ning.http.client.HttpResponseHeaders; import com.ning.http.client.cookie.Cookie; +import com.ning.http.client.providers.netty.response.NettyResponse; +import com.ning.http.client.providers.netty.response.ResponseStatus; /** * @author Benjamin Hanzelmann From 3992022505896231af7c3c995de080dfe35076c3 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 22 Jul 2014 11:55:44 +0200 Subject: [PATCH 457/701] Upgrade to AHC2 status, headers and parts API, close #641 --- .../ning/http/client/AsyncHttpProvider.java | 13 -- .../com/ning/http/client/HttpContent.java | 49 ------- .../http/client/HttpResponseBodyPart.java | 72 +++++++---- .../ning/http/client/HttpResponseHeaders.java | 10 +- .../ning/http/client/HttpResponseStatus.java | 58 ++++++--- .../java/com/ning/http/client/Response.java | 122 +++++++++--------- .../apache/ApacheAsyncHttpProvider.java | 8 +- .../apache/ApacheResponseBodyPart.java | 29 ++--- .../apache/ApacheResponseHeaders.java | 11 +- .../apache/ApacheResponseStatus.java | 17 ++- .../grizzly/GrizzlyAsyncHttpProvider.java | 25 +--- .../grizzly/GrizzlyResponseBodyPart.java | 18 +-- .../grizzly/GrizzlyResponseHeaders.java | 7 +- .../grizzly/GrizzlyResponseStatus.java | 16 ++- .../providers/jdk/JDKAsyncHttpProvider.java | 15 +-- .../providers/jdk/ResponseBodyPart.java | 29 ++--- .../client/providers/jdk/ResponseHeaders.java | 9 +- .../client/providers/jdk/ResponseStatus.java | 14 +- .../netty/NettyAsyncHttpProvider.java | 30 ++--- .../netty/response/ResponseBodyPart.java | 47 ++----- .../netty/response/ResponseHeaders.java | 22 ++-- .../netty/response/ResponseStatus.java | 15 ++- .../webdav/WebDavCompletionHandlerBase.java | 11 +- .../client/async/AsyncStreamHandlerTest.java | 2 +- .../netty/NettyAsyncResponseTest.java | 6 +- 25 files changed, 291 insertions(+), 364 deletions(-) delete mode 100644 src/main/java/com/ning/http/client/HttpContent.java diff --git a/src/main/java/com/ning/http/client/AsyncHttpProvider.java b/src/main/java/com/ning/http/client/AsyncHttpProvider.java index 8aa6052400..cfde4082d8 100644 --- a/src/main/java/com/ning/http/client/AsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/AsyncHttpProvider.java @@ -16,7 +16,6 @@ package com.ning.http.client; import java.io.IOException; -import java.util.List; /** * Interface to be used when implementing custom asynchronous I/O HTTP client. @@ -37,16 +36,4 @@ public interface AsyncHttpProvider { * Close the current underlying TCP/HTTP connection. */ void close(); - - /** - * Prepare a {@link Response} - * - * @param status {@link HttpResponseStatus} - * @param headers {@link HttpResponseHeaders} - * @param bodyParts list of {@link HttpResponseBodyPart} - * @return a {@link Response} - */ - Response prepareResponse(HttpResponseStatus status, - HttpResponseHeaders headers, - List bodyParts); } diff --git a/src/main/java/com/ning/http/client/HttpContent.java b/src/main/java/com/ning/http/client/HttpContent.java deleted file mode 100644 index fff00b9280..0000000000 --- a/src/main/java/com/ning/http/client/HttpContent.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * 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 com.ning.http.client.uri.UriComponents; - -/** - * Base class for callback class used by {@link com.ning.http.client.AsyncHandler} - */ -public class HttpContent { - protected final AsyncHttpProvider provider; - protected final UriComponents uri; - - protected HttpContent(UriComponents uri, AsyncHttpProvider provider) { - this.provider = provider; - this.uri = uri; - } - - /** - * Return the current {@link AsyncHttpProvider} - * - * @return the current {@link AsyncHttpProvider} - */ - public final AsyncHttpProvider provider() { - return provider; - } - - /** - * Return the request {@link UriComponents} - * - * @return the request {@link UriComponents} - */ - public final UriComponents getUri() { - return uri; - } -} diff --git a/src/main/java/com/ning/http/client/HttpResponseBodyPart.java b/src/main/java/com/ning/http/client/HttpResponseBodyPart.java index c310f37942..d0fc141be4 100644 --- a/src/main/java/com/ning/http/client/HttpResponseBodyPart.java +++ b/src/main/java/com/ning/http/client/HttpResponseBodyPart.java @@ -15,21 +15,55 @@ */ package com.ning.http.client; -import com.ning.http.client.uri.UriComponents; - import java.io.IOException; +import java.io.InputStream; import java.io.OutputStream; import java.nio.ByteBuffer; /** * A callback class used when an HTTP response body is received. */ -public abstract class HttpResponseBodyPart extends HttpContent { +public abstract class HttpResponseBodyPart { + + private final boolean last; + private boolean closeConnection; - public HttpResponseBodyPart(UriComponents uri, AsyncHttpProvider provider) { - super(uri, provider); + public HttpResponseBodyPart(boolean last) { + this.last = last; } + /** + * Close the underlying connection once the processing has completed. Invoking that method means the + * underlying TCP connection will be closed as soon as the processing of the response is completed. That + * means the underlying connection will never get pooled. + */ + public void markUnderlyingConnectionAsToBeClosed() { + closeConnection = true; + } + + /** + * Return true of the underlying connection will be closed once the response has been fully processed. + * + * @return true of the underlying connection will be closed once the response has been fully processed. + */ + public boolean isUnderlyingConnectionToBeClosed() { + return closeConnection; + } + + /** + * Return true if this is the last part. + * + * @return true if this is the last part. + */ + public boolean isLast() { + return last; + } + + /** + * Return length of this part in bytes. + */ + public abstract int length(); + /** * Return the response body's part bytes received. * @@ -37,6 +71,11 @@ public HttpResponseBodyPart(UriComponents uri, AsyncHttpProvider provider) { */ public abstract byte[] getBodyPartBytes(); + /** + * Method for accessing contents of this part via stream. + */ + public abstract InputStream readBodyPartBytes(); + /** * Write the available bytes to the {@link java.io.OutputStream} * @@ -53,27 +92,4 @@ public HttpResponseBodyPart(UriComponents uri, AsyncHttpProvider provider) { * @return {@link ByteBuffer} */ public abstract ByteBuffer getBodyByteBuffer(); - - /** - * Return true if this is the last part. - * - * @return true if this is the last part. - */ - public abstract boolean isLast(); - - /** - * Close the underlying connection once the processing has completed. Invoking that method means the - * underlying TCP connection will be closed as soon as the processing of the response is completed. That - * means the underlying connection will never get pooled. - */ - public abstract void markUnderlyingConnectionAsClosed(); - - /** - * Return true of the underlying connection will be closed once the response has been fully processed. - * - * @return true of the underlying connection will be closed once the response has been fully processed. - */ - public abstract boolean closeUnderlyingConnection(); - - public abstract int length(); } diff --git a/src/main/java/com/ning/http/client/HttpResponseHeaders.java b/src/main/java/com/ning/http/client/HttpResponseHeaders.java index e6dcf13d23..9070eb064d 100644 --- a/src/main/java/com/ning/http/client/HttpResponseHeaders.java +++ b/src/main/java/com/ning/http/client/HttpResponseHeaders.java @@ -15,22 +15,18 @@ */ package com.ning.http.client; -import com.ning.http.client.uri.UriComponents; - /** * A class that represent the HTTP headers. */ -public abstract class HttpResponseHeaders extends HttpContent { +public abstract class HttpResponseHeaders { private final boolean traillingHeaders; - public HttpResponseHeaders(UriComponents uri, AsyncHttpProvider provider) { - super(uri, provider); + public HttpResponseHeaders() { this.traillingHeaders = false; } - public HttpResponseHeaders(UriComponents uri, AsyncHttpProvider provider, boolean traillingHeaders) { - super(uri, provider); + public HttpResponseHeaders(boolean traillingHeaders) { this.traillingHeaders = traillingHeaders; } diff --git a/src/main/java/com/ning/http/client/HttpResponseStatus.java b/src/main/java/com/ning/http/client/HttpResponseStatus.java index 8084d9f97d..9e3b9f7183 100644 --- a/src/main/java/com/ning/http/client/HttpResponseStatus.java +++ b/src/main/java/com/ning/http/client/HttpResponseStatus.java @@ -18,54 +18,82 @@ import com.ning.http.client.uri.UriComponents; +import java.util.List; + /** * A class that represent the HTTP response' status line (code + text) */ -public abstract class HttpResponseStatus extends HttpContent { +public abstract class HttpResponseStatus { + + private final UriComponents uri; + protected final AsyncHttpClientConfig config; - public HttpResponseStatus(UriComponents uri, AsyncHttpProvider provider) { - super(uri, provider); + public HttpResponseStatus(UriComponents uri, AsyncHttpClientConfig config) { + this.uri = uri; + this.config = config; } /** - * Return the response status code + * Return the request {@link UriComponents} + * + * @return the request {@link UriComponents} + */ + public final UriComponents getUri() { + return uri; + } + + public AsyncHttpClientConfig getConfig() { + return config; + } + + /** + * Prepare a {@link Response} * + * @param headers {@link HttpResponseHeaders} + * @param bodyParts list of {@link HttpResponseBodyPart} + * @return a {@link Response} + */ + public abstract Response prepareResponse(HttpResponseHeaders headers, List bodyParts); + + /** + * Return the response status code + * * @return the response status code */ - abstract public int getStatusCode(); + public abstract int getStatusCode(); /** * Return the response status text - * + * * @return the response status text */ - abstract public String getStatusText(); + public abstract String getStatusText(); /** * Protocol name from status line. - * + * * @return Protocol name. */ - abstract public String getProtocolName(); + public abstract String getProtocolName(); /** * Protocol major version. - * + * * @return Major version. */ - abstract public int getProtocolMajorVersion(); + public abstract int getProtocolMajorVersion(); /** * Protocol minor version. - * + * * @return Minor version. */ - abstract public int getProtocolMinorVersion(); + public abstract int getProtocolMinorVersion(); /** * Full protocol name + version - * + * * @return protocol name + version */ - abstract public String getProtocolText(); + public abstract String getProtocolText(); } diff --git a/src/main/java/com/ning/http/client/Response.java b/src/main/java/com/ning/http/client/Response.java index 55d8fc86ed..55fd8e00ed 100644 --- a/src/main/java/com/ning/http/client/Response.java +++ b/src/main/java/com/ning/http/client/Response.java @@ -16,37 +16,37 @@ */ package com.ning.http.client; +import com.ning.http.client.cookie.Cookie; +import com.ning.http.client.uri.UriComponents; + import java.io.IOException; import java.io.InputStream; +import java.net.URI; import java.nio.ByteBuffer; import java.util.ArrayList; -import java.util.Collections; import java.util.List; -import com.ning.http.client.cookie.Cookie; -import com.ning.http.client.uri.UriComponents; - /** - * Represents the asynchronous HTTP response callback for an {@link com.ning.http.client.AsyncCompletionHandler} + * Represents the asynchronous HTTP response callback for an {@link AsyncCompletionHandler} */ public interface Response { /** * Returns the status code for the request. - * + * * @return The status code */ int getStatusCode(); /** * Returns the status text for the request. - * + * * @return The status text */ String getStatusText(); /** * Return the entire response body as a byte[]. - * + * * @return the entire response body as a byte[]. * @throws IOException */ @@ -54,28 +54,28 @@ public interface Response { /** * Return the entire response body as a ByteBuffer. - * + * * @return the entire response body as a ByteBuffer. * @throws IOException */ 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. - * + * 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. + * * @return The input stream * @throws java.io.IOException */ InputStream getResponseBodyAsStream() throws IOException; /** - * Returns the first maxLength bytes of the response body as a string. Note that this does not check - * whether the content type is actually a textual one, but it will use the charset if present in the content - * type header. - * - * @param maxLength The maximum number of bytes to read - * @param charset the charset to use when decoding the stream + * Returns the first maxLength bytes of the response body as a string. Note that this does not check whether the content type is actually a textual one, but it will use the + * charset if present in the content type header. + * + * @param maxLength + * The maximum number of bytes to read + * @param charset + * the charset to use when decoding the stream * @return The response body * @throws java.io.IOException */ @@ -83,19 +83,20 @@ public interface Response { /** * Return the entire response body as a String. - * - * @param charset the charset to use when decoding the stream + * + * @param charset + * the charset to use when decoding the stream * @return the entire response body as a String. * @throws IOException */ String getResponseBody(String charset) throws IOException; /** - * Returns the first maxLength bytes of the response body as a string. Note that this does not check - * whether the content type is actually a textual one, but it will use the charset if present in the content - * type header. - * - * @param maxLength The maximum number of bytes to read + * Returns the first maxLength bytes of the response body as a string. Note that this does not check whether the content type is actually a textual one, but it will use the + * charset if present in the content type header. + * + * @param maxLength + * The maximum number of bytes to read * @return The response body * @throws java.io.IOException */ @@ -103,37 +104,36 @@ public interface Response { /** * Return the entire response body as a String. - * + * * @return the entire response body as a String. * @throws IOException */ String getResponseBody() throws IOException; /** - * Return the request {@link UriComponents}. Note that if the request got redirected, the value of the {@link UriComponents} will be - * the last valid redirect url. - * + * Return the request {@link UriComponents}. Note that if the request got redirected, the value of the {@link URI} will be the last valid redirect url. + * * @return the request {@link UriComponents}. */ UriComponents getUri(); /** * Return the content-type header value. - * + * * @return the content-type header value. */ String getContentType(); /** * Return the response header - * + * * @return the response header */ String getHeader(String name); /** * Return a {@link List} of the response header value. - * + * * @return the response header */ List getHeaders(String name); @@ -142,14 +142,14 @@ public interface Response { /** * Return true if the response redirects to another object. - * + * * @return True if the response redirects to another object. */ boolean isRedirected(); /** * Subclasses SHOULD implement toString() in a way that identifies the request for logging. - * + * * @return The textual representation */ String toString(); @@ -161,69 +161,67 @@ public interface Response { /** * Return true if the response's status has been computed by an {@link AsyncHandler} - * + * * @return true if the response's status has been computed by an {@link AsyncHandler} */ boolean hasResponseStatus(); /** - * Return true if the response's headers has been computed by an {@link AsyncHandler} It will return false if the - * either {@link com.ning.http.client.AsyncHandler#onStatusReceived(HttpResponseStatus)} - * or {@link AsyncHandler#onHeadersReceived(HttpResponseHeaders)} returned {@link com.ning.http.client.AsyncHandler.STATE#ABORT} - * + * Return true if the response's headers has been computed by an {@link AsyncHandler} It will return false if the either + * {@link AsyncHandler#onStatusReceived(HttpResponseStatus)} or {@link AsyncHandler#onHeadersReceived(HttpResponseHeaders)} returned {@link AsyncHandler.STATE#ABORT} + * * @return true if the response's headers has been computed by an {@link AsyncHandler} */ boolean hasResponseHeaders(); /** - * Return true if the response's body has been computed by an {@link AsyncHandler}. It will return false if the - * either {@link com.ning.http.client.AsyncHandler#onStatusReceived(HttpResponseStatus)} - * or {@link AsyncHandler#onHeadersReceived(HttpResponseHeaders)} returned {@link com.ning.http.client.AsyncHandler.STATE#ABORT} - * + * Return true if the response's body has been computed by an {@link AsyncHandler}. It will return false if the either {@link AsyncHandler#onStatusReceived(HttpResponseStatus)} + * or {@link AsyncHandler#onHeadersReceived(HttpResponseHeaders)} returned {@link AsyncHandler.STATE#ABORT} + * * @return true if the response's body has been computed by an {@link AsyncHandler} */ boolean hasResponseBody(); - public static class ResponseBuilder { - private final List bodies = - Collections.synchronizedList(new ArrayList()); + private final List bodyParts = new ArrayList(); private HttpResponseStatus status; private HttpResponseHeaders headers; + public ResponseBuilder accumulate(HttpResponseStatus status) { + this.status = status; + return this; + } + + public ResponseBuilder accumulate(HttpResponseHeaders headers) { + this.headers = headers; + return this; + } + /** - * Accumulate {@link HttpContent} in order to build a {@link Response} - * - * @param httpContent {@link HttpContent} + * @param bodyPart + * a body part (possibly empty, but will be filtered out) * @return this */ - public ResponseBuilder accumulate(HttpContent httpContent) { - if (httpContent instanceof HttpResponseStatus) { - status = (HttpResponseStatus) httpContent; - } else if (httpContent instanceof HttpResponseHeaders) { - headers = (HttpResponseHeaders) httpContent; - } else if (httpContent instanceof HttpResponseBodyPart) { - HttpResponseBodyPart part = (HttpResponseBodyPart) httpContent; - if (part.length() > 0) - bodies.add(part); - } + public ResponseBuilder accumulate(HttpResponseBodyPart bodyPart) { + if (bodyPart.length() > 0) + bodyParts.add(bodyPart); return this; } /** * Build a {@link Response} instance - * + * * @return a {@link Response} instance */ public Response build() { - return status == null ? null : status.provider().prepareResponse(status, headers, bodies); + return status == null ? null : status.prepareResponse(headers, bodyParts); } /** * Reset the internal state of this builder. */ public void reset() { - bodies.clear(); + bodyParts.clear(); status = null; headers = null; } 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 50518dff0b..f17d748ca7 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 @@ -481,7 +481,7 @@ public T call() { currentRedirectCount = config.getMaxRedirects(); } - ApacheResponseStatus status = new ApacheResponseStatus(uri, method, ApacheAsyncHttpProvider.this); + ApacheResponseStatus status = new ApacheResponseStatus(uri, config, method); FilterContext fc = new FilterContext.FilterContextBuilder().asyncHandler(asyncHandler).request(request).responseStatus(status).build(); for (ResponseFilter asyncFilter : config.getResponseFilters()) { fc = asyncFilter.filter(fc); @@ -525,7 +525,7 @@ public T call() { state = asyncHandler.onStatusReceived(status); if (state == AsyncHandler.STATE.CONTINUE) { - state = asyncHandler.onHeadersReceived(new ApacheResponseHeaders(uri, method, ApacheAsyncHttpProvider.this)); + state = asyncHandler.onHeadersReceived(new ApacheResponseHeaders(method)); } if (state == AsyncHandler.STATE.CONTINUE) { @@ -573,14 +573,14 @@ public T call() { System.arraycopy(bytes, 0, b, 0, read); leftBytes -= read; - asyncHandler.onBodyPartReceived(new ApacheResponseBodyPart(uri, b, ApacheAsyncHttpProvider.this, leftBytes > -1)); + asyncHandler.onBodyPartReceived(new ApacheResponseBodyPart(b, leftBytes > -1)); } } } if (method.getName().equalsIgnoreCase("HEAD")) { - asyncHandler.onBodyPartReceived(new ApacheResponseBodyPart(uri, "".getBytes(), ApacheAsyncHttpProvider.this, true)); + asyncHandler.onBodyPartReceived(new ApacheResponseBodyPart("".getBytes(), true)); } } diff --git a/src/main/java/com/ning/http/client/providers/apache/ApacheResponseBodyPart.java b/src/main/java/com/ning/http/client/providers/apache/ApacheResponseBodyPart.java index 3050b35631..d89e4f874a 100644 --- a/src/main/java/com/ning/http/client/providers/apache/ApacheResponseBodyPart.java +++ b/src/main/java/com/ning/http/client/providers/apache/ApacheResponseBodyPart.java @@ -12,11 +12,11 @@ */ package com.ning.http.client.providers.apache; -import com.ning.http.client.AsyncHttpProvider; import com.ning.http.client.HttpResponseBodyPart; -import com.ning.http.client.uri.UriComponents; +import java.io.ByteArrayInputStream; import java.io.IOException; +import java.io.InputStream; import java.io.OutputStream; import java.nio.ByteBuffer; @@ -26,13 +26,10 @@ public class ApacheResponseBodyPart extends HttpResponseBodyPart { private final byte[] chunk; - private final boolean isLast; - private boolean closeConnection; - public ApacheResponseBodyPart(UriComponents uri, byte[] chunk, AsyncHttpProvider provider, boolean last) { - super(uri, provider); + public ApacheResponseBodyPart(byte[] chunk, boolean last) { + super(last); this.chunk = chunk; - isLast = last; } /** @@ -56,22 +53,12 @@ public ByteBuffer getBodyByteBuffer() { } @Override - public boolean isLast() { - return isLast; - } - - @Override - public void markUnderlyingConnectionAsClosed() { - closeConnection = true; - } - - @Override - public boolean closeUnderlyingConnection() { - return closeConnection; + public int length() { + return chunk != null ? chunk.length : 0; } @Override - public int length() { - return chunk != null? chunk.length: 0; + public InputStream readBodyPartBytes() { + return chunk != null ? new ByteArrayInputStream(chunk) : null; } } diff --git a/src/main/java/com/ning/http/client/providers/apache/ApacheResponseHeaders.java b/src/main/java/com/ning/http/client/providers/apache/ApacheResponseHeaders.java index c3723acf74..3bfedfa6dd 100644 --- a/src/main/java/com/ning/http/client/providers/apache/ApacheResponseHeaders.java +++ b/src/main/java/com/ning/http/client/providers/apache/ApacheResponseHeaders.java @@ -12,13 +12,12 @@ */ package com.ning.http.client.providers.apache; -import com.ning.http.client.AsyncHttpProvider; -import com.ning.http.client.FluentCaseInsensitiveStringsMap; -import com.ning.http.client.HttpResponseHeaders; -import com.ning.http.client.uri.UriComponents; import org.apache.commons.httpclient.Header; import org.apache.commons.httpclient.HttpMethodBase; +import com.ning.http.client.FluentCaseInsensitiveStringsMap; +import com.ning.http.client.HttpResponseHeaders; + /** * A class that represent the HTTP headers. */ @@ -27,8 +26,8 @@ public class ApacheResponseHeaders extends HttpResponseHeaders { private final HttpMethodBase method; private final FluentCaseInsensitiveStringsMap headers; - public ApacheResponseHeaders(UriComponents uri, HttpMethodBase method, AsyncHttpProvider provider) { - super(uri, provider, false); + public ApacheResponseHeaders(HttpMethodBase method) { + super(false); this.method = method; headers = computerHeaders(); } diff --git a/src/main/java/com/ning/http/client/providers/apache/ApacheResponseStatus.java b/src/main/java/com/ning/http/client/providers/apache/ApacheResponseStatus.java index 7edda57f2e..e7009f56db 100644 --- a/src/main/java/com/ning/http/client/providers/apache/ApacheResponseStatus.java +++ b/src/main/java/com/ning/http/client/providers/apache/ApacheResponseStatus.java @@ -12,11 +12,16 @@ */ package com.ning.http.client.providers.apache; -import com.ning.http.client.AsyncHttpProvider; +import org.apache.commons.httpclient.HttpMethodBase; + +import com.ning.http.client.AsyncHttpClientConfig; +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 com.ning.http.client.uri.UriComponents; -import org.apache.commons.httpclient.HttpMethodBase; +import java.util.List; /** * A class that represent the HTTP response' status line (code + text) @@ -25,8 +30,8 @@ public class ApacheResponseStatus extends HttpResponseStatus { private final HttpMethodBase method; - public ApacheResponseStatus(UriComponents uri, HttpMethodBase method, AsyncHttpProvider provider) { - super(uri, provider); + public ApacheResponseStatus(UriComponents uri, AsyncHttpClientConfig config, HttpMethodBase method) { + super(uri, config); this.method = method; } @@ -68,4 +73,8 @@ public String getProtocolText() { return ""; //TODO } + @Override + public Response prepareResponse(HttpResponseHeaders headers, List bodyParts) { + return new ApacheResponse(this, headers, bodyParts); + } } \ No newline at end of file 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 49e9ec34d7..5350d9b374 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 @@ -22,9 +22,6 @@ import com.ning.http.client.Body; import com.ning.http.client.BodyGenerator; 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.Param; @@ -33,7 +30,6 @@ 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.UpgradeHandler; import com.ning.http.client.cookie.Cookie; import com.ning.http.client.cookie.CookieDecoder; @@ -298,17 +294,6 @@ public void close() { } - - @Override - public Response prepareResponse(HttpResponseStatus status, - HttpResponseHeaders headers, - List bodyParts) { - - return new GrizzlyResponse(status, headers, bodyParts); - - } - - // ------------------------------------------------------- Protected Methods @@ -1181,9 +1166,7 @@ protected void onHttpContentParsed(HttpContent content, try { context.currentState = handler.onBodyPartReceived( new GrizzlyResponseBodyPart(content, - null, - ctx.getConnection(), - provider)); + ctx.getConnection())); } catch (Exception e) { handler.onThrowable(e); } @@ -1274,7 +1257,7 @@ protected void onInitialLineParsed(HttpHeader httpHeader, final GrizzlyResponseStatus responseStatus = new GrizzlyResponseStatus((HttpResponsePacket) httpHeader, context.request.getURI(), - provider); + provider.clientConfig); context.responseStatus = responseStatus; if (context.statusHandler != null) { return; @@ -1342,9 +1325,7 @@ protected void onHttpHeadersParsed(HttpHeader httpHeader, final AsyncHandler handler = context.handler; final List filters = context.provider.clientConfig.getResponseFilters(); - final GrizzlyResponseHeaders responseHeaders = new GrizzlyResponseHeaders((HttpResponsePacket) httpHeader, - context.request.getURI(), - provider); + final GrizzlyResponseHeaders responseHeaders = new GrizzlyResponseHeaders((HttpResponsePacket) httpHeader); if (!filters.isEmpty()) { FilterContext fc = new FilterContext.FilterContextBuilder() .asyncHandler(handler).request(context.request) diff --git a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponseBodyPart.java b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponseBodyPart.java index 6fe3937ef7..6e2548afca 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponseBodyPart.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponseBodyPart.java @@ -13,15 +13,15 @@ package com.ning.http.client.providers.grizzly; -import com.ning.http.client.AsyncHttpProvider; import com.ning.http.client.HttpResponseBodyPart; -import com.ning.http.client.uri.UriComponents; import org.glassfish.grizzly.Buffer; import org.glassfish.grizzly.Connection; import org.glassfish.grizzly.http.HttpContent; +import java.io.ByteArrayInputStream; import java.io.IOException; +import java.io.InputStream; import java.io.OutputStream; import java.nio.ByteBuffer; import java.util.concurrent.atomic.AtomicReference; @@ -47,10 +47,8 @@ public class GrizzlyResponseBodyPart extends HttpResponseBodyPart { public GrizzlyResponseBodyPart(final HttpContent content, - final UriComponents uri, - final Connection connection, - final AsyncHttpProvider provider) { - super(uri, provider); + final Connection connection) { + super(false); this.content = content; this.connection = connection; @@ -102,15 +100,19 @@ public boolean isLast() { } @Override - public void markUnderlyingConnectionAsClosed() { + public void markUnderlyingConnectionAsToBeClosed() { markConnectionAsDoNotCache(connection); } @Override - public boolean closeUnderlyingConnection() { + public boolean isUnderlyingConnectionToBeClosed() { return !isConnectionCacheable(connection); } + @Override + public InputStream readBodyPartBytes() { + return new ByteArrayInputStream(getBodyPartBytes()); + } // ----------------------------------------------- Package Protected Methods diff --git a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponseHeaders.java b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponseHeaders.java index 7027573547..ad78dc3260 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponseHeaders.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponseHeaders.java @@ -13,10 +13,8 @@ package com.ning.http.client.providers.grizzly; -import com.ning.http.client.AsyncHttpProvider; import com.ning.http.client.FluentCaseInsensitiveStringsMap; import com.ning.http.client.HttpResponseHeaders; -import com.ning.http.client.uri.UriComponents; import org.glassfish.grizzly.http.HttpResponsePacket; import org.glassfish.grizzly.http.util.MimeHeaders; @@ -38,11 +36,8 @@ public class GrizzlyResponseHeaders extends HttpResponseHeaders { // ------------------------------------------------------------ Constructors - public GrizzlyResponseHeaders(final HttpResponsePacket response, - final UriComponents uri, - final AsyncHttpProvider provider) { + public GrizzlyResponseHeaders(final HttpResponsePacket response) { - super(uri, provider); this.response = response; } diff --git a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponseStatus.java b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponseStatus.java index 8676cd1f0b..a9684b544c 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponseStatus.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponseStatus.java @@ -13,10 +13,15 @@ package com.ning.http.client.providers.grizzly; -import com.ning.http.client.AsyncHttpProvider; +import com.ning.http.client.AsyncHttpClientConfig; +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 com.ning.http.client.uri.UriComponents; +import java.util.List; + import org.glassfish.grizzly.http.HttpResponsePacket; /** @@ -36,9 +41,9 @@ public class GrizzlyResponseStatus extends HttpResponseStatus { public GrizzlyResponseStatus(final HttpResponsePacket response, final UriComponents uri, - final AsyncHttpProvider provider) { + final AsyncHttpClientConfig config) { - super(uri, provider); + super(uri, config); this.response = response; } @@ -95,4 +100,9 @@ public String getProtocolText() { public HttpResponsePacket getResponse() { return response; } + + @Override + public Response prepareResponse(HttpResponseHeaders headers, List bodyParts) { + return new GrizzlyResponse(this, headers, 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 65a7a59440..65ca37fd58 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 @@ -35,7 +35,6 @@ import java.nio.ByteBuffer; import java.security.GeneralSecurityException; import java.security.NoSuchAlgorithmException; -import java.util.List; import java.util.Map; import java.util.concurrent.Callable; import java.util.concurrent.TimeoutException; @@ -57,9 +56,6 @@ import com.ning.http.client.AsyncHttpProviderConfig; import com.ning.http.client.Body; 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.ProgressAsyncHandler; @@ -67,7 +63,6 @@ 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.cookie.CookieEncoder; import com.ning.http.client.filter.FilterContext; import com.ning.http.client.filter.FilterException; @@ -203,10 +198,6 @@ public void close() { isClose.set(true); } - public Response prepareResponse(HttpResponseStatus status, HttpResponseHeaders headers, List bodyParts) { - return new JDKResponse(status, headers, bodyParts); - } - private final class AsyncHttpUrlConnection implements Callable { private HttpURLConnection urlConnection; @@ -243,7 +234,7 @@ public T call() throws Exception { logger.debug("\n\nRequest {}\n\nResponse {}\n", request, statusCode); - ResponseStatus status = new ResponseStatus(uri, urlConnection, JDKAsyncHttpProvider.this); + ResponseStatus status = new ResponseStatus(uri, config, urlConnection); FilterContext fc = new FilterContext.FilterContextBuilder().asyncHandler(asyncHandler).request(request).responseStatus(status).build(); for (ResponseFilter asyncFilter : config.getResponseFilters()) { fc = asyncFilter.filter(fc); @@ -339,12 +330,12 @@ public T call() throws Exception { byte[] b = new byte[read]; System.arraycopy(bytes, 0, b, 0, read); leftBytes -= read; - asyncHandler.onBodyPartReceived(new ResponseBodyPart(uri, b, JDKAsyncHttpProvider.this, leftBytes > -1)); + asyncHandler.onBodyPartReceived(new ResponseBodyPart(b, leftBytes > -1)); } } if (request.getMethod().equalsIgnoreCase("HEAD")) { - asyncHandler.onBodyPartReceived(new ResponseBodyPart(uri, "".getBytes(), JDKAsyncHttpProvider.this, true)); + asyncHandler.onBodyPartReceived(new ResponseBodyPart("".getBytes(), true)); } } diff --git a/src/main/java/com/ning/http/client/providers/jdk/ResponseBodyPart.java b/src/main/java/com/ning/http/client/providers/jdk/ResponseBodyPart.java index 7410532529..8184d05401 100644 --- a/src/main/java/com/ning/http/client/providers/jdk/ResponseBodyPart.java +++ b/src/main/java/com/ning/http/client/providers/jdk/ResponseBodyPart.java @@ -12,11 +12,11 @@ */ package com.ning.http.client.providers.jdk; -import com.ning.http.client.AsyncHttpProvider; import com.ning.http.client.HttpResponseBodyPart; -import com.ning.http.client.uri.UriComponents; +import java.io.ByteArrayInputStream; import java.io.IOException; +import java.io.InputStream; import java.io.OutputStream; import java.nio.ByteBuffer; @@ -26,13 +26,10 @@ public class ResponseBodyPart extends HttpResponseBodyPart { private final byte[] chunk; - private final boolean isLast; - private boolean closeConnection; - public ResponseBodyPart(UriComponents uri, byte[] chunk, AsyncHttpProvider provider, boolean last) { - super(uri, provider); + public ResponseBodyPart(byte[] chunk, boolean last) { + super(last); this.chunk = chunk; - isLast = last; } /** @@ -56,22 +53,12 @@ public ByteBuffer getBodyByteBuffer() { } @Override - public boolean isLast() { - return isLast; - } - - @Override - public void markUnderlyingConnectionAsClosed() { - closeConnection = true; - } - - @Override - public boolean closeUnderlyingConnection() { - return closeConnection; + public int length() { + return chunk != null? chunk.length: 0; } @Override - public int length() { - return chunk != null? chunk.length: 0; + public InputStream readBodyPartBytes() { + return chunk != null ? new ByteArrayInputStream(chunk) : null; } } diff --git a/src/main/java/com/ning/http/client/providers/jdk/ResponseHeaders.java b/src/main/java/com/ning/http/client/providers/jdk/ResponseHeaders.java index 64c939ccd4..672093beb9 100644 --- a/src/main/java/com/ning/http/client/providers/jdk/ResponseHeaders.java +++ b/src/main/java/com/ning/http/client/providers/jdk/ResponseHeaders.java @@ -26,16 +26,13 @@ */ public class ResponseHeaders extends HttpResponseHeaders { - private final HttpURLConnection urlConnection; private final FluentCaseInsensitiveStringsMap headers; public ResponseHeaders(UriComponents uri, HttpURLConnection urlConnection, AsyncHttpProvider provider) { - super(uri, provider, false); - this.urlConnection = urlConnection; - headers = computerHeaders(); + headers = computerHeaders(urlConnection); } - private FluentCaseInsensitiveStringsMap computerHeaders() { + private FluentCaseInsensitiveStringsMap computerHeaders(HttpURLConnection urlConnection) { FluentCaseInsensitiveStringsMap h = new FluentCaseInsensitiveStringsMap(); Map> uh = urlConnection.getHeaderFields(); @@ -57,4 +54,4 @@ private FluentCaseInsensitiveStringsMap computerHeaders() { public FluentCaseInsensitiveStringsMap getHeaders() { return headers; } -} \ No newline at end of file +} diff --git a/src/main/java/com/ning/http/client/providers/jdk/ResponseStatus.java b/src/main/java/com/ning/http/client/providers/jdk/ResponseStatus.java index 175d25ab28..d9d506e297 100644 --- a/src/main/java/com/ning/http/client/providers/jdk/ResponseStatus.java +++ b/src/main/java/com/ning/http/client/providers/jdk/ResponseStatus.java @@ -12,12 +12,16 @@ */ package com.ning.http.client.providers.jdk; -import com.ning.http.client.AsyncHttpProvider; +import com.ning.http.client.AsyncHttpClientConfig; +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 com.ning.http.client.uri.UriComponents; import java.io.IOException; import java.net.HttpURLConnection; +import java.util.List; /** * A class that represent the HTTP response' status line (code + text) @@ -26,8 +30,8 @@ public class ResponseStatus extends HttpResponseStatus { private final HttpURLConnection urlConnection; - public ResponseStatus(UriComponents uri, HttpURLConnection urlConnection, AsyncHttpProvider provider) { - super(uri, provider); + public ResponseStatus(UriComponents uri, AsyncHttpClientConfig config, HttpURLConnection urlConnection) { + super(uri, config); this.urlConnection = urlConnection; } @@ -77,4 +81,8 @@ public String getProtocolText() { return ""; //TODO } + @Override + public Response prepareResponse(HttpResponseHeaders headers, List bodyParts) { + return new JDKResponse(this, headers, bodyParts); + } } \ No newline at end of file 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 4e9afdc422..262cfa8934 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 @@ -106,7 +106,6 @@ 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.cookie.CookieDecoder; import com.ning.http.client.cookie.CookieEncoder; import com.ning.http.client.filter.FilterContext; @@ -132,7 +131,6 @@ import com.ning.http.client.providers.netty.request.timeout.ReadTimeoutTimerTask; import com.ning.http.client.providers.netty.request.timeout.RequestTimeoutTimerTask; import com.ning.http.client.providers.netty.request.timeout.TimeoutsHolder; -import com.ning.http.client.providers.netty.response.NettyResponse; import com.ning.http.client.providers.netty.response.ResponseBodyPart; import com.ning.http.client.providers.netty.response.ResponseHeaders; import com.ning.http.client.providers.netty.response.ResponseStatus; @@ -777,12 +775,6 @@ public void close() { } } - @Override - public Response prepareResponse(final HttpResponseStatus status, final HttpResponseHeaders headers, - final List bodyParts) { - return new NettyResponse(status, headers, bodyParts); - } - @Override public ListenableFuture execute(Request request, final AsyncHandler asyncHandler) throws IOException { return doConnect(request, asyncHandler, null, true, false); @@ -1316,7 +1308,7 @@ private final boolean updateHeadersAndInterrupt(AsyncHandler handler, HttpRes private final boolean updateBodyAndInterrupt(final NettyResponseFuture future, AsyncHandler handler, HttpResponseBodyPart c) throws Exception { boolean state = handler.onBodyPartReceived(c) != STATE.CONTINUE; - if (c.closeUnderlyingConnection()) + if (c.isUnderlyingConnectionToBeClosed()) future.setKeepAlive(false); return state; } @@ -1813,7 +1805,7 @@ private final boolean exitAfterHandlingHeaders(Channel channel, NettyResponseFut private final boolean exitAfterHandlingBody(Channel channel, NettyResponseFuture future, HttpResponse response, AsyncHandler handler) throws Exception { if (!response.isChunked()) { - updateBodyAndInterrupt(future, handler, new ResponseBodyPart(future.getURI(), response, NettyAsyncHttpProvider.this, true)); + updateBodyAndInterrupt(future, handler, new ResponseBodyPart(response, null, true)); finishUpdate(future, channel, false); return true; } @@ -1823,7 +1815,7 @@ private final boolean exitAfterHandlingBody(Channel channel, NettyResponseFuture private final boolean exitAfterHandlingHead(Channel channel, NettyResponseFuture future, HttpResponse response, AsyncHandler handler, HttpRequest nettyRequest) throws Exception { if (nettyRequest.getMethod().equals(HttpMethod.HEAD)) { - updateBodyAndInterrupt(future, handler, new ResponseBodyPart(future.getURI(), response, NettyAsyncHttpProvider.this, true)); + updateBodyAndInterrupt(future, handler, new ResponseBodyPart(response, null, true)); markAsDone(future, channel); drainChannel(channel, future); } @@ -1843,8 +1835,8 @@ private final void handleHttpResponse(final HttpResponse response, final Channel configureKeepAlive(future, response); - HttpResponseStatus status = new ResponseStatus(future.getURI(), response, NettyAsyncHttpProvider.this); - HttpResponseHeaders responseHeaders = new ResponseHeaders(future.getURI(), response, NettyAsyncHttpProvider.this); + HttpResponseStatus status = new ResponseStatus(future.getURI(), config, response); + HttpResponseHeaders responseHeaders = new ResponseHeaders(response); if (exitAfterProcessingFilters(channel, future, response, handler, request, status, responseHeaders)) return; @@ -1873,12 +1865,12 @@ private final void handleChunk(final HttpChunk chunk, final Channel channel, fin final AsyncHandler handler) throws Exception { boolean last = chunk.isLast(); // we don't notify updateBodyAndInterrupt with the last chunk as it's empty - if (last || updateBodyAndInterrupt(future, handler, new ResponseBodyPart(future.getURI(), null, this, chunk, last))) { + if (last || updateBodyAndInterrupt(future, handler, new ResponseBodyPart(null, chunk, last))) { if (chunk instanceof HttpChunkTrailer) { HttpChunkTrailer chunkTrailer = (HttpChunkTrailer) chunk; if (!chunkTrailer.trailingHeaders().isEmpty()) { - ResponseHeaders responseHeaders = new ResponseHeaders(future.getURI(), future.getHttpResponse(), this, chunkTrailer); + ResponseHeaders responseHeaders = new ResponseHeaders(future.getHttpResponse(), chunkTrailer); updateHeadersAndInterrupt(handler, responseHeaders); } } @@ -1962,8 +1954,8 @@ public void handle(Channel channel, MessageEvent e, final NettyResponseFuture fu HttpResponse response = (HttpResponse) e.getMessage(); HttpHeaders nettyResponseHeaders = response.headers(); - HttpResponseStatus s = new ResponseStatus(future.getURI(), response, NettyAsyncHttpProvider.this); - HttpResponseHeaders responseHeaders = new ResponseHeaders(future.getURI(), response, NettyAsyncHttpProvider.this); + HttpResponseStatus s = new ResponseStatus(future.getURI(), config, response); + HttpResponseHeaders responseHeaders = new ResponseHeaders(response); FilterContext fc = new FilterContext.FilterContextBuilder().asyncHandler(wsUpgradeHandler).request(request) .responseStatus(s).responseHeaders(responseHeaders).build(); for (ResponseFilter asyncFilter : config.getResponseFilters()) { @@ -2002,7 +1994,7 @@ public void handle(Channel channel, MessageEvent e, final NettyResponseFuture fu final boolean validConnection = c == null ? false : c.equalsIgnoreCase(HttpHeaders.Values.UPGRADE); - s = new ResponseStatus(future.getURI(), response, NettyAsyncHttpProvider.this); + s = new ResponseStatus(future.getURI(), config, response); final boolean statusReceived = wsUpgradeHandler.onStatusReceived(s) == STATE.UPGRADE; if (!statusReceived) { @@ -2066,7 +2058,7 @@ public void setContent(ChannelBuffer content) { if (frame.getBinaryData() != null) { webSocketChunk.setContent(ChannelBuffers.wrappedBuffer(frame.getBinaryData())); - ResponseBodyPart rp = new ResponseBodyPart(future.getURI(), null, NettyAsyncHttpProvider.this, webSocketChunk, true); + ResponseBodyPart rp = new ResponseBodyPart(null, webSocketChunk, true); wsUpgradeHandler.onBodyPartReceived(rp); NettyWebSocket webSocket = NettyWebSocket.class.cast(wsUpgradeHandler.onCompleted()); diff --git a/src/main/java/com/ning/http/client/providers/netty/response/ResponseBodyPart.java b/src/main/java/com/ning/http/client/providers/netty/response/ResponseBodyPart.java index fc4049f154..ecbb1ea327 100644 --- a/src/main/java/com/ning/http/client/providers/netty/response/ResponseBodyPart.java +++ b/src/main/java/com/ning/http/client/providers/netty/response/ResponseBodyPart.java @@ -15,19 +15,18 @@ */ package com.ning.http.client.providers.netty.response; -import com.ning.http.client.AsyncHttpProvider; import com.ning.http.client.HttpResponseBodyPart; import com.ning.http.client.providers.netty.util.ChannelBufferUtil; -import com.ning.http.client.uri.UriComponents; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.handler.codec.http.HttpChunk; import org.jboss.netty.handler.codec.http.HttpResponse; +import java.io.ByteArrayInputStream; import java.io.IOException; +import java.io.InputStream; import java.io.OutputStream; import java.nio.ByteBuffer; -import java.util.concurrent.atomic.AtomicReference; /** * A callback class used when an HTTP response body is received. @@ -35,20 +34,17 @@ public class ResponseBodyPart extends HttpResponseBodyPart { private final ChannelBuffer content; - private final AtomicReference bytes = new AtomicReference(null); - private final boolean isLast; + private volatile byte[] bytes; private final int length; - private boolean closeConnection = false; - public ResponseBodyPart(UriComponents uri, HttpResponse response, AsyncHttpProvider provider, boolean last) { - this(uri, response, provider, null, last); + public ResponseBodyPart(HttpResponse response, boolean last) { + this(response, null, last); } - public ResponseBodyPart(UriComponents uri, HttpResponse response, AsyncHttpProvider provider, HttpChunk chunk, boolean last) { - super(uri, provider); + public ResponseBodyPart(HttpResponse response, HttpChunk chunk, boolean last) { + super(last); content = chunk != null ? chunk.getContent() : response.getContent(); length = content.readableBytes(); - isLast = last; } /** @@ -57,14 +53,9 @@ public ResponseBodyPart(UriComponents uri, HttpResponse response, AsyncHttpProvi * @return the response body's part bytes received. */ public byte[] getBodyPartBytes() { - - if (bytes.get() != null) { - return bytes.get(); - } - - byte[] b = ChannelBufferUtil.channelBuffer2bytes(content); - bytes.set(b); - return b; + if (bytes == null) + bytes = ChannelBufferUtil.channelBuffer2bytes(content); + return bytes; } public int writeTo(OutputStream outputStream) throws IOException { @@ -88,22 +79,12 @@ public ByteBuffer getBodyByteBuffer() { } @Override - public boolean isLast() { - return isLast; - } - - @Override - public void markUnderlyingConnectionAsClosed() { - closeConnection = true; - } - - @Override - public boolean closeUnderlyingConnection() { - return closeConnection; + public int length() { + return length; } @Override - public int length() { - return length; + public InputStream readBodyPartBytes() { + return new ByteArrayInputStream(getBodyPartBytes()); } } diff --git a/src/main/java/com/ning/http/client/providers/netty/response/ResponseHeaders.java b/src/main/java/com/ning/http/client/providers/netty/response/ResponseHeaders.java index 5b2e9ab271..597e72c018 100644 --- a/src/main/java/com/ning/http/client/providers/netty/response/ResponseHeaders.java +++ b/src/main/java/com/ning/http/client/providers/netty/response/ResponseHeaders.java @@ -15,14 +15,12 @@ */ package com.ning.http.client.providers.netty.response; -import com.ning.http.client.AsyncHttpProvider; -import com.ning.http.client.FluentCaseInsensitiveStringsMap; -import com.ning.http.client.HttpResponseHeaders; -import com.ning.http.client.uri.UriComponents; - import org.jboss.netty.handler.codec.http.HttpChunkTrailer; import org.jboss.netty.handler.codec.http.HttpResponse; +import com.ning.http.client.FluentCaseInsensitiveStringsMap; +import com.ning.http.client.HttpResponseHeaders; + import java.util.Map; /** @@ -34,15 +32,15 @@ public class ResponseHeaders extends HttpResponseHeaders { private final HttpResponse response; private final FluentCaseInsensitiveStringsMap headers; - public ResponseHeaders(UriComponents uri, HttpResponse response, AsyncHttpProvider provider) { - super(uri, provider, false); + public ResponseHeaders(HttpResponse response) { + super(false); this.trailingHeaders = null; this.response = response; headers = computerHeaders(); } - public ResponseHeaders(UriComponents uri, HttpResponse response, AsyncHttpProvider provider, HttpChunkTrailer traillingHeaders) { - super(uri, provider, true); + public ResponseHeaders(HttpResponse response, HttpChunkTrailer traillingHeaders) { + super(true); this.trailingHeaders = traillingHeaders; this.response = response; headers = computerHeaders(); @@ -50,12 +48,12 @@ public ResponseHeaders(UriComponents uri, HttpResponse response, AsyncHttpProvid private FluentCaseInsensitiveStringsMap computerHeaders() { FluentCaseInsensitiveStringsMap h = new FluentCaseInsensitiveStringsMap(); - for (Map.Entry header: response.getHeaders()) { - h.add(header.getKey(), header.getValue()); + for (Map.Entry header : response.headers()) { + h.add(header.getKey(), header.getValue()); } if (trailingHeaders != null) { - for (Map.Entry header: trailingHeaders.getHeaders()) { + for (Map.Entry header : trailingHeaders.trailingHeaders()) { h.add(header.getKey(), header.getValue()); } } diff --git a/src/main/java/com/ning/http/client/providers/netty/response/ResponseStatus.java b/src/main/java/com/ning/http/client/providers/netty/response/ResponseStatus.java index 67452cfe83..075b7bc3bb 100644 --- a/src/main/java/com/ning/http/client/providers/netty/response/ResponseStatus.java +++ b/src/main/java/com/ning/http/client/providers/netty/response/ResponseStatus.java @@ -16,10 +16,15 @@ */ package com.ning.http.client.providers.netty.response; -import com.ning.http.client.AsyncHttpProvider; +import com.ning.http.client.AsyncHttpClientConfig; +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 com.ning.http.client.uri.UriComponents; +import java.util.List; + import org.jboss.netty.handler.codec.http.HttpResponse; /** @@ -29,8 +34,8 @@ public class ResponseStatus extends HttpResponseStatus { private final HttpResponse response; - public ResponseStatus(UriComponents uri, HttpResponse response, AsyncHttpProvider provider) { - super(uri, provider); + public ResponseStatus(UriComponents uri, AsyncHttpClientConfig config, HttpResponse response) { + super(uri, config); this.response = response; } @@ -72,4 +77,8 @@ public String getProtocolText() { return response.getProtocolVersion().getText(); } + @Override + public Response prepareResponse(HttpResponseHeaders headers, List bodyParts) { + return new NettyResponse(this, headers, bodyParts); + } } 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 809e7ba4ad..e766755047 100644 --- a/src/main/java/com/ning/http/client/webdav/WebDavCompletionHandlerBase.java +++ b/src/main/java/com/ning/http/client/webdav/WebDavCompletionHandlerBase.java @@ -69,12 +69,12 @@ public final STATE onHeadersReceived(final HttpResponseHeaders headers) throws E @Override public final T onCompleted() throws Exception { if (status != null) { - Response response = status.provider().prepareResponse(status, headers, bodies); + Response response = status.prepareResponse(headers, bodies); Document document = null; if (status.getStatusCode() == 207) { document = readXMLResponse(response.getResponseBodyAsStream()); } - return onCompleted(new WebDavResponse(status.provider().prepareResponse(status, headers, bodies), document)); + return onCompleted(new WebDavResponse(status.prepareResponse(headers, bodies), document)); } else { throw new IllegalStateException("Status is null"); } @@ -103,7 +103,7 @@ private class HttpStatusWrapper extends HttpResponseStatus { private final int statusCode; public HttpStatusWrapper(HttpResponseStatus wrapper, String statusText, int statusCode) { - super(wrapper.getUri(), wrapper.provider()); + super(wrapper.getUri(), wrapper.getConfig()); this.wrapper = wrapper; this.statusText = statusText; this.statusCode = statusCode; @@ -138,6 +138,11 @@ public int getProtocolMinorVersion() { public String getProtocolText() { return wrapper.getStatusText(); } + + @Override + public Response prepareResponse(HttpResponseHeaders headers, List bodyParts) { + return wrapper.prepareResponse(headers, bodyParts); + } } private Document readXMLResponse(InputStream stream) { 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 4072be94a3..2a5a79e6f2 100644 --- a/src/test/java/com/ning/http/client/async/AsyncStreamHandlerTest.java +++ b/src/test/java/com/ning/http/client/async/AsyncStreamHandlerTest.java @@ -533,7 +533,7 @@ public STATE onBodyPartReceived(HttpResponseBodyPart content) throws Exception { builder.accumulate(content); if (content.isLast()) { - content.closeUnderlyingConnection(); + content.markUnderlyingConnectionAsToBeClosed(); } return STATE.CONTINUE; } 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 1b340032e8..037ce12076 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 @@ -43,7 +43,7 @@ public void testCookieParseExpires() { 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) { + NettyResponse response = new NettyResponse(new ResponseStatus(null, null, null), new HttpResponseHeaders(false) { @Override public FluentCaseInsensitiveStringsMap getHeaders() { return new FluentCaseInsensitiveStringsMap().add("Set-Cookie", cookieDef); @@ -61,7 +61,7 @@ public FluentCaseInsensitiveStringsMap getHeaders() { @Test(groups = "standalone") public void testCookieParseMaxAge() { final String cookieDef = "efmembercheck=true; max-age=60; path=/; domain=.eclipse.org"; - NettyResponse response = new NettyResponse(new ResponseStatus(null, null, null), new HttpResponseHeaders(null, null, false) { + NettyResponse response = new NettyResponse(new ResponseStatus(null, null, null), new HttpResponseHeaders(false) { @Override public FluentCaseInsensitiveStringsMap getHeaders() { return new FluentCaseInsensitiveStringsMap().add("Set-Cookie", cookieDef); @@ -77,7 +77,7 @@ public FluentCaseInsensitiveStringsMap getHeaders() { @Test(groups = "standalone") public void testCookieParseWeirdExpiresValue() { final String cookieDef = "efmembercheck=true; expires=60; path=/; domain=.eclipse.org"; - NettyResponse response = new NettyResponse(new ResponseStatus(null, null, null), new HttpResponseHeaders(null, null, false) { + NettyResponse response = new NettyResponse(new ResponseStatus(null, null, null), new HttpResponseHeaders(false) { @Override public FluentCaseInsensitiveStringsMap getHeaders() { return new FluentCaseInsensitiveStringsMap().add("Set-Cookie", cookieDef); From a0cf94867cbc393ca68febaaa4bc483977565859 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 22 Jul 2014 12:18:08 +0200 Subject: [PATCH 458/701] Refactor Response implementations duplicated code into ResponseBase, close #642 --- .../com/ning/http/client/ResponseBase.java | 128 +++++++++++++++ .../providers/apache/ApacheResponse.java | 146 ++++-------------- .../providers/grizzly/GrizzlyResponse.java | 146 ++---------------- .../client/providers/jdk/JDKResponse.java | 145 ++++------------- .../netty/response/NettyResponse.java | 124 +++------------ 5 files changed, 220 insertions(+), 469 deletions(-) create mode 100644 src/main/java/com/ning/http/client/ResponseBase.java diff --git a/src/main/java/com/ning/http/client/ResponseBase.java b/src/main/java/com/ning/http/client/ResponseBase.java new file mode 100644 index 0000000000..9f578f8b55 --- /dev/null +++ b/src/main/java/com/ning/http/client/ResponseBase.java @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2014 AsyncHttpClient Project. 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; + +import static com.ning.http.util.MiscUtils.isNonEmpty; + +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.Response; +import com.ning.http.client.cookie.Cookie; +import com.ning.http.client.uri.UriComponents; +import com.ning.http.util.AsyncHttpProviderUtils; + +import java.util.Collections; +import java.util.List; + +public abstract class ResponseBase implements Response { + + protected final static String DEFAULT_CHARSET = "ISO-8859-1"; + + protected final HttpResponseStatus status; + protected final HttpResponseHeaders headers; + protected final List bodyParts; + private List cookies; + + protected ResponseBase(HttpResponseStatus status, HttpResponseHeaders headers, List bodyParts) { + this.bodyParts = bodyParts; + this.headers = headers; + this.status = status; + } + + protected abstract List buildCookies(); + + protected String calculateCharset(String charset) { + + if (charset == null) { + String contentType = getContentType(); + if (contentType != null) + charset = AsyncHttpProviderUtils.parseCharset(contentType); // parseCharset can return null + } + return charset != null ? charset : DEFAULT_CHARSET; + } + + @Override + public final int getStatusCode() { + return status.getStatusCode(); + } + + @Override + public final String getStatusText() { + return status.getStatusText(); + } + + @Override + public final UriComponents getUri() { + return status.getUri(); + } + + @Override + public final String getContentType() { + return headers != null ? getHeader("Content-Type") : null; + } + + @Override + public final String getHeader(String name) { + return headers != null ? getHeaders().getFirstValue(name) : null; + } + + @Override + public final List getHeaders(String name) { + return headers != null ? getHeaders().get(name) : null; + } + + @Override + public final FluentCaseInsensitiveStringsMap getHeaders() { + return headers != null ? headers.getHeaders() : new FluentCaseInsensitiveStringsMap(); + } + + @Override + public final boolean isRedirected() { + switch (status.getStatusCode()) { + case 301: + case 302: + case 303: + case 307: + case 308: + return true; + default: + return false; + } + } + + @Override + public List getCookies() { + if (cookies == null) + cookies = headers != null ? buildCookies() : Collections. emptyList(); + return cookies; + + } + + @Override + public boolean hasResponseStatus() { + return status != null; + } + + @Override + public boolean hasResponseHeaders() { + return headers != null && isNonEmpty(headers.getHeaders()); + } + + @Override + public boolean hasResponseBody() { + return isNonEmpty(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 c9378c0b82..bd2c43f675 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,55 +12,25 @@ */ package com.ning.http.client.providers.apache; -import static com.ning.http.util.MiscUtils.isNonEmpty; - -import java.io.IOException; -import java.io.InputStream; -import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; - -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.Response; +import com.ning.http.client.ResponseBase; import com.ning.http.client.cookie.Cookie; import com.ning.http.client.cookie.CookieDecoder; -import com.ning.http.client.uri.UriComponents; import com.ning.http.util.AsyncHttpProviderUtils; -import com.ning.http.util.StandardCharsets; - -public class ApacheResponse implements Response { - private final static String DEFAULT_CHARSET = StandardCharsets.ISO_8859_1.name(); - - private final UriComponents uri; - private final List bodyParts; - private final HttpResponseHeaders headers; - private final HttpResponseStatus status; - private List cookies; - - public ApacheResponse(HttpResponseStatus status, - HttpResponseHeaders headers, - List bodyParts) { - this.bodyParts = bodyParts; - this.headers = headers; - this.status = status; - - uri = this.status.getUri(); - } +import java.io.IOException; +import java.io.InputStream; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; - @Override - public int getStatusCode() { - return status.getStatusCode(); - } +public class ApacheResponse extends ResponseBase { - @Override - public String getStatusText() { - return status.getStatusText(); + public ApacheResponse(HttpResponseStatus status, HttpResponseHeaders headers, List bodyParts) { + super(status, headers, bodyParts); } @Override @@ -68,6 +38,7 @@ public byte[] getResponseBodyAsBytes() throws IOException { return AsyncHttpProviderUtils.contentToByte(bodyParts); } + @Override public ByteBuffer getResponseBodyAsByteBuffer() throws IOException { return ByteBuffer.wrap(getResponseBodyAsBytes()); } @@ -77,13 +48,14 @@ public String getResponseBody() throws IOException { return getResponseBody(DEFAULT_CHARSET); } + @Override public String getResponseBody(String charset) throws IOException { return AsyncHttpProviderUtils.contentToString(bodyParts, computeCharset(charset)); } - + @Override public InputStream getResponseBodyAsStream() throws IOException { - return AsyncHttpProviderUtils.contentToInputStream(bodyParts); + return AsyncHttpProviderUtils.contentToInputStream(bodyParts); } @Override @@ -98,89 +70,29 @@ public String getResponseBodyExcerpt(int maxLength, String charset) throws IOExc String response = AsyncHttpProviderUtils.contentToString(bodyParts, charset); return response.length() <= maxLength ? response : response.substring(0, maxLength); } - + private String 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 : DEFAULT_CHARSET; } @Override - public UriComponents getUri() { - return uri; - } - - @Override - public String getContentType() { - return getHeader("Content-Type"); - } - - @Override - public String getHeader(String name) { - return headers != null? headers.getHeaders().getFirstValue(name): null; - } - - @Override - public List getHeaders(String name) { - return headers != null? headers.getHeaders().get(name): Collections. emptyList(); - } - - @Override - public FluentCaseInsensitiveStringsMap getHeaders() { - return headers != null? headers.getHeaders(): new FluentCaseInsensitiveStringsMap(); - } - - @Override - public boolean isRedirected() { - switch (status.getStatusCode()) { - case 301: - case 302: - case 303: - case 307: - case 308: - return true; - default: - return false; - } - } - - @Override - public List getCookies() { - if (headers == null) { - return Collections.emptyList(); - } - 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 = CookieDecoder.decode(value); - localCookies.add(cookie); - } + protected List buildCookies() { + 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 = CookieDecoder.decode(value); + localCookies.add(cookie); } } - cookies = Collections.unmodifiableList(localCookies); } - return cookies; - } - - @Override - public boolean hasResponseStatus() { - return bodyParts != null; - } - - @Override - public boolean hasResponseHeaders() { - return headers != null; - } - - @Override - public boolean hasResponseBody() { - return isNonEmpty(bodyParts); + return localCookies; } } 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 19f3fa0cdd..77e0ec675c 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 @@ -20,7 +20,6 @@ import java.nio.ByteBuffer; import java.nio.charset.Charset; import java.util.ArrayList; -import java.util.Collection; import java.util.Collections; import java.util.List; @@ -32,13 +31,11 @@ import org.glassfish.grizzly.utils.BufferInputStream; import org.glassfish.grizzly.utils.Charsets; -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.Response; +import com.ning.http.client.ResponseBase; import com.ning.http.client.cookie.Cookie; -import com.ning.http.client.uri.UriComponents; import com.ning.http.util.AsyncHttpProviderUtils; /** @@ -48,15 +45,10 @@ * @author The Grizzly Team * @since 1.7.0 */ -public class GrizzlyResponse implements Response { +public class GrizzlyResponse extends ResponseBase { - private final HttpResponseStatus status; - private final HttpResponseHeaders headers; - private final Collection bodyParts; private final Buffer responseBody; - private List cookies; - // ------------------------------------------------------------ Constructors @@ -65,9 +57,7 @@ public GrizzlyResponse(final HttpResponseStatus status, final HttpResponseHeaders headers, final List bodyParts) { - this.status = status; - this.headers = headers; - this.bodyParts = bodyParts; + super(status, headers, bodyParts); if (isNonEmpty(bodyParts)) { if (bodyParts.size() == 1) { @@ -94,22 +84,6 @@ public GrizzlyResponse(final HttpResponseStatus status, // --------------------------------------------------- Methods from Response - @Override - public int getStatusCode() { - - return status.getStatusCode(); - - } - - - @Override - public String getStatusText() { - - return status.getStatusText(); - - } - - @Override public InputStream getResponseBodyAsStream() throws IOException { @@ -167,116 +141,22 @@ public ByteBuffer getResponseBodyAsByteBuffer() throws IOException { return responseBody.toByteBuffer(); } - /** - * @return the response body as a Grizzly {@link Buffer}. - * - * @since 1.7.11. - */ - @SuppressWarnings("UnusedDeclaration") - private Buffer getResponseBodyAsBuffer() { - return responseBody; - } - - @Override - public UriComponents getUri() { - - return status.getUri(); - - } - - - @Override - public String getContentType() { - - return headers.getHeaders().getFirstValue("Content-Type"); - - } - - - @Override - public String getHeader(String name) { - - return headers.getHeaders().getFirstValue(name); - - } - - - @Override - public List getHeaders(String name) { - - return headers.getHeaders().get(name); - - } - - - @Override - public FluentCaseInsensitiveStringsMap getHeaders() { - - return headers.getHeaders(); - - } - - - @Override - public boolean isRedirected() { - switch (status.getStatusCode()) { - case 301: - case 302: - case 303: - case 307: - case 308: - return true; - default: - return false; - } - } - - - @Override - public List getCookies() { + protected List buildCookies() { + List values = headers.getHeaders().get("set-cookie"); + if (isNonEmpty(values)) { + CookiesBuilder.ServerCookiesBuilder builder = + new CookiesBuilder.ServerCookiesBuilder(false, true); + for (String header : values) { + builder.parse(header); + } + return convertCookies(builder.build()); - if (headers == null) { + } else { return Collections.emptyList(); } - - if (cookies == null) { - List values = headers.getHeaders().get("set-cookie"); - if (isNonEmpty(values)) { - CookiesBuilder.ServerCookiesBuilder builder = - new CookiesBuilder.ServerCookiesBuilder(false, true); - for (String header : values) { - builder.parse(header); - } - cookies = convertCookies(builder.build()); - - } else { - cookies = Collections.emptyList(); - } - } - return cookies; - - } - - - @Override - public boolean hasResponseStatus() { - return (status != null); } - - @Override - public boolean hasResponseHeaders() { - return headers != null && !headers.getHeaders().isEmpty(); - } - - - @Override - public boolean hasResponseBody() { - return isNonEmpty(bodyParts); - } - - // --------------------------------------------------------- Private Methods 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 8cca8c09e9..7f33e7da32 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,60 +12,30 @@ */ package com.ning.http.client.providers.jdk; -import static com.ning.http.util.MiscUtils.isNonEmpty; +import com.ning.http.client.HttpResponseBodyPart; +import com.ning.http.client.HttpResponseHeaders; +import com.ning.http.client.HttpResponseStatus; +import com.ning.http.client.ResponseBase; +import com.ning.http.client.cookie.Cookie; +import com.ning.http.client.cookie.CookieDecoder; +import com.ning.http.util.AsyncHttpProviderUtils; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.nio.ByteBuffer; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicBoolean; -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.Response; -import com.ning.http.client.cookie.Cookie; -import com.ning.http.client.cookie.CookieDecoder; -import com.ning.http.client.uri.UriComponents; -import com.ning.http.util.AsyncHttpProviderUtils; -import com.ning.http.util.StandardCharsets; +public class JDKResponse extends ResponseBase { - -public class JDKResponse implements Response { - private final static String DEFAULT_CHARSET = StandardCharsets.ISO_8859_1.name(); - - private final UriComponents uri; - private final List bodyParts; - private final HttpResponseHeaders headers; - private final HttpResponseStatus status; - private List cookies; private AtomicBoolean contentComputed = new AtomicBoolean(false); private String content; - public JDKResponse(HttpResponseStatus status, - HttpResponseHeaders headers, - List bodyParts) { - - this.bodyParts = bodyParts; - this.headers = headers; - this.status = status; - - uri = this.status.getUri(); - } - - @Override - public int getStatusCode() { - return status.getStatusCode(); - } - - @Override - public String getStatusText() { - return status.getStatusText(); + public JDKResponse(HttpResponseStatus status, HttpResponseHeaders headers, List bodyParts) { + super(status, headers, bodyParts); } @Override @@ -78,18 +48,20 @@ public byte[] getResponseBodyAsBytes() throws IOException { return AsyncHttpProviderUtils.contentToByte(bodyParts); } + @Override public ByteBuffer getResponseBodyAsByteBuffer() throws IOException { return ByteBuffer.wrap(getResponseBodyAsBytes()); } + @Override public String getResponseBody(String charset) throws IOException { - if (!contentComputed.get()) { + if (!contentComputed.get()) { content = AsyncHttpProviderUtils.contentToString(bodyParts, computeCharset(charset)); } return content; } - + @Override public InputStream getResponseBodyAsStream() throws IOException { if (contentComputed.get()) { @@ -104,6 +76,7 @@ public String getResponseBodyExcerpt(int maxLength) throws IOException { return getResponseBodyExcerpt(maxLength, DEFAULT_CHARSET); } + @Override public String getResponseBodyExcerpt(int maxLength, String charset) throws IOException { charset = computeCharset(charset); @@ -113,88 +86,28 @@ public String getResponseBodyExcerpt(int maxLength, String charset) throws IOExc return content.length() <= maxLength ? content : content.substring(0, maxLength); } - + private String 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 : DEFAULT_CHARSET; } @Override - public UriComponents getUri() { - return uri; - } - - @Override - public String getContentType() { - return getHeader("Content-Type"); - } - - @Override - public String getHeader(String name) { - return headers != null? headers.getHeaders().getFirstValue(name): null; - } - - @Override - public List getHeaders(String name) { - return headers != null? headers.getHeaders().get(name): Collections. emptyList(); - } - - @Override - public FluentCaseInsensitiveStringsMap getHeaders() { - return headers != null? headers.getHeaders(): new FluentCaseInsensitiveStringsMap(); - } - - @Override - public boolean isRedirected() { - switch (status.getStatusCode()) { - case 301: - case 302: - case 303: - case 307: - case 308: - return true; - default: - return false; - } - } - - @Override - public List getCookies() { - if (headers == null) { - return Collections.emptyList(); - } - if (!isNonEmpty(cookies)) { - 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) { - localCookies.add(CookieDecoder.decode(value)); - } + protected List buildCookies() { + 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) { + localCookies.add(CookieDecoder.decode(value)); } } - cookies = Collections.unmodifiableList(localCookies); } - return cookies; - } - - @Override - public boolean hasResponseStatus() { - return bodyParts != null; - } - - @Override - public boolean hasResponseHeaders() { - return headers != null; - } - - @Override - public boolean hasResponseBody() { - return isNonEmpty(bodyParts); + return localCookies; } } diff --git a/src/main/java/com/ning/http/client/providers/netty/response/NettyResponse.java b/src/main/java/com/ning/http/client/providers/netty/response/NettyResponse.java index 78a8d30f45..60e17c1311 100644 --- a/src/main/java/com/ning/http/client/providers/netty/response/NettyResponse.java +++ b/src/main/java/com/ning/http/client/providers/netty/response/NettyResponse.java @@ -15,61 +15,39 @@ */ package com.ning.http.client.providers.netty.response; -import static com.ning.http.util.MiscUtils.isNonEmpty; - -import java.io.IOException; -import java.io.InputStream; -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; +import org.jboss.netty.handler.codec.http.HttpHeaders; -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.Response; +import com.ning.http.client.ResponseBase; import com.ning.http.client.cookie.Cookie; import com.ning.http.client.cookie.CookieDecoder; import com.ning.http.client.providers.netty.util.ChannelBufferUtil; -import com.ning.http.client.uri.UriComponents; import com.ning.http.util.AsyncHttpProviderUtils; -import com.ning.http.util.StandardCharsets; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.ByteBuffer; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; /** * Wrapper around the {@link com.ning.http.client.Response} API. */ -public class NettyResponse implements Response { - private final static Charset DEFAULT_CHARSET = StandardCharsets.ISO_8859_1; - - private final List bodyParts; - private final HttpResponseHeaders headers; - private final HttpResponseStatus status; - private List cookies; +public class NettyResponse extends ResponseBase { public NettyResponse(HttpResponseStatus status, HttpResponseHeaders headers, List bodyParts) { - this.status = status; - this.headers = headers; - this.bodyParts = bodyParts; - } - - @Override - public int getStatusCode() { - return status.getStatusCode(); - } - - @Override - public String getStatusText() { - return status.getStatusText(); + super(status, headers, bodyParts); } @Override @@ -132,81 +110,21 @@ private Charset computeCharset(String charset) { if (contentType != null) charset = AsyncHttpProviderUtils.parseCharset(contentType); // parseCharset can return null } - return charset != null ? Charset.forName(charset) : DEFAULT_CHARSET; - } - - @Override - public UriComponents getUri() { - return status.getUri(); + return charset != null ? Charset.forName(charset) : Charset.forName(DEFAULT_CHARSET); } @Override - public String getContentType() { - return getHeader("Content-Type"); - } - - @Override - public String getHeader(String name) { - return headers != null ? headers.getHeaders().getFirstValue(name) : null; - } - - @Override - public List getHeaders(String name) { - return headers != null ? headers.getHeaders().get(name) : Collections. emptyList(); - } - - @Override - public FluentCaseInsensitiveStringsMap getHeaders() { - return headers != null ? headers.getHeaders() : new FluentCaseInsensitiveStringsMap(); - } - - @Override - public boolean isRedirected() { - switch (status.getStatusCode()) { - case 301: - case 302: - case 303: - case 307: - case 308: - return true; - default: - return false; - } - } - - @Override - public List getCookies() { - if (headers == null) { - return Collections.emptyList(); - } - 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) { - localCookies.add(CookieDecoder.decode(value)); - } + protected List buildCookies() { + List cookies = new ArrayList(); + for (Map.Entry> header : headers.getHeaders().entrySet()) { + if (header.getKey().equalsIgnoreCase(HttpHeaders.Names.SET_COOKIE)) { + // TODO: ask for parsed header + List v = header.getValue(); + for (String value : v) { + cookies.add(CookieDecoder.decode(value)); } } - cookies = Collections.unmodifiableList(localCookies); } return cookies; } - - @Override - public boolean hasResponseStatus() { - return status != null; - } - - @Override - public boolean hasResponseHeaders() { - return headers != null; - } - - @Override - public boolean hasResponseBody() { - return isNonEmpty(bodyParts); - } } From 7dd2d60b7fb58f17cf8f6354db47ff1d7b5163cb Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 22 Jul 2014 12:29:16 +0200 Subject: [PATCH 459/701] ResponseBase.calculateCharset returns a Charset --- .../com/ning/http/client/ResponseBase.java | 12 +++-------- .../providers/apache/ApacheResponse.java | 19 ++++-------------- .../client/providers/jdk/JDKResponse.java | 20 +++++-------------- .../netty/response/NettyResponse.java | 11 +--------- .../http/util/AsyncHttpProviderUtils.java | 2 +- 5 files changed, 14 insertions(+), 50 deletions(-) diff --git a/src/main/java/com/ning/http/client/ResponseBase.java b/src/main/java/com/ning/http/client/ResponseBase.java index 9f578f8b55..45605f73b8 100644 --- a/src/main/java/com/ning/http/client/ResponseBase.java +++ b/src/main/java/com/ning/http/client/ResponseBase.java @@ -15,22 +15,16 @@ import static com.ning.http.util.MiscUtils.isNonEmpty; -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.Response; import com.ning.http.client.cookie.Cookie; import com.ning.http.client.uri.UriComponents; import com.ning.http.util.AsyncHttpProviderUtils; +import java.nio.charset.Charset; import java.util.Collections; import java.util.List; public abstract class ResponseBase implements Response { - protected final static String DEFAULT_CHARSET = "ISO-8859-1"; - protected final HttpResponseStatus status; protected final HttpResponseHeaders headers; protected final List bodyParts; @@ -44,14 +38,14 @@ protected ResponseBase(HttpResponseStatus status, HttpResponseHeaders headers, L protected abstract List buildCookies(); - protected String calculateCharset(String charset) { + protected Charset calculateCharset(String charset) { if (charset == 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) : AsyncHttpProviderUtils.DEFAULT_CHARSET; } @Override 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 bd2c43f675..2d765d82f6 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 @@ -45,12 +45,12 @@ public ByteBuffer getResponseBodyAsByteBuffer() throws IOException { @Override public String getResponseBody() throws IOException { - return getResponseBody(DEFAULT_CHARSET); + return getResponseBody(null); } @Override public String getResponseBody(String charset) throws IOException { - return AsyncHttpProviderUtils.contentToString(bodyParts, computeCharset(charset)); + return AsyncHttpProviderUtils.contentToString(bodyParts, calculateCharset(charset)); } @Override @@ -60,26 +60,15 @@ public InputStream getResponseBodyAsStream() throws IOException { @Override public String getResponseBodyExcerpt(int maxLength) throws IOException { - return getResponseBodyExcerpt(maxLength, DEFAULT_CHARSET); + return getResponseBodyExcerpt(maxLength, null); } @Override public String getResponseBodyExcerpt(int maxLength, String charset) throws IOException { - charset = computeCharset(charset); - - String response = AsyncHttpProviderUtils.contentToString(bodyParts, charset); + String response = AsyncHttpProviderUtils.contentToString(bodyParts, calculateCharset(charset)); return response.length() <= maxLength ? response : response.substring(0, maxLength); } - private String computeCharset(String charset) { - if (charset == null) { - String contentType = getContentType(); - if (contentType != null) - charset = AsyncHttpProviderUtils.parseCharset(contentType); // parseCharset can return null - } - return charset != null ? charset : DEFAULT_CHARSET; - } - @Override protected List buildCookies() { List localCookies = new ArrayList(); 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 7f33e7da32..2c58d7dfef 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 @@ -40,7 +40,7 @@ public JDKResponse(HttpResponseStatus status, HttpResponseHeaders headers, List< @Override public String getResponseBody() throws IOException { - return getResponseBody(DEFAULT_CHARSET); + return getResponseBody(null); } @Override @@ -57,7 +57,7 @@ public ByteBuffer getResponseBodyAsByteBuffer() throws IOException { public String getResponseBody(String charset) throws IOException { if (!contentComputed.get()) { - content = AsyncHttpProviderUtils.contentToString(bodyParts, computeCharset(charset)); + content = AsyncHttpProviderUtils.contentToString(bodyParts, calculateCharset(charset)); } return content; } @@ -65,7 +65,7 @@ public String getResponseBody(String charset) throws IOException { @Override public InputStream getResponseBodyAsStream() throws IOException { if (contentComputed.get()) { - return new ByteArrayInputStream(content.getBytes(DEFAULT_CHARSET)); + return new ByteArrayInputStream(content.getBytes(calculateCharset(null))); } return AsyncHttpProviderUtils.contentToInputStream(bodyParts); @@ -73,29 +73,19 @@ public InputStream getResponseBodyAsStream() throws IOException { @Override public String getResponseBodyExcerpt(int maxLength) throws IOException { - return getResponseBodyExcerpt(maxLength, DEFAULT_CHARSET); + return getResponseBodyExcerpt(maxLength, null); } @Override public String getResponseBodyExcerpt(int maxLength, String charset) throws IOException { - charset = computeCharset(charset); if (!contentComputed.get()) { - content = AsyncHttpProviderUtils.contentToString(bodyParts, charset == null ? DEFAULT_CHARSET : charset); + content = AsyncHttpProviderUtils.contentToString(bodyParts, calculateCharset(charset)); } return content.length() <= maxLength ? content : content.substring(0, maxLength); } - private String computeCharset(String charset) { - if (charset == null) { - String contentType = getContentType(); - if (contentType != null) - charset = AsyncHttpProviderUtils.parseCharset(contentType); // parseCharset can return null - } - return charset != null ? charset : DEFAULT_CHARSET; - } - @Override protected List buildCookies() { List localCookies = new ArrayList(); diff --git a/src/main/java/com/ning/http/client/providers/netty/response/NettyResponse.java b/src/main/java/com/ning/http/client/providers/netty/response/NettyResponse.java index 60e17c1311..bff1cdf2e4 100644 --- a/src/main/java/com/ning/http/client/providers/netty/response/NettyResponse.java +++ b/src/main/java/com/ning/http/client/providers/netty/response/NettyResponse.java @@ -66,7 +66,7 @@ public String getResponseBody() throws IOException { } public String getResponseBody(String charset) throws IOException { - return getResponseBodyAsChannelBuffer().toString(computeCharset(charset)); + return getResponseBodyAsChannelBuffer().toString(calculateCharset(charset)); } @Override @@ -104,15 +104,6 @@ public String getResponseBodyExcerpt(int maxLength, String charset) throws IOExc return response.length() <= maxLength ? response : response.substring(0, maxLength); } - private Charset computeCharset(String charset) { - if (charset == null) { - String contentType = getContentType(); - if (contentType != null) - charset = AsyncHttpProviderUtils.parseCharset(contentType); // parseCharset can return null - } - return charset != null ? Charset.forName(charset) : Charset.forName(DEFAULT_CHARSET); - } - @Override protected List buildCookies() { List cookies = new ArrayList(); diff --git a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java index d86125078c..e65c2bf74e 100644 --- a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java +++ b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java @@ -67,7 +67,7 @@ public final static String getAuthority(UriComponents uri) { return uri.getHost() + ":" + port; } - public final static String contentToString(List bodyParts, String charset) throws UnsupportedEncodingException { + public final static String contentToString(List bodyParts, Charset charset) throws UnsupportedEncodingException { return new String(contentToByte(bodyParts), charset); } From 26d4ab0a6178bccfbdf4c162a11ffae706b7bdf1 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 22 Jul 2014 12:31:45 +0200 Subject: [PATCH 460/701] Extract OptimizedFileRegion --- .../netty/NettyAsyncHttpProvider.java | 58 +------------- .../request/body/OptimizedFileRegion.java | 80 +++++++++++++++++++ 2 files changed, 81 insertions(+), 57 deletions(-) create mode 100644 src/main/java/com/ning/http/client/providers/netty/request/body/OptimizedFileRegion.java 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 262cfa8934..7c3efbcce6 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 @@ -28,8 +28,6 @@ import java.net.InetSocketAddress; import java.net.MalformedURLException; 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; @@ -128,6 +126,7 @@ import com.ning.http.client.providers.netty.request.ProgressListener; import com.ning.http.client.providers.netty.request.body.BodyChunkedInput; import com.ning.http.client.providers.netty.request.body.BodyFileRegion; +import com.ning.http.client.providers.netty.request.body.OptimizedFileRegion; import com.ning.http.client.providers.netty.request.timeout.ReadTimeoutTimerTask; import com.ning.http.client.providers.netty.request.timeout.RequestTimeoutTimerTask; import com.ning.http.client.providers.netty.request.timeout.TimeoutsHolder; @@ -1423,61 +1422,6 @@ protected Boolean initialValue() { } } - public static class OptimizedFileRegion implements FileRegion { - - private final FileChannel file; - private final RandomAccessFile raf; - private final long position; - private final long count; - private long byteWritten; - - public OptimizedFileRegion(RandomAccessFile raf, long position, long count) { - this.raf = raf; - this.file = raf.getChannel(); - this.position = position; - this.count = count; - } - - public long getPosition() { - return position; - } - - public long getCount() { - return count; - } - - 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) + ")"); - } - if (count == 0) { - return 0L; - } - - long bw = file.transferTo(this.position + position, count, target); - byteWritten += bw; - if (byteWritten == raf.length()) { - releaseExternalResources(); - } - return bw; - } - - public void releaseExternalResources() { - try { - file.close(); - } catch (IOException e) { - LOGGER.warn("Failed to close a file.", e); - } - - try { - raf.close(); - } catch (IOException e) { - LOGGER.warn("Failed to close a file.", e); - } - } - } - private static class NettyTransferAdapter extends TransferCompletionHandler.TransferAdapter { private final ChannelBuffer content; diff --git a/src/main/java/com/ning/http/client/providers/netty/request/body/OptimizedFileRegion.java b/src/main/java/com/ning/http/client/providers/netty/request/body/OptimizedFileRegion.java new file mode 100644 index 0000000000..c5ae973167 --- /dev/null +++ b/src/main/java/com/ning/http/client/providers/netty/request/body/OptimizedFileRegion.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2014 AsyncHttpClient Project. 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.providers.netty.request.body; + +import org.jboss.netty.channel.FileRegion; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.io.RandomAccessFile; +import java.nio.channels.FileChannel; +import java.nio.channels.WritableByteChannel; + +public class OptimizedFileRegion implements FileRegion { + + private static final Logger LOGGER = LoggerFactory.getLogger(OptimizedFileRegion.class); + + private final FileChannel file; + private final RandomAccessFile raf; + private final long position; + private final long count; + private long byteWritten; + + public OptimizedFileRegion(RandomAccessFile raf, long position, long count) { + this.raf = raf; + this.file = raf.getChannel(); + this.position = position; + this.count = count; + } + + public long getPosition() { + return position; + } + + public long getCount() { + return count; + } + + 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) + ")"); + } + if (count == 0) { + return 0L; + } + + long bw = file.transferTo(this.position + position, count, target); + byteWritten += bw; + if (byteWritten == raf.length()) { + releaseExternalResources(); + } + return bw; + } + + public void releaseExternalResources() { + try { + file.close(); + } catch (IOException e) { + LOGGER.warn("Failed to close a file.", e); + } + + try { + raf.close(); + } catch (IOException e) { + LOGGER.warn("Failed to close a file.", e); + } + } +} From 1678cc801e6436119f27b68254b6950d525701c1 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 22 Jul 2014 16:00:38 +0200 Subject: [PATCH 461/701] Extract Handler logic out of the Netty provider, close #643 --- .../com/ning/http/client/ntlm/NTLMEngine.java | 13 +- .../netty/NettyAsyncHttpProvider.java | 2042 +---------------- .../http/client/providers/netty/Protocol.java | 29 - .../netty/channel/ChannelManager.java | 234 +- .../CleanupChannelGroup.java | 2 +- .../netty/channel/SslInitializer.java | 14 +- .../channel/pool/DefaultChannelPool.java | 1 + .../netty/future/NettyResponseFuture.java | 24 +- .../providers/netty/handler/HttpProtocol.java | 537 +++++ .../providers/netty/handler/Processor.java | 239 ++ .../providers/netty/handler/Protocol.java | 144 ++ .../netty/handler/WebSocketProtocol.java | 250 ++ .../netty/request/NettyConnectListener.java | 13 +- .../netty/request/NettyRequestSender.java | 840 +++++++ .../request/timeout/ReadTimeoutTimerTask.java | 10 +- .../timeout/RequestTimeoutTimerTask.java | 9 +- .../request/timeout/TimeoutTimerTask.java | 14 +- .../providers/netty/spnego/SpnegoEngine.java | 6 +- .../client/providers/netty/util/HttpUtil.java | 48 + 19 files changed, 2371 insertions(+), 2098 deletions(-) delete mode 100644 src/main/java/com/ning/http/client/providers/netty/Protocol.java rename src/main/java/com/ning/http/client/providers/netty/{util => channel}/CleanupChannelGroup.java (98%) create mode 100644 src/main/java/com/ning/http/client/providers/netty/handler/HttpProtocol.java create mode 100644 src/main/java/com/ning/http/client/providers/netty/handler/Processor.java create mode 100644 src/main/java/com/ning/http/client/providers/netty/handler/Protocol.java create mode 100644 src/main/java/com/ning/http/client/providers/netty/handler/WebSocketProtocol.java create mode 100644 src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java create mode 100644 src/main/java/com/ning/http/client/providers/netty/util/HttpUtil.java 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 44c7f8ee65..853abd6c2c 100644 --- a/src/main/java/com/ning/http/client/ntlm/NTLMEngine.java +++ b/src/main/java/com/ning/http/client/ntlm/NTLMEngine.java @@ -28,17 +28,17 @@ import static com.ning.http.util.MiscUtils.isNonEmpty; +import com.ning.http.util.Base64; + +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. @@ -99,6 +99,8 @@ public class NTLMEngine { SIGNATURE[bytesWithoutNull.length] = (byte) 0x00; } + public static final NTLMEngine INSTANCE = new NTLMEngine(); + /** * Returns the response for the given message. * @@ -1337,5 +1339,4 @@ public String generateType3Msg( t2m.getTarget(), t2m.getTargetInfo()); } - } 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 7c3efbcce6..11aadd3e13 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,755 +15,88 @@ */ package com.ning.http.client.providers.netty; -import static com.ning.http.util.AsyncHttpProviderUtils.DEFAULT_CHARSET; -import static com.ning.http.util.AsyncHttpProviderUtils.getNonEmptyPath; -import static com.ning.http.util.MiscUtils.isNonEmpty; -import static org.jboss.netty.channel.Channels.pipeline; -import static org.jboss.netty.handler.ssl.SslHandler.getDefaultBufferPool; - -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.RandomAccessFile; -import java.net.InetSocketAddress; -import java.net.MalformedURLException; -import java.nio.channels.ClosedChannelException; -import java.nio.charset.Charset; -import java.security.GeneralSecurityException; -import java.security.NoSuchAlgorithmException; -import java.util.ArrayList; -import java.util.List; -import java.util.Map.Entry; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.RejectedExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; - -import javax.net.ssl.SSLEngine; - -import org.jboss.netty.bootstrap.ClientBootstrap; -import org.jboss.netty.buffer.ChannelBuffer; -import org.jboss.netty.buffer.ChannelBuffers; -import org.jboss.netty.channel.Channel; -import org.jboss.netty.channel.ChannelFuture; -import org.jboss.netty.channel.ChannelHandlerContext; -import org.jboss.netty.channel.ChannelPipeline; -import org.jboss.netty.channel.ChannelPipelineFactory; -import org.jboss.netty.channel.ChannelStateEvent; -import org.jboss.netty.channel.DefaultChannelFuture; -import org.jboss.netty.channel.ExceptionEvent; -import org.jboss.netty.channel.FileRegion; -import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelUpstreamHandler; -import org.jboss.netty.channel.socket.ClientSocketChannelFactory; -import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory; -import org.jboss.netty.handler.codec.PrematureChannelClosureException; -import org.jboss.netty.handler.codec.http.DefaultHttpRequest; -import org.jboss.netty.handler.codec.http.HttpChunk; -import org.jboss.netty.handler.codec.http.HttpChunkTrailer; -import org.jboss.netty.handler.codec.http.HttpClientCodec; -import org.jboss.netty.handler.codec.http.HttpContentDecompressor; -import org.jboss.netty.handler.codec.http.HttpHeaders; -import org.jboss.netty.handler.codec.http.HttpMethod; -import org.jboss.netty.handler.codec.http.HttpRequest; -import org.jboss.netty.handler.codec.http.HttpResponse; -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; -import org.jboss.netty.handler.ssl.SslHandler; -import org.jboss.netty.handler.stream.ChunkedFile; -import org.jboss.netty.handler.stream.ChunkedWriteHandler; import org.jboss.netty.util.HashedWheelTimer; -import org.jboss.netty.util.Timeout; import org.jboss.netty.util.Timer; -import org.jboss.netty.util.TimerTask; 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.AsyncHandlerExtensions; 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.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.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.cookie.CookieDecoder; -import com.ning.http.client.cookie.CookieEncoder; -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.channel.ChannelManager; -import com.ning.http.client.providers.netty.channel.Channels; -import com.ning.http.client.providers.netty.channel.SslInitializer; import com.ning.http.client.providers.netty.channel.pool.ChannelPool; import com.ning.http.client.providers.netty.channel.pool.DefaultChannelPool; import com.ning.http.client.providers.netty.channel.pool.NoopChannelPool; -import com.ning.http.client.providers.netty.future.NettyResponseFuture; -import com.ning.http.client.providers.netty.future.StackTraceInspector; -import com.ning.http.client.providers.netty.request.NettyConnectListener; -import com.ning.http.client.providers.netty.request.ProgressListener; -import com.ning.http.client.providers.netty.request.body.BodyChunkedInput; -import com.ning.http.client.providers.netty.request.body.BodyFileRegion; -import com.ning.http.client.providers.netty.request.body.OptimizedFileRegion; -import com.ning.http.client.providers.netty.request.timeout.ReadTimeoutTimerTask; -import com.ning.http.client.providers.netty.request.timeout.RequestTimeoutTimerTask; -import com.ning.http.client.providers.netty.request.timeout.TimeoutsHolder; -import com.ning.http.client.providers.netty.response.ResponseBodyPart; -import com.ning.http.client.providers.netty.response.ResponseHeaders; -import com.ning.http.client.providers.netty.response.ResponseStatus; -import com.ning.http.client.providers.netty.spnego.SpnegoEngine; -import com.ning.http.client.providers.netty.ws.NettyWebSocket; -import com.ning.http.client.providers.netty.ws.WebSocketUtil; -import com.ning.http.client.uri.UriComponents; -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.ProxyUtils; -import com.ning.http.util.SslUtils; -import com.ning.http.util.StandardCharsets; +import com.ning.http.client.providers.netty.handler.HttpProtocol; +import com.ning.http.client.providers.netty.handler.Processor; +import com.ning.http.client.providers.netty.handler.Protocol; +import com.ning.http.client.providers.netty.handler.WebSocketProtocol; +import com.ning.http.client.providers.netty.request.NettyRequestSender; + +import java.io.IOException; +import java.util.concurrent.atomic.AtomicBoolean; public class NettyAsyncHttpProvider extends SimpleChannelUpstreamHandler implements AsyncHttpProvider { static final Logger LOGGER = LoggerFactory.getLogger(NettyAsyncHttpProvider.class); - public static final String GZIP_DEFLATE = HttpHeaders.Values.GZIP + "," + HttpHeaders.Values.DEFLATE; - - public static final IOException REMOTELY_CLOSED_EXCEPTION = new IOException("Remotely Closed"); - static { - REMOTELY_CLOSED_EXCEPTION.setStackTrace(new StackTraceElement[0]); - } - public static final String HTTP_HANDLER = "httpHandler"; - public static final String SSL_HANDLER = "sslHandler"; - public static final String HTTP_PROCESSOR = "httpProcessor"; - public static final String WS_PROCESSOR = "wsProcessor"; - - private static final String HTTPS = "https"; - private static final String HTTP = "http"; - private static final String WEBSOCKET = "ws"; - private static final String WEBSOCKET_SSL = "wss"; - - private final ClientBootstrap plainBootstrap; - private final ClientBootstrap secureBootstrap; - private final ClientBootstrap webSocketBootstrap; - private final ClientBootstrap secureWebSocketBootstrap; - private final AsyncHttpClientConfig config; - private final AtomicBoolean isClose = new AtomicBoolean(false); - private final ClientSocketChannelFactory socketChannelFactory; - private final boolean allowReleaseSocketChannelFactory; + private final AtomicBoolean closed = new AtomicBoolean(false); private final ChannelManager channelManager; - private final NettyAsyncHttpProviderConfig providerConfig; - private final boolean disableZeroCopy; - private static final NTLMEngine ntlmEngine = new NTLMEngine(); - private static SpnegoEngine spnegoEngine; - private final Protocol httpProtocol = new HttpProtocol(); - private final Protocol webSocketProtocol = new WebSocketProtocol(); + private final NettyAsyncHttpProviderConfig nettyConfig; private final boolean allowStopNettyTimer; private final Timer nettyTimer; - private final long handshakeTimeoutInMillis; - private static boolean isNTLM(List auth) { - return isNonEmpty(auth) && auth.get(0).startsWith("NTLM"); - } + private final NettyRequestSender nettyRequestSender; public NettyAsyncHttpProvider(AsyncHttpClientConfig config) { this.config = config; if (config.getAsyncHttpProviderConfig() instanceof NettyAsyncHttpProviderConfig) - providerConfig = (NettyAsyncHttpProviderConfig) config.getAsyncHttpProviderConfig(); + nettyConfig = (NettyAsyncHttpProviderConfig) config.getAsyncHttpProviderConfig(); else - providerConfig = new NettyAsyncHttpProviderConfig(); - - // check if external NioClientSocketChannelFactory is defined - if (providerConfig.getSocketChannelFactory() != null) { - socketChannelFactory = providerConfig.getSocketChannelFactory(); - // cannot allow releasing shared channel factory - allowReleaseSocketChannelFactory = false; - - } else { - ExecutorService e = providerConfig.getBossExecutorService(); - if (e == null) - e = Executors.newCachedThreadPool(); - int numWorkers = config.getIoThreadMultiplier() * Runtime.getRuntime().availableProcessors(); - LOGGER.trace("Number of application's worker threads is {}", numWorkers); - socketChannelFactory = new NioClientSocketChannelFactory(e, config.executorService(), numWorkers); - allowReleaseSocketChannelFactory = true; - } - - allowStopNettyTimer = providerConfig.getNettyTimer() == null; - nettyTimer = allowStopNettyTimer ? newNettyTimer() : providerConfig.getNettyTimer(); - - handshakeTimeoutInMillis = providerConfig.getHandshakeTimeoutInMillis(); - - plainBootstrap = new ClientBootstrap(socketChannelFactory); - secureBootstrap = new ClientBootstrap(socketChannelFactory); - webSocketBootstrap = new ClientBootstrap(socketChannelFactory); - secureWebSocketBootstrap = new ClientBootstrap(socketChannelFactory); - disableZeroCopy = providerConfig.isDisableZeroCopy(); + nettyConfig = new NettyAsyncHttpProviderConfig(); - configureNetty(); + allowStopNettyTimer = nettyConfig.getNettyTimer() == null; + nettyTimer = allowStopNettyTimer ? newNettyTimer() : nettyConfig.getNettyTimer(); - // This is dangerous as we can't catch a wrong typed ConnectionsPool - ChannelPool channelPool = providerConfig.getChannelPool(); + ChannelPool channelPool = nettyConfig.getChannelPool(); if (channelPool == null && config.isAllowPoolingConnections()) { channelPool = new DefaultChannelPool(config, nettyTimer); } else if (channelPool == null) { channelPool = new NoopChannelPool(); } - this.channelManager = new ChannelManager(config, channelPool); - } - - private Timer newNettyTimer() { - HashedWheelTimer timer = new HashedWheelTimer(); - timer.start(); - return timer; - } - - void configureNetty() { - - DefaultChannelFuture.setUseDeadLockChecker(providerConfig.isUseDeadLockChecker()); - - for (Entry entry : providerConfig.propertiesSet()) { - String key = entry.getKey(); - Object value = entry.getValue(); - plainBootstrap.setOption(key, value); - webSocketBootstrap.setOption(key, value); - secureBootstrap.setOption(key, value); - secureWebSocketBootstrap.setOption(key, value); - } - - final boolean compressionEnabled = config.isCompressionEnabled(); - - plainBootstrap.setPipelineFactory(new ChannelPipelineFactory() { - - public ChannelPipeline getPipeline() throws Exception { - ChannelPipeline pipeline = pipeline(); - pipeline.addLast(HTTP_HANDLER, createHttpClientCodec()); - if (compressionEnabled) - pipeline.addLast("inflater", new HttpContentDecompressor()); - pipeline.addLast("chunkedWriter", new ChunkedWriteHandler()); - pipeline.addLast(HTTP_PROCESSOR, NettyAsyncHttpProvider.this); - return pipeline; - } - }); - - webSocketBootstrap.setPipelineFactory(new ChannelPipelineFactory() { - - public ChannelPipeline getPipeline() throws Exception { - ChannelPipeline pipeline = pipeline(); - pipeline.addLast(HTTP_HANDLER, createHttpClientCodec()); - pipeline.addLast(WS_PROCESSOR, NettyAsyncHttpProvider.this); - return pipeline; - } - }); - - secureBootstrap.setPipelineFactory(new ChannelPipelineFactory() { - - public ChannelPipeline getPipeline() throws Exception { - ChannelPipeline pipeline = pipeline(); - pipeline.addLast(SSL_HANDLER, new SslInitializer(NettyAsyncHttpProvider.this)); - pipeline.addLast(HTTP_HANDLER, createHttpsClientCodec()); - if (compressionEnabled) - pipeline.addLast("inflater", new HttpContentDecompressor()); - pipeline.addLast("chunkedWriter", new ChunkedWriteHandler()); - pipeline.addLast(HTTP_PROCESSOR, NettyAsyncHttpProvider.this); - return pipeline; - } - }); - - secureWebSocketBootstrap.setPipelineFactory(new ChannelPipelineFactory() { - - public ChannelPipeline getPipeline() throws Exception { - ChannelPipeline pipeline = pipeline(); - pipeline.addLast(SSL_HANDLER, new SslInitializer(NettyAsyncHttpProvider.this)); - pipeline.addLast(HTTP_HANDLER, createHttpsClientCodec()); - pipeline.addLast(WS_PROCESSOR, NettyAsyncHttpProvider.this); - return pipeline; - } - }); - } - - public SslHandler createSslHandler(String peerHost, int peerPort) throws GeneralSecurityException, IOException { - SSLEngine sslEngine = SslUtils.getInstance().createClientSSLEngine(config, peerHost, peerPort); - return handshakeTimeoutInMillis > 0 ? new SslHandler(sslEngine, getDefaultBufferPool(), false, nettyTimer, handshakeTimeoutInMillis) - : new SslHandler(sslEngine); - } - - private Channel lookupInCache(UriComponents uri, ProxyServer proxy, ConnectionPoolKeyStrategy strategy) { - final Channel channel = channelManager.poll(getPoolKey(uri, proxy, strategy)); - - if (channel != null) { - LOGGER.debug("Using cached Channel {}\n for uri {}\n", channel, uri); - - try { - // Always make sure the channel who got cached support the proper protocol. It could - // only occurs when a HttpMethod.CONNECT is used against a proxy that requires upgrading from http to - // https. - return verifyChannelPipeline(channel, uri.getScheme()); - } catch (Exception ex) { - LOGGER.debug(ex.getMessage(), ex); - } - } - return null; - } - - private HttpClientCodec createHttpClientCodec() { - return new HttpClientCodec(providerConfig.getHttpClientCodecMaxInitialLineLength(),// - providerConfig.getHttpClientCodecMaxHeaderSize(),// - providerConfig.getHttpClientCodecMaxChunkSize()); - } - - private HttpClientCodec createHttpsClientCodec() { - return new HttpClientCodec(providerConfig.getHttpClientCodecMaxInitialLineLength(),// - providerConfig.getHttpClientCodecMaxHeaderSize(),// - providerConfig.getHttpClientCodecMaxChunkSize()); - } - - private Channel verifyChannelPipeline(Channel channel, String scheme) throws IOException, GeneralSecurityException { - - if (channel.getPipeline().get(SSL_HANDLER) != null && HTTP.equalsIgnoreCase(scheme)) { - channel.getPipeline().remove(SSL_HANDLER); - } else if (channel.getPipeline().get(HTTP_HANDLER) != null && HTTP.equalsIgnoreCase(scheme)) { - return channel; - } else if (channel.getPipeline().get(SSL_HANDLER) == null && isSecure(scheme)) { - channel.getPipeline().addFirst(SSL_HANDLER, new SslInitializer(NettyAsyncHttpProvider.this)); - } - return channel; - } - - public final void writeRequest(final Channel channel, final AsyncHttpClientConfig config, final NettyResponseFuture future) { - - HttpRequest nettyRequest = future.getNettyRequest(); - HttpHeaders nettyRequestHeaders = nettyRequest.headers(); - boolean ssl = channel.getPipeline().get(SslHandler.class) != null; - - 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 channelClosed do it's work. - */ - if (!channel.isOpen() || !channel.isConnected()) { - return; - } - - Body body = null; - if (!nettyRequest.getMethod().equals(HttpMethod.CONNECT)) { - BodyGenerator bg = future.getRequest().getBodyGenerator(); - - if (bg == null && future.getRequest().getStreamData() != null) { - bg = new InputStreamBodyGenerator(future.getRequest().getStreamData()); - } - - if (bg != null) { - // Netty issue with chunking. - if (bg instanceof InputStreamBodyGenerator) { - InputStreamBodyGenerator.class.cast(bg).patchNettyChunkingIssue(true); - } - - try { - body = bg.createBody(); - } catch (IOException ex) { - throw new IllegalStateException(ex); - } - long length = body.getContentLength(); - if (length >= 0) { - nettyRequestHeaders.set(HttpHeaders.Names.CONTENT_LENGTH, length); - } else { - nettyRequestHeaders.set(HttpHeaders.Names.TRANSFER_ENCODING, HttpHeaders.Values.CHUNKED); - } - - } else if (isNonEmpty(future.getRequest().getParts())) { - String contentType = nettyRequestHeaders.get(HttpHeaders.Names.CONTENT_TYPE); - String contentLength = nettyRequestHeaders.get(HttpHeaders.Names.CONTENT_LENGTH); - - long length = -1; - if (contentLength != null) { - length = Long.parseLong(contentLength); - } else { - nettyRequestHeaders.add(HttpHeaders.Names.TRANSFER_ENCODING, HttpHeaders.Values.CHUNKED); - } - - body = new MultipartBody(future.getRequest().getParts(), contentType, length); - } - } - - if (future.getAsyncHandler() instanceof TransferCompletionHandler) { - - FluentCaseInsensitiveStringsMap h = new FluentCaseInsensitiveStringsMap(); - for (String s : nettyRequestHeaders.names()) { - for (String header : nettyRequestHeaders.getAll(s)) { - h.add(s, header); - } - } - - TransferCompletionHandler.class.cast(future.getAsyncHandler()).transferAdapter( - new NettyTransferAdapter(h, nettyRequest.getContent(), future.getRequest().getFile())); - } - - // Leave it to true. - if (future.getAndSetWriteHeaders(true)) { - try { - if (future.getAsyncHandler() instanceof AsyncHandlerExtensions) - AsyncHandlerExtensions.class.cast(future.getAsyncHandler()).onRequestSent(); - - channel.write(nettyRequest).addListener(new ProgressListener(config, true, future.getAsyncHandler(), future)); - } catch (Throwable cause) { - LOGGER.debug(cause.getMessage(), cause); - try { - channel.close(); - } catch (RuntimeException ex) { - LOGGER.debug(ex.getMessage(), ex); - } - return; - } - } - - if (future.getAndSetWriteBody(true)) { - if (!nettyRequest.getMethod().equals(HttpMethod.CONNECT)) { - - if (future.getRequest().getFile() != null) { - final File file = future.getRequest().getFile(); - final RandomAccessFile raf = new RandomAccessFile(file, "r"); - - try { - ChannelFuture writeFuture; - if (disableZeroCopy || ssl) { - writeFuture = channel - .write(new ChunkedFile(raf, 0, raf.length(), providerConfig.getChunkedFileChunkSize())); - } else { - final FileRegion region = new OptimizedFileRegion(raf, 0, raf.length()); - writeFuture = channel.write(region); - } - writeFuture.addListener(new ProgressListener(config, false, future.getAsyncHandler(), future) { - public void operationComplete(ChannelFuture cf) { - try { - raf.close(); - } catch (IOException e) { - LOGGER.warn("Failed to close request body: {}", e.getMessage(), e); - } - super.operationComplete(cf); - } - }); - } catch (IOException ex) { - if (raf != null) { - try { - raf.close(); - } catch (IOException e) { - } - } - throw ex; - } - } else if (body != null) { - final Body b = body; - - ChannelFuture writeFuture; - if (disableZeroCopy || ssl || !(body instanceof RandomAccessBody)) { - BodyChunkedInput bodyChunkedInput = new BodyChunkedInput(body); - writeFuture = channel.write(bodyChunkedInput); - } else { - BodyFileRegion bodyFileRegion = new BodyFileRegion((RandomAccessBody) body); - writeFuture = channel.write(bodyFileRegion); - } - writeFuture.addListener(new ProgressListener(config, false, future.getAsyncHandler(), future) { - public void operationComplete(ChannelFuture cf) { - try { - b.close(); - } catch (IOException e) { - LOGGER.warn("Failed to close request body: {}", e.getMessage(), e); - } - super.operationComplete(cf); - } - }); - } - } - } - } catch (Throwable ioe) { - try { - channel.close(); - } catch (RuntimeException ex) { - LOGGER.debug(ex.getMessage(), ex); - } - } - - try { - future.touch(); - int requestTimeout = AsyncHttpProviderUtils.requestTimeout(config, future.getRequest()); - TimeoutsHolder timeoutsHolder = new TimeoutsHolder(); - if (requestTimeout != -1) { - timeoutsHolder.requestTimeout = newTimeout(new RequestTimeoutTimerTask(future, this, timeoutsHolder, requestTimeout), requestTimeout); - } - - int readTimeout = config.getReadTimeout(); - if (readTimeout != -1 && readTimeout <= requestTimeout) { - // no need for a idleConnectionTimeout that's less than the requestTimeout - timeoutsHolder.readTimeout = newTimeout(new ReadTimeoutTimerTask(future, this, timeoutsHolder, - requestTimeout, readTimeout), readTimeout); - } - future.setTimeoutsHolder(timeoutsHolder); - } catch (RejectedExecutionException ex) { - abort(future, ex); - } - } + channelManager = new ChannelManager(config, nettyConfig, channelPool, nettyTimer); - protected static final HttpRequest buildRequest(AsyncHttpClientConfig config, Request request, UriComponents uri, boolean allowConnect, - ChannelBuffer buffer, ProxyServer proxyServer) throws IOException { + nettyRequestSender = new NettyRequestSender(config, nettyConfig, channelManager, nettyTimer, closed); - String method = request.getMethod(); - if (allowConnect && proxyServer != null && isSecure(uri)) { - method = HttpMethod.CONNECT.toString(); - } - return construct(config, request, new HttpMethod(method), uri, buffer, proxyServer); - } + Protocol webSocketProtocol = new WebSocketProtocol(channelManager, config, nettyRequestSender); + Processor webSocketProcessor = new Processor(config, channelManager, nettyRequestSender, webSocketProtocol); - private static SpnegoEngine getSpnegoEngine() { - if (spnegoEngine == null) - spnegoEngine = new SpnegoEngine(); - return spnegoEngine; - } + Protocol httpProtocol = new HttpProtocol(channelManager, config, nettyRequestSender, webSocketProcessor); + Processor httpProcessor = new Processor(config, channelManager, nettyRequestSender, httpProtocol); - private static String computeNonConnectRequestPath(AsyncHttpClientConfig config, UriComponents uri, ProxyServer proxyServer) { - if (proxyServer != null && !(isSecure(uri) && config.isUseRelativeURIsWithSSLProxies())) - return uri.toString(); - else { - String path = getNonEmptyPath(uri); - return uri.getQuery() != null ? path + "?" + uri.getQuery() : path; - } + channelManager.configureBootstraps(httpProcessor, webSocketProcessor); } - private static HttpRequest construct(AsyncHttpClientConfig config, Request request, HttpMethod m, UriComponents uri, - ChannelBuffer buffer, ProxyServer proxyServer) throws IOException { - - HttpRequest nettyRequest; - - if (m.equals(HttpMethod.CONNECT)) { - nettyRequest = new DefaultHttpRequest(HttpVersion.HTTP_1_0, m, AsyncHttpProviderUtils.getAuthority(uri)); - } else { - String path = computeNonConnectRequestPath(config, uri, proxyServer); - nettyRequest = new DefaultHttpRequest(HttpVersion.HTTP_1_1, m, path); - } - - HttpHeaders nettyRequestHeaders = nettyRequest.headers(); - - boolean webSocket = isWebSocket(uri.getScheme()); - if (webSocket && !m.equals(HttpMethod.CONNECT)) { - nettyRequestHeaders.add(HttpHeaders.Names.UPGRADE, HttpHeaders.Values.WEBSOCKET); - nettyRequestHeaders.add(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.UPGRADE); - nettyRequestHeaders.add(HttpHeaders.Names.ORIGIN, "http://" + uri.getHost() + ":" + uri.getPort()); - nettyRequestHeaders.add(HttpHeaders.Names.SEC_WEBSOCKET_KEY, WebSocketUtil.getKey()); - nettyRequestHeaders.add(HttpHeaders.Names.SEC_WEBSOCKET_VERSION, "13"); - } - - String host = request.getVirtualHost() != null ? request.getVirtualHost() : uri.getHost(); - String hostHeader = request.getVirtualHost() != null || uri.getPort() == -1 ? host : host + ":" + uri.getPort(); - nettyRequestHeaders.set(HttpHeaders.Names.HOST, hostHeader); - - if (!m.equals(HttpMethod.CONNECT)) { - for (Entry> header : request.getHeaders()) { - String name = header.getKey(); - if (!HttpHeaders.Names.HOST.equalsIgnoreCase(name)) { - for (String value : header.getValue()) { - nettyRequestHeaders.add(name, value); - } - } - } - - if (config.isCompressionEnabled()) { - nettyRequestHeaders.set(HttpHeaders.Names.ACCEPT_ENCODING, GZIP_DEFLATE); - } - } else { - List auth = request.getHeaders().get(HttpHeaders.Names.PROXY_AUTHORIZATION); - if (isNTLM(auth)) { - nettyRequestHeaders.add(HttpHeaders.Names.PROXY_AUTHORIZATION, auth.get(0)); - } - } - Realm realm = request.getRealm() != null ? request.getRealm() : config.getRealm(); - - if (realm != null && realm.getUsePreemptiveAuth()) { - - String domain = realm.getNtlmDomain(); - if (proxyServer != null && proxyServer.getNtlmDomain() != null) { - domain = proxyServer.getNtlmDomain(); - } - - String authHost = realm.getNtlmHost(); - if (proxyServer != null && proxyServer.getHost() != null) { - host = proxyServer.getHost(); - } - - switch (realm.getAuthScheme()) { - case BASIC: - nettyRequestHeaders.add(HttpHeaders.Names.AUTHORIZATION, AuthenticatorUtils.computeBasicAuthentication(realm)); - break; - case DIGEST: - if (isNonEmpty(realm.getNonce())) { - try { - nettyRequestHeaders.add(HttpHeaders.Names.AUTHORIZATION, AuthenticatorUtils.computeDigestAuthentication(realm)); - } catch (NoSuchAlgorithmException e) { - throw new SecurityException(e); - } - } - break; - case NTLM: - try { - nettyRequestHeaders.add(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; - } - nettyRequestHeaders.add(HttpHeaders.Names.AUTHORIZATION, "Negotiate " + challengeHeader); - break; - case NONE: - break; - default: - throw new IllegalStateException(String.format("Invalid Authentication %s", realm.toString())); - } - } - - if (!webSocket && !request.getHeaders().containsKey(HttpHeaders.Names.CONNECTION)) { - nettyRequestHeaders.set(HttpHeaders.Names.CONNECTION, AsyncHttpProviderUtils.keepAliveHeaderValue(config)); - } - - if (proxyServer != null) { - if (!request.getHeaders().containsKey("Proxy-Connection")) { - nettyRequestHeaders.set("Proxy-Connection", AsyncHttpProviderUtils.keepAliveHeaderValue(config)); - } - - if (proxyServer.getPrincipal() != null) { - if (isNonEmpty(proxyServer.getNtlmDomain())) { - - List auth = request.getHeaders().get(HttpHeaders.Names.PROXY_AUTHORIZATION); - if (!isNTLM(auth)) { - try { - String msg = ntlmEngine.generateType1Msg(proxyServer.getNtlmDomain(), proxyServer.getHost()); - nettyRequestHeaders.set(HttpHeaders.Names.PROXY_AUTHORIZATION, "NTLM " + msg); - } catch (NTLMEngineException e) { - IOException ie = new IOException(); - ie.initCause(e); - throw ie; - } - } - } else { - nettyRequestHeaders.set(HttpHeaders.Names.PROXY_AUTHORIZATION, - AuthenticatorUtils.computeBasicAuthentication(proxyServer)); - } - } - } - - // Add default accept headers. - if (!request.getHeaders().containsKey(HttpHeaders.Names.ACCEPT)) { - nettyRequestHeaders.set(HttpHeaders.Names.ACCEPT, "*/*"); - } - - String userAgentHeader = request.getHeaders().getFirstValue(HttpHeaders.Names.USER_AGENT); - if (userAgentHeader != null) { - nettyRequestHeaders.set(HttpHeaders.Names.USER_AGENT, userAgentHeader); - } else if (config.getUserAgent() != null) { - nettyRequestHeaders.set(HttpHeaders.Names.USER_AGENT, config.getUserAgent()); - } else { - nettyRequestHeaders.set(HttpHeaders.Names.USER_AGENT, AsyncHttpProviderUtils.constructUserAgent(NettyAsyncHttpProvider.class)); - } - - if (!m.equals(HttpMethod.CONNECT)) { - if (isNonEmpty(request.getCookies())) { - nettyRequestHeaders.set(HttpHeaders.Names.COOKIE, CookieEncoder.encode(request.getCookies())); - } - - Charset bodyCharset = request.getBodyEncoding() == null ? DEFAULT_CHARSET : Charset.forName(request.getBodyEncoding()); - - // We already have processed the body. - if (buffer != null && buffer.writerIndex() != 0) { - nettyRequestHeaders.set(HttpHeaders.Names.CONTENT_LENGTH, buffer.writerIndex()); - nettyRequest.setContent(buffer); - - } else if (request.getByteData() != null) { - nettyRequestHeaders.set(HttpHeaders.Names.CONTENT_LENGTH, String.valueOf(request.getByteData().length)); - nettyRequest.setContent(ChannelBuffers.wrappedBuffer(request.getByteData())); - - } else if (request.getStringData() != null) { - byte[] bytes = request.getStringData().getBytes(bodyCharset); - nettyRequestHeaders.set(HttpHeaders.Names.CONTENT_LENGTH, String.valueOf(bytes.length)); - nettyRequest.setContent(ChannelBuffers.wrappedBuffer(bytes)); - - } else if (isNonEmpty(request.getFormParams())) { - String formBody = AsyncHttpProviderUtils.formParams2UTF8String(request.getFormParams()); - nettyRequestHeaders.set(HttpHeaders.Names.CONTENT_LENGTH, String.valueOf(formBody.length())); - nettyRequest.setContent(ChannelBuffers.wrappedBuffer(formBody.getBytes(bodyCharset))); - - if (!request.getHeaders().containsKey(HttpHeaders.Names.CONTENT_TYPE)) { - nettyRequestHeaders.set(HttpHeaders.Names.CONTENT_TYPE, HttpHeaders.Values.APPLICATION_X_WWW_FORM_URLENCODED); - } - - } else if (isNonEmpty(request.getParts())) { - MultipartRequestEntity mre = AsyncHttpProviderUtils.createMultipartRequestEntity(request.getParts(), request.getHeaders()); - - nettyRequestHeaders.set(HttpHeaders.Names.CONTENT_TYPE, mre.getContentType()); - long contentLength = mre.getContentLength(); - if (contentLength >= 0) { - nettyRequestHeaders.set(HttpHeaders.Names.CONTENT_LENGTH, String.valueOf(contentLength)); - } - - } else if (request.getFile() != null) { - File file = request.getFile(); - if (!file.isFile()) { - throw new IOException(String.format("File %s is not a file or doesn't exist", file.getAbsolutePath())); - } - nettyRequestHeaders.set(HttpHeaders.Names.CONTENT_LENGTH, file.length()); - } - } - return nettyRequest; + private Timer newNettyTimer() { + HashedWheelTimer timer = new HashedWheelTimer(); + timer.start(); + return timer; } public void close() { - if (isClose.compareAndSet(false, true)) { + if (closed.compareAndSet(false, true)) { try { - channelManager.destroy(); + channelManager.close(); + // FIXME shouldn't close if not allowed config.executorService().shutdown(); - if (allowReleaseSocketChannelFactory) { - socketChannelFactory.releaseExternalResources(); - plainBootstrap.releaseExternalResources(); - secureBootstrap.releaseExternalResources(); - webSocketBootstrap.releaseExternalResources(); - secureWebSocketBootstrap.releaseExternalResources(); - } if (allowStopNettyTimer) nettyTimer.stop(); @@ -776,1319 +109,10 @@ public void close() { @Override public ListenableFuture execute(Request request, final AsyncHandler asyncHandler) throws IOException { - return doConnect(request, asyncHandler, null, true, false); - } - - private void execute(final Request request, final NettyResponseFuture f, boolean useCache, boolean reclaimCache) - throws IOException { - doConnect(request, f.getAsyncHandler(), f, useCache, reclaimCache); - } - - private NettyResponseFuture buildNettyResponseFutureWithCachedChannel(Request request, AsyncHandler asyncHandler, - NettyResponseFuture f, ProxyServer proxyServer, UriComponents uri, ChannelBuffer bufferedBytes, int maxTry) - throws IOException { - - for (int i = 0; i < maxTry; i++) { - if (maxTry == 0) - return null; - - Channel channel = null; - if (f != null && f.reuseChannel() && f.channel() != null) { - channel = f.channel(); - } else { - channel = lookupInCache(uri, proxyServer, request.getConnectionPoolKeyStrategy()); - } - - if (channel == null) - return null; - else { - HttpRequest nettyRequest = null; - - if (f == null) { - nettyRequest = buildRequest(config, request, uri, false, bufferedBytes, proxyServer); - f = newFuture(uri, request, asyncHandler, nettyRequest, config, proxyServer); - } else if (i == 0) { - // only build request on first try - nettyRequest = buildRequest(config, request, uri, f.isConnectAllowed(), bufferedBytes, proxyServer); - f.setNettyRequest(nettyRequest); - } - f.setState(NettyResponseFuture.STATE.POOLED); - f.attachChannel(channel, false); - - if (channel.isOpen() && channel.isConnected()) { - Channels.setAttachment(channel, f); - return f; - } else - // else, channel was closed by the server since we fetched it from the pool, starting over - f.attachChannel(null); - } - } - return null; - } - - private NettyResponseFuture buildConnectListenerFuture(AsyncHttpClientConfig config,// - Request request,// - AsyncHandler asyncHandler,// - NettyResponseFuture future,// - ChannelBuffer buffer,// - UriComponents uri) throws IOException { - ProxyServer proxyServer = ProxyUtils.getProxyServer(config, request); - HttpRequest nettyRequest = NettyAsyncHttpProvider.buildRequest(config, request, uri, true, buffer, proxyServer); - if (future == null) { - return NettyAsyncHttpProvider.newFuture(uri, request, asyncHandler, nettyRequest, config, proxyServer); - } else { - future.setNettyRequest(nettyRequest); - future.setRequest(request); - return future; - } - } - - private ListenableFuture doConnect(final Request request, final AsyncHandler asyncHandler, NettyResponseFuture f, - boolean useCache, boolean reclaimCache) throws IOException { - - if (isClose()) { - throw new IOException("Closed"); - } - - UriComponents uri = request.getURI(); - - if (uri.getScheme().startsWith(WEBSOCKET) && !validateWebSocketRequest(request, asyncHandler)) { - throw new IOException("WebSocket method must be a GET"); - } - - ProxyServer proxyServer = ProxyUtils.getProxyServer(config, request); - - boolean resultOfAConnect = f != null && f.getNettyRequest() != null && f.getNettyRequest().getMethod().equals(HttpMethod.CONNECT); - boolean useProxy = proxyServer != null && !resultOfAConnect; - - ChannelBuffer bufferedBytes = null; - if (f != null && f.getRequest().getFile() == null - && !f.getNettyRequest().getMethod().getName().equals(HttpMethod.CONNECT.getName())) { - bufferedBytes = f.getNettyRequest().getContent(); - } - - boolean useSSl = isSecure(uri) && !useProxy; - - if (useCache) { - // 3 tentatives - NettyResponseFuture connectedFuture = buildNettyResponseFutureWithCachedChannel(request, asyncHandler, f, proxyServer, uri, - bufferedBytes, 3); - - if (connectedFuture != null) { - LOGGER.debug("\nUsing cached Channel {}\n for request \n{}\n", connectedFuture.channel(), connectedFuture.getNettyRequest()); - - try { - writeRequest(connectedFuture.channel(), config, connectedFuture); - } catch (Exception ex) { - LOGGER.debug("writeRequest failure", ex); - if (useSSl && ex.getMessage() != null && ex.getMessage().contains("SSLEngine")) { - LOGGER.debug("SSLEngine failure", ex); - connectedFuture = null; - } else { - try { - asyncHandler.onThrowable(ex); - } catch (Throwable t) { - LOGGER.warn("doConnect.writeRequest()", t); - } - IOException ioe = new IOException(ex.getMessage()); - ioe.initCause(ex); - throw ioe; - } - } - return connectedFuture; - } - } - - NettyResponseFuture connectListenerFuture = buildConnectListenerFuture(config, request, asyncHandler, f, bufferedBytes, - uri); - - boolean channelPreempted = false; - String poolKey = null; - - // Do not throw an exception when we need an extra connection for a redirect. - if (!reclaimCache) { - - // only compute when maxConnectionPerHost is enabled - // FIXME clean up - if (config.getMaxConnectionsPerHost() > 0) - poolKey = getPoolKey(connectListenerFuture); - - if (channelManager.preemptChannel(poolKey)) { - channelPreempted = true; - } else { - IOException ex = new IOException(String.format("Too many connections %s", config.getMaxConnections())); - try { - asyncHandler.onThrowable(ex); - } catch (Exception e) { - LOGGER.warn("asyncHandler.onThrowable crashed", e); - } - throw ex; - } - } - - NettyConnectListener connectListener = new NettyConnectListener(config, connectListenerFuture, this, channelManager, - channelPreempted, poolKey); - - ChannelFuture channelFuture; - ClientBootstrap bootstrap = (request.getURI().getScheme().startsWith(WEBSOCKET) && !useProxy) ? (useSSl ? secureWebSocketBootstrap - : webSocketBootstrap) : (useSSl ? secureBootstrap : plainBootstrap); - bootstrap.setOption("connectTimeoutMillis", config.getConnectionTimeout()); - - try { - InetSocketAddress remoteAddress; - if (request.getInetAddress() != null) { - remoteAddress = new InetSocketAddress(request.getInetAddress(), AsyncHttpProviderUtils.getDefaultPort(uri)); - } else if (!useProxy) { - remoteAddress = new InetSocketAddress(uri.getHost(), AsyncHttpProviderUtils.getDefaultPort(uri)); - } else { - remoteAddress = new InetSocketAddress(proxyServer.getHost(), proxyServer.getPort()); - } - - if (request.getLocalAddress() != null) { - channelFuture = bootstrap.connect(remoteAddress, new InetSocketAddress(request.getLocalAddress(), 0)); - } else { - channelFuture = bootstrap.connect(remoteAddress); - } - - channelFuture.addListener(connectListener); - - } catch (Throwable t) { - if (channelPreempted) - channelManager.abortChannelPreemption(poolKey); - abort(connectListener.future(), t.getCause() == null ? t : t.getCause()); - } - - return connectListener.future(); - } - - @Override - public void messageReceived(final ChannelHandlerContext ctx, MessageEvent e) throws Exception { - - // call super to reset the read timeout - super.messageReceived(ctx, e); - - Channel channel = ctx.getChannel(); - Object attachment = Channels.getAttachment(channel); - - if (attachment == null) - LOGGER.debug("ChannelHandlerContext doesn't have any attachment"); - - if (attachment == DiscardEvent.INSTANCE) { - // discard - - } else if (attachment instanceof Callback) { - Object message = e.getMessage(); - Callback ac = (Callback) attachment; - if (message instanceof HttpChunk) { - // the AsyncCallable is to be processed on the last chunk - if (HttpChunk.class.cast(message).isLast()) - // process the AsyncCallable before passing the message to the protocol - ac.call(); - } else { - ac.call(); - Channels.setDiscard(channel); - } - - } else if (attachment instanceof NettyResponseFuture) { - Protocol p = (ctx.getPipeline().get(HTTP_PROCESSOR) != null ? httpProtocol : webSocketProtocol); - p.handle(channel, e, NettyResponseFuture.class.cast(attachment)); - - } else { - // unhandled message - try { - ctx.getChannel().close(); - } catch (Throwable t) { - LOGGER.trace("Closing an orphan channel {}", ctx.getChannel()); - } - } - } - - private Realm kerberosChallenge(List proxyAuth, Request request, ProxyServer proxyServer, - FluentCaseInsensitiveStringsMap headers, Realm realm, NettyResponseFuture future, boolean proxyInd) - throws NTLMEngineException { - - UriComponents uri = request.getURI(); - String host = request.getVirtualHost() != null ? request.getVirtualHost() : uri.getHost(); - String server = proxyServer == null ? host : proxyServer.getHost(); - try { - String challengeHeader = getSpnegoEngine().generateToken(server); - headers.remove(HttpHeaders.Names.AUTHORIZATION); - headers.add(HttpHeaders.Names.AUTHORIZATION, "Negotiate " + challengeHeader); - - Realm.RealmBuilder realmBuilder; - if (realm != null) { - realmBuilder = new Realm.RealmBuilder().clone(realm); - } else { - realmBuilder = new Realm.RealmBuilder(); - } - return realmBuilder.setUri(uri).setMethodName(request.getMethod()).setScheme(Realm.AuthScheme.KERBEROS).build(); - } catch (Throwable throwable) { - if (isNTLM(proxyAuth)) - return ntlmChallenge(proxyAuth, request, proxyServer, headers, realm, future, proxyInd); - abort(future, throwable); - return null; - } - } - - private String authorizationHeaderName(boolean proxyInd) { - return proxyInd ? HttpHeaders.Names.PROXY_AUTHORIZATION : HttpHeaders.Names.AUTHORIZATION; - } - - private void addNTLMAuthorization(FluentCaseInsensitiveStringsMap headers, String challengeHeader, boolean proxyInd) { - headers.add(authorizationHeaderName(proxyInd), "NTLM " + challengeHeader); - } - - private void addType3NTLMAuthorizationHeader(List auth, FluentCaseInsensitiveStringsMap headers, String username, - String password, String domain, String workstation, boolean proxyInd) throws NTLMEngineException { - headers.remove(authorizationHeaderName(proxyInd)); - - // Beware of space!, see #462 - if (isNonEmpty(auth) && auth.get(0).startsWith("NTLM ")) { - String serverChallenge = auth.get(0).trim().substring("NTLM ".length()); - String challengeHeader = ntlmEngine.generateType3Msg(username, password, domain, workstation, serverChallenge); - addNTLMAuthorization(headers, challengeHeader, proxyInd); - } - } - - private Realm ntlmChallenge(List wwwAuth, Request request, ProxyServer proxyServer, FluentCaseInsensitiveStringsMap headers, - Realm realm, NettyResponseFuture future, boolean proxyInd) throws NTLMEngineException { - - boolean useRealm = (proxyServer == null && realm != null); - - String ntlmDomain = useRealm ? realm.getNtlmDomain() : proxyServer.getNtlmDomain(); - String ntlmHost = useRealm ? realm.getNtlmHost() : proxyServer.getHost(); - String principal = useRealm ? realm.getPrincipal() : proxyServer.getPrincipal(); - String password = useRealm ? realm.getPassword() : proxyServer.getPassword(); - UriComponents uri = request.getURI(); - - Realm.RealmBuilder realmBuilder; - if (realm != null && !realm.isNtlmMessageType2Received()) { - String challengeHeader = ntlmEngine.generateType1Msg(ntlmDomain, ntlmHost); - addNTLMAuthorization(headers, challengeHeader, proxyInd); - realmBuilder = new Realm.RealmBuilder().clone(realm).setScheme(realm.getAuthScheme()).setNtlmMessageType2Received(true); - future.getAndSetAuth(false); - } else { - addType3NTLMAuthorizationHeader(wwwAuth, headers, principal, password, ntlmDomain, ntlmHost, proxyInd); - - if (realm != null) { - realmBuilder = new Realm.RealmBuilder().clone(realm).setScheme(realm.getAuthScheme()); - } else { - realmBuilder = new Realm.RealmBuilder().setScheme(Realm.AuthScheme.NTLM); - } - } - - return realmBuilder.setUri(uri).setMethodName(request.getMethod()).build(); - } - - private Realm ntlmProxyChallenge(List wwwAuth, Request request, ProxyServer proxyServer, - FluentCaseInsensitiveStringsMap headers, Realm realm, NettyResponseFuture future) throws NTLMEngineException { - future.getAndSetAuth(false); - - addType3NTLMAuthorizationHeader(wwwAuth, headers, proxyServer.getPrincipal(), proxyServer.getPassword(), - proxyServer.getNtlmDomain(), proxyServer.getHost(), true); - - Realm.RealmBuilder realmBuilder = new Realm.RealmBuilder(); - if (realm != null) { - realmBuilder = realmBuilder.clone(realm); - } - return realmBuilder.setUri(request.getURI()).setMethodName(request.getMethod()).build(); - } - - private String getPoolKey(NettyResponseFuture future) { - return getPoolKey(future.getURI(), future.getProxyServer(), future.getConnectionPoolKeyStrategy()); - } - - private String getPoolKey(UriComponents uri, ProxyServer proxy, ConnectionPoolKeyStrategy strategy) { - String serverPart = strategy.getKey(uri); - return proxy != null ? proxy.getUrl() + serverPart : serverPart; - } - - private void drainChannel(final Channel channel, final NettyResponseFuture future) { - Channels.setAttachment(channel, newDrainCallable(future, channel, future.isKeepAlive(), getPoolKey(future))); - } - - private FilterContext handleIoException(FilterContext fc, NettyResponseFuture future) { - for (IOExceptionFilter asyncFilter : config.getIOExceptionFilters()) { - try { - fc = asyncFilter.filter(fc); - if (fc == null) { - throw new NullPointerException("FilterContext is null"); - } - } catch (FilterException efe) { - abort(future, efe); - } - } - return fc; - } - - private void replayRequest(final NettyResponseFuture future, FilterContext fc, Channel channel) throws IOException { - if (future.getAsyncHandler() instanceof AsyncHandlerExtensions) { - AsyncHandlerExtensions.class.cast(future.getAsyncHandler()).onRetry(); - } - final Request newRequest = fc.getRequest(); - future.setAsyncHandler(fc.getAsyncHandler()); - future.setState(NettyResponseFuture.STATE.NEW); - future.touch(); - - LOGGER.debug("\n\nReplaying Request {}\n for Future {}\n", newRequest, future); - drainChannel(channel, future); - nextRequest(newRequest, future); - return; - } - - private List getNettyHeaderValuesByCaseInsensitiveName(HttpHeaders headers, String name) { - ArrayList l = new ArrayList(); - for (Entry e : headers) { - if (e.getKey().equalsIgnoreCase(name)) { - l.add(e.getValue().trim()); - } - } - return l; - } - - private void nextRequest(final Request request, final NettyResponseFuture future) throws IOException { - nextRequest(request, future, true); - } - - private void nextRequest(final Request request, final NettyResponseFuture future, final boolean useCache) throws IOException { - execute(request, future, useCache, true); - } - - public void abort(NettyResponseFuture future, Throwable t) { - Channel channel = future.channel(); - if (channel != null) - channelManager.closeChannel(channel); - - if (!future.isDone()) { - LOGGER.debug("Aborting Future {}\n", future); - LOGGER.debug(t.getMessage(), t); - } - - future.abort(t); - } - - private void upgradeProtocol(ChannelPipeline p, String scheme, String host, int port) throws IOException, GeneralSecurityException { - if (p.get(HTTP_HANDLER) != null) { - p.remove(HTTP_HANDLER); - } - - if (isSecure(scheme)) { - if (p.get(SSL_HANDLER) == null) { - p.addFirst(HTTP_HANDLER, createHttpClientCodec()); - p.addFirst(SSL_HANDLER, createSslHandler(host, port)); - } else { - p.addAfter(SSL_HANDLER, HTTP_HANDLER, createHttpClientCodec()); - } - - } else { - p.addFirst(HTTP_HANDLER, createHttpClientCodec()); - } - - if (isWebSocket(scheme)) { - p.replace(HTTP_PROCESSOR, WS_PROCESSOR, NettyAsyncHttpProvider.this); - } - } - - public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { - - if (isClose()) { - return; - } - - Channel channel = ctx.getChannel(); - channelManager.removeAll(channel); - - try { - super.channelClosed(ctx, e); - } catch (Exception ex) { - LOGGER.trace("super.channelClosed", ex); - } - - Object attachment = Channels.getAttachment(channel); - LOGGER.debug("Channel Closed: {} with attachment {}", channel, attachment); - - if (attachment instanceof Callback) { - Callback ac = (Callback) attachment; - Channels.setAttachment(channel, ac.future()); - ac.call(); - - } else if (attachment instanceof NettyResponseFuture) { - NettyResponseFuture future = (NettyResponseFuture) attachment; - future.touch(); - - 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); - - if (fc.replayRequest() && future.canBeReplay()) { - replayRequest(future, fc, channel); - return; - } - } - - Protocol p = (ctx.getPipeline().get(HttpClientCodec.class) != null ? httpProtocol : webSocketProtocol); - p.onClose(channel, e); - - if (future == null || future.isDone()) - channelManager.closeChannel(channel); - - else if (!retry(ctx.getChannel(), future)) - abort(future, REMOTELY_CLOSED_EXCEPTION); - } - } - - public boolean retry(Channel channel, NettyResponseFuture future) { - - if (isClose()) - return false; - - if (future == null) { - Object attachment = Channels.getAttachment(channel); - if (attachment instanceof NettyResponseFuture) - future = (NettyResponseFuture) attachment; - } - - if (future != null && future.canBeReplay()) { - future.setState(NettyResponseFuture.STATE.RECONNECTED); - - LOGGER.debug("Trying to recover request {}\n", future.getNettyRequest()); - if (future.getAsyncHandler() instanceof AsyncHandlerExtensions) - AsyncHandlerExtensions.class.cast(future.getAsyncHandler()).onRetry(); - - try { - nextRequest(future.getRequest(), future); - return true; - - } catch (IOException iox) { - future.setState(NettyResponseFuture.STATE.CLOSED); - future.abort(iox); - LOGGER.error("Remotely Closed, unable to recover", iox); - return false; - } - - } else { - LOGGER.debug("Unable to recover future {}\n", future); - return false; - } - } - - private void markAsDone(final NettyResponseFuture future, final Channel channel) throws MalformedURLException { - // We need to make sure everything is OK before adding the connection back to the pool. - try { - future.done(); - } catch (Throwable t) { - // Never propagate exception once we know we are done. - LOGGER.debug(t.getMessage(), t); - } - - if (!future.isKeepAlive() || !channel.isReadable()) { - channelManager.closeChannel(channel); - } - } - - private void finishUpdate(final NettyResponseFuture future, Channel channel, boolean expectOtherChunks) throws IOException { - boolean keepAlive = future.isKeepAlive(); - if (expectOtherChunks && keepAlive) - drainChannel(channel, future); - else - channelManager.tryToOfferChannelToPool(channel, keepAlive, getPoolKey(future)); - markAsDone(future, channel); - } - - private final boolean updateStatusAndInterrupt(AsyncHandler handler, HttpResponseStatus c) throws Exception { - return handler.onStatusReceived(c) != STATE.CONTINUE; - } - - private final boolean updateHeadersAndInterrupt(AsyncHandler handler, HttpResponseHeaders c) throws Exception { - return handler.onHeadersReceived(c) != STATE.CONTINUE; - } - - private final boolean updateBodyAndInterrupt(final NettyResponseFuture future, AsyncHandler handler, HttpResponseBodyPart c) - throws Exception { - boolean state = handler.onBodyPartReceived(c) != STATE.CONTINUE; - if (c.isUnderlyingConnectionToBeClosed()) - future.setKeepAlive(false); - return state; - } - - @Override - public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { - Channel channel = ctx.getChannel(); - Throwable cause = e.getCause(); - NettyResponseFuture future = null; - - if (e.getCause() instanceof PrematureChannelClosureException) { - return; - } - - if (LOGGER.isDebugEnabled()) { - LOGGER.debug("Unexpected I/O exception on channel {}", channel, cause); - } - - try { - if (cause instanceof ClosedChannelException) { - return; - } - - Object attachment = Channels.getAttachment(channel); - if (attachment instanceof NettyResponseFuture) { - future = (NettyResponseFuture) attachment; - future.attachChannel(null, false); - future.touch(); - - 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(); - fc = handleIoException(fc, future); - - if (fc.replayRequest()) { - replayRequest(future, fc, channel); - return; - } - } else { - // Close the channel so the recovering can occurs. - try { - channel.close(); - } catch (Throwable t) { - // Swallow. - } - return; - } - } - - if (StackTraceInspector.abortOnReadOrWriteException(cause)) { - LOGGER.debug("Trying to recover from dead Channel: {}", channel); - return; - } - } else if (attachment instanceof Callback) { - future = ((Callback) attachment).future(); - } - } catch (Throwable t) { - cause = t; - } - - if (future != null) { - try { - LOGGER.debug("Was unable to recover Future: {}", future); - abort(future, cause); - } catch (Throwable t) { - LOGGER.error(t.getMessage(), t); - } - } - - Protocol p = channel.getPipeline().get(HttpClientCodec.class) != null ? httpProtocol : webSocketProtocol; - p.onError(channel, e); - - channelManager.closeChannel(channel); - ctx.sendUpstream(e); - } - - public static NettyResponseFuture newFuture(UriComponents uri, Request request, AsyncHandler asyncHandler, - HttpRequest nettyRequest, AsyncHttpClientConfig config, ProxyServer proxyServer) { - - NettyResponseFuture f = new NettyResponseFuture(uri,// - request,// - asyncHandler,// - nettyRequest,// - config.getMaxRequestRetry(),// - request.getConnectionPoolKeyStrategy(),// - proxyServer); - - String expectHeader = request.getHeaders().getFirstValue(HttpHeaders.Names.EXPECT); - if (expectHeader != null && expectHeader.equalsIgnoreCase(HttpHeaders.Values.CONTINUE)) { - f.getAndSetWriteBody(false); - } - return f; - } - - public static class ThreadLocalBoolean extends ThreadLocal { - - private final boolean defaultValue; - - public ThreadLocalBoolean() { - this(false); - } - - public ThreadLocalBoolean(boolean defaultValue) { - this.defaultValue = defaultValue; - } - - @Override - protected Boolean initialValue() { - return defaultValue ? Boolean.TRUE : Boolean.FALSE; - } - } - - private static class NettyTransferAdapter extends TransferCompletionHandler.TransferAdapter { - - private final ChannelBuffer content; - private final FileInputStream file; - private int byteRead = 0; - - public NettyTransferAdapter(FluentCaseInsensitiveStringsMap headers, ChannelBuffer content, File file) throws IOException { - super(headers); - this.content = content; - if (file != null) { - this.file = new FileInputStream(file); - } else { - this.file = null; - } - } - - @Override - public void getBytes(byte[] bytes) { - if (content.writableBytes() != 0) { - content.getBytes(byteRead, bytes); - byteRead += bytes.length; - } else if (file != null) { - try { - byteRead += file.read(bytes); - } catch (IOException e) { - LOGGER.error(e.getMessage(), e); - } - } - } - } - - public AsyncHttpClientConfig getConfig() { - return config; - } - - private static final boolean validateWebSocketRequest(Request request, AsyncHandler asyncHandler) { - if (request.getMethod() != "GET" || !(asyncHandler instanceof WebSocketUpgradeHandler)) { - return false; - } - return true; - } - - private boolean exitAfterHandlingRedirect(Channel channel, NettyResponseFuture future, Request request, HttpResponse response, - int statusCode) throws Exception { - - if (AsyncHttpProviderUtils.followRedirect(config, request) - && (statusCode == 302 || statusCode == 301 || statusCode == 303 || statusCode == 307)) { - - if (future.incrementAndGetCurrentRedirectCount() < config.getMaxRedirects()) { - // allow 401 handling again - future.getAndSetAuth(false); - - HttpHeaders responseHeaders = response.headers(); - - String location = responseHeaders.get(HttpHeaders.Names.LOCATION); - UriComponents uri = UriComponents.create(future.getURI(), location); - if (!uri.equals(future.getURI())) { - final RequestBuilder nBuilder = new RequestBuilder(future.getRequest()); - - if (config.isRemoveQueryParamOnRedirect()) - nBuilder.resetQuery(); - else - nBuilder.addQueryParams(future.getRequest().getQueryParams()); - - if (!(statusCode < 302 || statusCode > 303) && !(statusCode == 302 && config.isStrict302Handling())) { - nBuilder.setMethod("GET"); - } - final boolean initialConnectionKeepAlive = future.isKeepAlive(); - final String initialPoolKey = getPoolKey(future); - future.setURI(uri); - UriComponents newURI = uri; - String targetScheme = request.getURI().getScheme(); - if (targetScheme.equals(WEBSOCKET)) { - newURI = newURI.withNewScheme(WEBSOCKET); - } - if (targetScheme.equals(WEBSOCKET_SSL)) { - newURI = newURI.withNewScheme(WEBSOCKET_SSL); - } - - LOGGER.debug("Redirecting to {}", newURI); - List setCookieHeaders = responseHeaders.getAll(HttpHeaders.Names.SET_COOKIE2); - if (!isNonEmpty(setCookieHeaders)) { - setCookieHeaders = responseHeaders.getAll(HttpHeaders.Names.SET_COOKIE); - } - - for (String cookieStr : setCookieHeaders) { - nBuilder.addOrReplaceCookie(CookieDecoder.decode(cookieStr)); - } - - Callback ac = newDrainCallable(future, channel, initialConnectionKeepAlive, initialPoolKey); - - if (response.isChunked()) { - // We must make sure there is no bytes left before executing the next request. - Channels.setAttachment(channel, ac); - } else { - ac.call(); - } - nextRequest(nBuilder.setURI(newURI).build(), future); - return true; - } - } else { - throw new MaxRedirectException("Maximum redirect reached: " + config.getMaxRedirects()); - } - } - return false; - } - - private final Callback newDrainCallable(final NettyResponseFuture future, final Channel channel, final boolean keepAlive, - final String poolKey) { - - return new Callback(future) { - public void call() throws Exception { - channelManager.tryToOfferChannelToPool(channel, keepAlive, poolKey); - } - }; - } - - private final void configureKeepAlive(NettyResponseFuture future, HttpResponse response) { - String connectionHeader = response.headers().get(HttpHeaders.Names.CONNECTION); - future.setKeepAlive(connectionHeader == null || connectionHeader.equalsIgnoreCase(HttpHeaders.Values.KEEP_ALIVE)); - } - - private final boolean exitAfterProcessingFilters(Channel channel, NettyResponseFuture future, HttpResponse response, - AsyncHandler handler, Request request, HttpResponseStatus status, HttpResponseHeaders responseHeaders) throws IOException { - if (!config.getResponseFilters().isEmpty()) { - FilterContext fc = new FilterContext.FilterContextBuilder().asyncHandler(handler).request(request).responseStatus(status) - .responseHeaders(responseHeaders).build(); - - for (ResponseFilter asyncFilter : config.getResponseFilters()) { - try { - fc = asyncFilter.filter(fc); - if (fc == null) { - throw new NullPointerException("FilterContext is null"); - } - } catch (FilterException efe) { - abort(future, efe); - } - } - - // The handler may have been wrapped. - future.setAsyncHandler(fc.getAsyncHandler()); - - // The request has changed - if (fc.replayRequest()) { - replayRequest(future, fc, channel); - return true; - } - } - return false; - } - - private final boolean exitAfterHandling401(// - final Channel channel,// - final NettyResponseFuture future,// - HttpResponse response,// - Request request,// - int statusCode,// - Realm realm,// - ProxyServer proxyServer,// - final RequestBuilder requestBuilder) throws Exception { - - if (statusCode == 401 && realm != null && !future.getAndSetAuth(true)) { - - List wwwAuthHeaders = getNettyHeaderValuesByCaseInsensitiveName(response.headers(), HttpHeaders.Names.WWW_AUTHENTICATE); - - if (!wwwAuthHeaders.isEmpty()) { - future.setState(NettyResponseFuture.STATE.NEW); - Realm newRealm = null; - - FluentCaseInsensitiveStringsMap requestHeaders = request.getHeaders(); - - if (!wwwAuthHeaders.contains("Kerberos") && (isNTLM(wwwAuthHeaders) || (wwwAuthHeaders.contains("Negotiate")))) { - // NTLM - newRealm = ntlmChallenge(wwwAuthHeaders, request, proxyServer, requestHeaders, realm, future, false); - } else if (wwwAuthHeaders.contains("Negotiate")) { - // SPNEGO KERBEROS - newRealm = kerberosChallenge(wwwAuthHeaders, request, proxyServer, requestHeaders, realm, future, false); - if (newRealm == null) - return true; - } else { - newRealm = new Realm.RealmBuilder().clone(realm) // - .setScheme(realm.getAuthScheme()) // - .setUri(request.getURI()) // - .setMethodName(request.getMethod()) // - .setUsePreemptiveAuth(true) // - .parseWWWAuthenticateHeader(wwwAuthHeaders.get(0))// - .build(); - } - - final Realm nr = newRealm; - - LOGGER.debug("Sending authentication to {}", request.getURI()); - final Request nextRequest = requestBuilder.setHeaders(requestHeaders).setRealm(nr).build(); - Callback ac = new Callback(future) { - public void call() throws Exception { - // not waiting for the channel to be drained, so we might ended up pooling the initial channel and creating a new one - drainChannel(channel, future); - nextRequest(nextRequest, future); - } - }; - - if (future.isKeepAlive() && response.isChunked()) - // we must make sure there is no chunk left before executing the next request - Channels.setAttachment(channel, ac); - else - // FIXME couldn't we reuse the channel right now? - ac.call(); - return true; - } - } - return false; - } - - private final boolean exitAfterHandling407(// - NettyResponseFuture future,// - HttpResponse response,// - Request request,// - int statusCode,// - Realm realm,// - ProxyServer proxyServer,// - final RequestBuilder requestBuilder) throws Exception { - - if (statusCode == 407 && realm != null && !future.getAndSetAuth(true)) { - List proxyAuth = getNettyHeaderValuesByCaseInsensitiveName(response.headers(), HttpHeaders.Names.PROXY_AUTHENTICATE); - if (!proxyAuth.isEmpty()) { - LOGGER.debug("Sending proxy authentication to {}", request.getURI()); - - future.setState(NettyResponseFuture.STATE.NEW); - Realm newRealm = null; - FluentCaseInsensitiveStringsMap requestHeaders = request.getHeaders(); - - if (!proxyAuth.contains("Kerberos") && (isNTLM(proxyAuth) || (proxyAuth.contains("Negotiate")))) { - newRealm = ntlmProxyChallenge(proxyAuth, request, proxyServer, requestHeaders, realm, future); - // SPNEGO KERBEROS - } else if (proxyAuth.contains("Negotiate")) { - newRealm = kerberosChallenge(proxyAuth, request, proxyServer, requestHeaders, realm, future, true); - if (newRealm == null) - return true; - } else { - newRealm = new Realm.RealmBuilder().clone(realm)// - .setScheme(realm.getAuthScheme())// - .setUri(request.getURI())// - .setMethodName("CONNECT")// - .setTargetProxy(true)// - .setUsePreemptiveAuth(true)// - .parseProxyAuthenticateHeader(proxyAuth.get(0))// - .build(); - } - - Request req = requestBuilder.setHeaders(requestHeaders).setRealm(newRealm).build(); - future.setReuseChannel(true); - future.setConnectAllowed(true); - nextRequest(req, future); - return true; - } - } - return false; - } - - private boolean exitAfterHandling100(Channel channel, NettyResponseFuture future, int statusCode) { - if (statusCode == 100) { - future.getAndSetWriteHeaders(false); - future.getAndSetWriteBody(true); - writeRequest(channel, config, future); - return true; - } - return false; - } - - private boolean exitAfterHandlingConnect(Channel channel,// - NettyResponseFuture future,// - Request request,// - ProxyServer proxyServer,// - int statusCode,// - RequestBuilder requestBuilder,// - HttpRequest nettyRequest) throws IOException { - - if (nettyRequest.getMethod().equals(HttpMethod.CONNECT) && statusCode == 200) { - - LOGGER.debug("Connected to {}:{}", proxyServer.getHost(), proxyServer.getPort()); - - if (future.isKeepAlive()) { - future.attachChannel(channel, true); - } - - try { - UriComponents requestURI = request.getURI(); - String scheme = requestURI.getScheme(); - String host = requestURI.getHost(); - int port = AsyncHttpProviderUtils.getDefaultPort(requestURI); - - LOGGER.debug("Connecting to proxy {} for scheme {}", proxyServer, scheme); - upgradeProtocol(channel.getPipeline(), scheme, host, port); - - } catch (Throwable ex) { - abort(future, ex); - } - Request req = requestBuilder.build(); - future.setReuseChannel(true); - future.setConnectAllowed(false); - nextRequest(req, future); - return true; - } - return false; - } - - private final boolean exitAfterHandlingStatus(Channel channel, NettyResponseFuture future, HttpResponse response, - AsyncHandler handler, HttpResponseStatus status) throws IOException, Exception { - if (!future.getAndSetStatusReceived(true) && updateStatusAndInterrupt(handler, status)) { - finishUpdate(future, channel, response.isChunked()); - return true; - } - return false; - } - - private final boolean exitAfterHandlingHeaders(Channel channel, NettyResponseFuture future, HttpResponse response, - AsyncHandler handler, HttpResponseHeaders responseHeaders) throws IOException, Exception { - if (!response.headers().isEmpty() && updateHeadersAndInterrupt(handler, responseHeaders)) { - finishUpdate(future, channel, response.isChunked()); - return true; - } - return false; - } - - private final boolean exitAfterHandlingBody(Channel channel, NettyResponseFuture future, HttpResponse response, - AsyncHandler handler) throws Exception { - if (!response.isChunked()) { - updateBodyAndInterrupt(future, handler, new ResponseBodyPart(response, null, true)); - finishUpdate(future, channel, false); - return true; - } - return false; - } - - private final boolean exitAfterHandlingHead(Channel channel, NettyResponseFuture future, HttpResponse response, - AsyncHandler handler, HttpRequest nettyRequest) throws Exception { - if (nettyRequest.getMethod().equals(HttpMethod.HEAD)) { - updateBodyAndInterrupt(future, handler, new ResponseBodyPart(response, null, true)); - markAsDone(future, channel); - drainChannel(channel, future); - } - return false; - } - - private final void handleHttpResponse(final HttpResponse response, final Channel channel, final NettyResponseFuture future, - AsyncHandler handler) throws Exception { - - HttpRequest nettyRequest = future.getNettyRequest(); - Request request = future.getRequest(); - ProxyServer proxyServer = future.getProxyServer(); - LOGGER.debug("\n\nRequest {}\n\nResponse {}\n", nettyRequest, response); - - // Required if there is some trailing headers. - future.setHttpResponse(response); - - configureKeepAlive(future, response); - - HttpResponseStatus status = new ResponseStatus(future.getURI(), config, response); - HttpResponseHeaders responseHeaders = new ResponseHeaders(response); - - if (exitAfterProcessingFilters(channel, future, response, handler, request, status, responseHeaders)) - return; - - final RequestBuilder requestBuilder = new RequestBuilder(future.getRequest()); - - Realm realm = request.getRealm() != null ? request.getRealm() : config.getRealm(); - - int statusCode = response.getStatus().getCode(); - - // FIXME - if (exitAfterHandling401(channel, future, response, request, statusCode, realm, proxyServer, requestBuilder) || // - exitAfterHandling407(future, response, request, statusCode, realm, proxyServer, requestBuilder) || // - exitAfterHandling100(channel, future, statusCode) || // - exitAfterHandlingRedirect(channel, future, request, response, statusCode) || // - exitAfterHandlingConnect(channel, future, request, proxyServer, statusCode, requestBuilder, nettyRequest) || // - exitAfterHandlingStatus(channel, future, response, handler, status) || // - exitAfterHandlingHeaders(channel, future, response, handler, responseHeaders) || // - exitAfterHandlingBody(channel, future, response, handler) || // - exitAfterHandlingHead(channel, future, response, handler, nettyRequest)) { - return; - } - } - - private final void handleChunk(final HttpChunk chunk, final Channel channel, final NettyResponseFuture future, - final AsyncHandler handler) throws Exception { - boolean last = chunk.isLast(); - // we don't notify updateBodyAndInterrupt with the last chunk as it's empty - if (last || updateBodyAndInterrupt(future, handler, new ResponseBodyPart(null, chunk, last))) { - - if (chunk instanceof HttpChunkTrailer) { - HttpChunkTrailer chunkTrailer = (HttpChunkTrailer) chunk; - if (!chunkTrailer.trailingHeaders().isEmpty()) { - ResponseHeaders responseHeaders = new ResponseHeaders(future.getHttpResponse(), chunkTrailer); - updateHeadersAndInterrupt(handler, responseHeaders); - } - } - finishUpdate(future, channel, !chunk.isLast()); - } - } - - private final class HttpProtocol implements Protocol { - - public void handle(final Channel channel, final MessageEvent e, final NettyResponseFuture future) throws Exception { - - // The connect timeout occurred. - if (future.isDone()) { - channelManager.closeChannel(channel); - return; - } - - future.touch(); - - AsyncHandler handler = future.getAsyncHandler(); - Object message = e.getMessage(); - try { - if (message instanceof HttpResponse) - handleHttpResponse((HttpResponse) message, channel, future, handler); - - else if (message instanceof HttpChunk) - handleChunk((HttpChunk) message, channel, future, handler); - - } catch (Exception t) { - if (t instanceof IOException && !config.getIOExceptionFilters().isEmpty()) { - FilterContext fc = new FilterContext.FilterContextBuilder().asyncHandler(handler).request(future.getRequest()) - .ioException(IOException.class.cast(t)).build(); - fc = handleIoException(fc, future); - - if (fc.replayRequest()) { - replayRequest(future, fc, channel); - return; - } - } - - try { - abort(future, t); - } finally { - finishUpdate(future, channel, false); - throw t; - } - } - } - - public void onError(Channel channel, ExceptionEvent e) { - } - - public void onClose(Channel channel, 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; - - // We don't need to synchronize as replacing the "ws-decoder" will process using the same thread. - private void invokeOnSucces(Channel channel, WebSocketUpgradeHandler h) { - if (!h.touchSuccess()) { - try { - h.onSuccess(new NettyWebSocket(channel)); - } catch (Exception ex) { - NettyAsyncHttpProvider.this.LOGGER.warn("onSuccess unexexpected exception", ex); - } - } - } - - @Override - public void handle(Channel channel, MessageEvent e, final NettyResponseFuture future) throws Exception { - - WebSocketUpgradeHandler wsUpgradeHandler = (WebSocketUpgradeHandler) future.getAsyncHandler(); - Request request = future.getRequest(); - - if (e.getMessage() instanceof HttpResponse) { - HttpResponse response = (HttpResponse) e.getMessage(); - HttpHeaders nettyResponseHeaders = response.headers(); - - HttpResponseStatus s = new ResponseStatus(future.getURI(), config, response); - HttpResponseHeaders responseHeaders = new ResponseHeaders(response); - FilterContext fc = new FilterContext.FilterContextBuilder().asyncHandler(wsUpgradeHandler).request(request) - .responseStatus(s).responseHeaders(responseHeaders).build(); - for (ResponseFilter asyncFilter : config.getResponseFilters()) { - try { - fc = asyncFilter.filter(fc); - if (fc == null) { - throw new NullPointerException("FilterContext is null"); - } - } catch (FilterException efe) { - abort(future, efe); - } - } - - // The handler may have been wrapped. - future.setAsyncHandler(fc.getAsyncHandler()); - - // The request has changed - if (fc.replayRequest()) { - replayRequest(future, fc, channel); - return; - } - - future.setHttpResponse(response); - if (exitAfterHandlingRedirect(channel, future, request, response, response.getStatus().getCode())) - return; - - 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 = nettyResponseHeaders.contains(HttpHeaders.Names.UPGRADE); - String c = nettyResponseHeaders.get(HttpHeaders.Names.CONNECTION); - if (c == null) { - c = nettyResponseHeaders.get("connection"); - } - - final boolean validConnection = c == null ? false : c.equalsIgnoreCase(HttpHeaders.Values.UPGRADE); - - s = new ResponseStatus(future.getURI(), config, response); - final boolean statusReceived = wsUpgradeHandler.onStatusReceived(s) == STATE.UPGRADE; - - if (!statusReceived) { - try { - wsUpgradeHandler.onCompleted(); - } finally { - future.done(); - } - return; - } - - final boolean headerOK = wsUpgradeHandler.onHeadersReceived(responseHeaders) == STATE.CONTINUE; - if (!headerOK || !validStatus || !validUpgrade || !validConnection) { - abort(future, new IOException("Invalid handshake response")); - return; - } - - String accept = nettyResponseHeaders.get(HttpHeaders.Names.SEC_WEBSOCKET_ACCEPT); - String key = WebSocketUtil.getAcceptKey(future.getNettyRequest().headers().get(HttpHeaders.Names.SEC_WEBSOCKET_KEY)); - if (accept == null || !accept.equals(key)) { - abort(future, new IOException(String.format("Invalid challenge. Actual: %s. Expected: %s", accept, key))); - return; - } - - channel.getPipeline().replace(HTTP_HANDLER, "ws-encoder", new WebSocket08FrameEncoder(true)); - channel.getPipeline().addBefore(WS_PROCESSOR, "ws-decoder", new WebSocket08FrameDecoder(false, false)); - - invokeOnSucces(channel, wsUpgradeHandler); - future.done(); - } else if (e.getMessage() instanceof WebSocketFrame) { - - invokeOnSucces(channel, wsUpgradeHandler); - - final WebSocketFrame frame = (WebSocketFrame) e.getMessage(); - - byte pendingOpcode = OPCODE_UNKNOWN; - if (frame instanceof TextWebSocketFrame) { - pendingOpcode = OPCODE_TEXT; - } else if (frame instanceof BinaryWebSocketFrame) { - pendingOpcode = OPCODE_BINARY; - } - - HttpChunk webSocketChunk = new HttpChunk() { - private ChannelBuffer content; - - @Override - public boolean isLast() { - return false; - } - - @Override - public ChannelBuffer getContent() { - return content; - } - - @Override - public void setContent(ChannelBuffer content) { - this.content = content; - } - }; - - if (frame.getBinaryData() != null) { - webSocketChunk.setContent(ChannelBuffers.wrappedBuffer(frame.getBinaryData())); - ResponseBodyPart rp = new ResponseBodyPart(null, webSocketChunk, true); - wsUpgradeHandler.onBodyPartReceived(rp); - - NettyWebSocket webSocket = NettyWebSocket.class.cast(wsUpgradeHandler.onCompleted()); - - if (webSocket != null) { - if (pendingOpcode == OPCODE_BINARY) { - webSocket.onBinaryFragment(rp.getBodyPartBytes(), frame.isFinalFragment()); - } else if (pendingOpcode == OPCODE_TEXT) { - webSocket.onTextFragment(frame.getBinaryData().toString(StandardCharsets.UTF_8), frame.isFinalFragment()); - } - - if (frame instanceof CloseWebSocketFrame) { - try { - Channels.setDiscard(channel); - webSocket.onClose(CloseWebSocketFrame.class.cast(frame).getStatusCode(), - CloseWebSocketFrame.class.cast(frame).getReasonText()); - } finally { - wsUpgradeHandler.resetSuccess(); - } - } - } else { - LOGGER.debug("UpgradeHandler returned a null NettyWebSocket "); - } - } - } else { - LOGGER.error("Invalid message {}", e.getMessage()); - } - } - - @Override - public void onError(Channel channel, ExceptionEvent e) { - try { - Object attachment = Channels.getAttachment(channel); - LOGGER.warn("onError {}", e); - if (!(attachment instanceof NettyResponseFuture)) { - return; - } - - NettyResponseFuture nettyResponse = (NettyResponseFuture) attachment; - WebSocketUpgradeHandler h = WebSocketUpgradeHandler.class.cast(nettyResponse.getAsyncHandler()); - - NettyWebSocket webSocket = NettyWebSocket.class.cast(h.onCompleted()); - if (webSocket != null) { - webSocket.onError(e.getCause()); - webSocket.close(); - } - } catch (Throwable t) { - LOGGER.error("onError", t); - } - } - - @Override - public void onClose(Channel channel, ChannelStateEvent e) { - LOGGER.trace("onClose {}", e); - - Object attachment = Channels.getAttachment(channel); - if (attachment instanceof NettyResponseFuture) { - try { - NettyResponseFuture nettyResponse = (NettyResponseFuture) attachment; - WebSocketUpgradeHandler h = WebSocketUpgradeHandler.class.cast(nettyResponse.getAsyncHandler()); - h.resetSuccess(); - - } catch (Throwable t) { - LOGGER.error("onError", t); - } - } - } - } - - public boolean isClose() { - return isClose.get(); - } - - public Timeout newTimeout(TimerTask task, long delay) { - return nettyTimer.newTimeout(task, delay, TimeUnit.MILLISECONDS); - } - - private static boolean isWebSocket(String scheme) { - return WEBSOCKET.equalsIgnoreCase(scheme) || WEBSOCKET_SSL.equalsIgnoreCase(scheme); - } - - private static boolean isSecure(String scheme) { - return HTTPS.equalsIgnoreCase(scheme) || WEBSOCKET_SSL.equalsIgnoreCase(scheme); + return nettyRequestSender.doConnect(request, asyncHandler, null, true, false); } - private static boolean isSecure(UriComponents uri) { - return isSecure(uri.getScheme()); + public boolean isClosed() { + return closed.get(); } } diff --git a/src/main/java/com/ning/http/client/providers/netty/Protocol.java b/src/main/java/com/ning/http/client/providers/netty/Protocol.java deleted file mode 100644 index 97bee0f6d2..0000000000 --- a/src/main/java/com/ning/http/client/providers/netty/Protocol.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * 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.providers.netty; - -import org.jboss.netty.channel.Channel; -import org.jboss.netty.channel.ChannelStateEvent; -import org.jboss.netty.channel.ExceptionEvent; -import org.jboss.netty.channel.MessageEvent; - -import com.ning.http.client.providers.netty.future.NettyResponseFuture; - -public interface Protocol { - - void handle(Channel channel, MessageEvent e, NettyResponseFuture future) throws Exception; - - void onError(Channel channel, ExceptionEvent e); - - void onClose(Channel channel, ChannelStateEvent e); -} diff --git a/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java b/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java index 1d5c29a82a..b13dd2ab5b 100644 --- a/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java +++ b/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java @@ -13,23 +13,62 @@ */ package com.ning.http.client.providers.netty.channel; +import static org.jboss.netty.channel.Channels.pipeline; +import static org.jboss.netty.handler.ssl.SslHandler.getDefaultBufferPool; + +import org.jboss.netty.bootstrap.ClientBootstrap; import org.jboss.netty.channel.Channel; +import org.jboss.netty.channel.ChannelPipeline; +import org.jboss.netty.channel.ChannelPipelineFactory; +import org.jboss.netty.channel.DefaultChannelFuture; import org.jboss.netty.channel.group.ChannelGroup; +import org.jboss.netty.channel.socket.ClientSocketChannelFactory; +import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory; +import org.jboss.netty.handler.codec.http.HttpClientCodec; +import org.jboss.netty.handler.codec.http.HttpContentDecompressor; +import org.jboss.netty.handler.codec.http.HttpMethod; +import org.jboss.netty.handler.ssl.SslHandler; +import org.jboss.netty.handler.stream.ChunkedWriteHandler; +import org.jboss.netty.util.Timer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.ning.http.client.AsyncHandler; import com.ning.http.client.AsyncHttpClientConfig; +import com.ning.http.client.ConnectionPoolKeyStrategy; +import com.ning.http.client.ProxyServer; +import com.ning.http.client.Request; +import com.ning.http.client.providers.netty.DiscardEvent; +import com.ning.http.client.providers.netty.NettyAsyncHttpProviderConfig; import com.ning.http.client.providers.netty.channel.pool.ChannelPool; import com.ning.http.client.providers.netty.future.NettyResponseFuture; -import com.ning.http.client.providers.netty.util.CleanupChannelGroup; +import com.ning.http.client.providers.netty.handler.Processor; +import com.ning.http.client.providers.netty.util.HttpUtil; +import com.ning.http.client.uri.UriComponents; +import com.ning.http.client.websocket.WebSocketUpgradeHandler; +import com.ning.http.util.SslUtils; + +import javax.net.ssl.SSLEngine; +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.util.Map.Entry; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import java.util.concurrent.Semaphore; public class ChannelManager { private static final Logger LOGGER = LoggerFactory.getLogger(ChannelManager.class); + public static final String HTTP_HANDLER = "httpHandler"; + public static final String SSL_HANDLER = "sslHandler"; + public static final String HTTP_PROCESSOR = "httpProcessor"; + public static final String WS_PROCESSOR = "wsProcessor"; + + private final AsyncHttpClientConfig config; + private final NettyAsyncHttpProviderConfig nettyConfig; private final ChannelPool channelPool; private final boolean maxTotalConnectionsEnabled; private final Semaphore freeChannels; @@ -38,12 +77,25 @@ public class ChannelManager { private final boolean maxConnectionsPerHostEnabled; private final ConcurrentHashMap freeChannelsPerHost; private final ConcurrentHashMap channelId2KeyPool; + private final long handshakeTimeoutInMillis; + private final Timer nettyTimer; + + private final ClientSocketChannelFactory socketChannelFactory; + private final boolean allowReleaseSocketChannelFactory; + private final ClientBootstrap plainBootstrap; + private final ClientBootstrap secureBootstrap; + private final ClientBootstrap webSocketBootstrap; + private final ClientBootstrap secureWebSocketBootstrap; - public ChannelManager(AsyncHttpClientConfig config, ChannelPool channelPool) { + public ChannelManager(AsyncHttpClientConfig config, NettyAsyncHttpProviderConfig nettyConfig, ChannelPool channelPool, Timer nettyTimer) { + + this.config = config; + this.nettyConfig = nettyConfig; this.channelPool = channelPool; + this.nettyTimer = nettyTimer; maxTotalConnectionsEnabled = config.getMaxConnections() > 0; - + if (maxTotalConnectionsEnabled) { openChannels = new CleanupChannelGroup("asyncHttpClient") { @Override @@ -71,7 +123,7 @@ public boolean remove(Object o) { maxConnectionsPerHost = config.getMaxConnectionsPerHost(); maxConnectionsPerHostEnabled = config.getMaxConnectionsPerHost() > 0; - + if (maxConnectionsPerHostEnabled) { freeChannelsPerHost = new ConcurrentHashMap(); channelId2KeyPool = new ConcurrentHashMap(); @@ -79,6 +131,94 @@ public boolean remove(Object o) { freeChannelsPerHost = null; channelId2KeyPool = null; } + + handshakeTimeoutInMillis = nettyConfig.getHandshakeTimeoutInMillis(); + + if (nettyConfig.getSocketChannelFactory() != null) { + socketChannelFactory = nettyConfig.getSocketChannelFactory(); + // cannot allow releasing shared channel factory + allowReleaseSocketChannelFactory = false; + + } else { + ExecutorService e = nettyConfig.getBossExecutorService(); + if (e == null) + e = Executors.newCachedThreadPool(); + int numWorkers = config.getIoThreadMultiplier() * Runtime.getRuntime().availableProcessors(); + LOGGER.trace("Number of application's worker threads is {}", numWorkers); + socketChannelFactory = new NioClientSocketChannelFactory(e, config.executorService(), numWorkers); + allowReleaseSocketChannelFactory = true; + } + + plainBootstrap = new ClientBootstrap(socketChannelFactory); + secureBootstrap = new ClientBootstrap(socketChannelFactory); + webSocketBootstrap = new ClientBootstrap(socketChannelFactory); + secureWebSocketBootstrap = new ClientBootstrap(socketChannelFactory); + + DefaultChannelFuture.setUseDeadLockChecker(nettyConfig.isUseDeadLockChecker()); + + // FIXME isn't there a constant for this name??? + nettyConfig.addProperty("connectTimeoutMillis", config.getConnectionTimeout()); + for (Entry entry : nettyConfig.propertiesSet()) { + String key = entry.getKey(); + Object value = entry.getValue(); + plainBootstrap.setOption(key, value); + webSocketBootstrap.setOption(key, value); + secureBootstrap.setOption(key, value); + secureWebSocketBootstrap.setOption(key, value); + } + } + + public void configureBootstraps(final Processor httpProcessor, final Processor webSocketProcessor) { + + final boolean compressionEnabled = config.isCompressionEnabled(); + + plainBootstrap.setPipelineFactory(new ChannelPipelineFactory() { + + public ChannelPipeline getPipeline() throws Exception { + ChannelPipeline pipeline = pipeline(); + pipeline.addLast(HTTP_HANDLER, createHttpClientCodec()); + if (compressionEnabled) + pipeline.addLast("inflater", new HttpContentDecompressor()); + pipeline.addLast("chunkedWriter", new ChunkedWriteHandler()); + pipeline.addLast(HTTP_PROCESSOR, httpProcessor); + return pipeline; + } + }); + + webSocketBootstrap.setPipelineFactory(new ChannelPipelineFactory() { + + public ChannelPipeline getPipeline() throws Exception { + ChannelPipeline pipeline = pipeline(); + pipeline.addLast(HTTP_HANDLER, createHttpClientCodec()); + pipeline.addLast(WS_PROCESSOR, webSocketProcessor); + return pipeline; + } + }); + + secureBootstrap.setPipelineFactory(new ChannelPipelineFactory() { + + public ChannelPipeline getPipeline() throws Exception { + ChannelPipeline pipeline = pipeline(); + pipeline.addLast(SSL_HANDLER, new SslInitializer(ChannelManager.this)); + pipeline.addLast(HTTP_HANDLER, createHttpsClientCodec()); + if (compressionEnabled) + pipeline.addLast("inflater", new HttpContentDecompressor()); + pipeline.addLast("chunkedWriter", new ChunkedWriteHandler()); + pipeline.addLast(HTTP_PROCESSOR, httpProcessor); + return pipeline; + } + }); + + secureWebSocketBootstrap.setPipelineFactory(new ChannelPipelineFactory() { + + public ChannelPipeline getPipeline() throws Exception { + ChannelPipeline pipeline = pipeline(); + pipeline.addLast(SSL_HANDLER, new SslInitializer(ChannelManager.this)); + pipeline.addLast(HTTP_HANDLER, createHttpsClientCodec()); + pipeline.addLast(WS_PROCESSOR, webSocketProcessor); + return pipeline; + } + }); } public final void tryToOfferChannelToPool(Channel channel, boolean keepAlive, String poolKey) { @@ -117,19 +257,19 @@ private Semaphore getFreeConnectionsForHost(String poolKey) { } return freeConnections; } - + private boolean tryAcquirePerHost(String poolKey) { return !maxConnectionsPerHostEnabled || getFreeConnectionsForHost(poolKey).tryAcquire(); } - + public boolean preemptChannel(String poolKey) { return channelPool.isOpen() && tryAcquireGlobal() && tryAcquirePerHost(poolKey); } - public void destroy() { + public void close() { channelPool.destroy(); openChannels.close(); - + for (Channel channel : openChannels) { Object attachment = Channels.getAttachment(channel); if (attachment instanceof NettyResponseFuture) { @@ -137,6 +277,15 @@ public void destroy() { future.cancelTimeouts(); } } + + config.executorService().shutdown(); + if (allowReleaseSocketChannelFactory) { + socketChannelFactory.releaseExternalResources(); + plainBootstrap.releaseExternalResources(); + secureBootstrap.releaseExternalResources(); + webSocketBootstrap.releaseExternalResources(); + secureWebSocketBootstrap.releaseExternalResources(); + } } public void closeChannel(Channel channel) { @@ -165,4 +314,73 @@ public void abortChannelPreemption(String poolKey) { public void registerOpenChannel(Channel channel) { openChannels.add(channel); } + + private HttpClientCodec createHttpClientCodec() { + return new HttpClientCodec(nettyConfig.getHttpClientCodecMaxInitialLineLength(),// + nettyConfig.getHttpClientCodecMaxHeaderSize(),// + nettyConfig.getHttpClientCodecMaxChunkSize()); + } + + private HttpClientCodec createHttpsClientCodec() { + return new HttpClientCodec(nettyConfig.getHttpClientCodecMaxInitialLineLength(),// + nettyConfig.getHttpClientCodecMaxHeaderSize(),// + nettyConfig.getHttpClientCodecMaxChunkSize()); + } + + public SslHandler createSslHandler(String peerHost, int peerPort) throws GeneralSecurityException, IOException { + SSLEngine sslEngine = SslUtils.getInstance().createClientSSLEngine(config, peerHost, peerPort); + return handshakeTimeoutInMillis > 0 ? new SslHandler(sslEngine, getDefaultBufferPool(), false, nettyTimer, handshakeTimeoutInMillis) + : new SslHandler(sslEngine); + } + + public void upgradeProtocol(ChannelPipeline pipeline, String scheme, String host, int port, Processor webSocketProcessor) + throws IOException, GeneralSecurityException { + if (pipeline.get(HTTP_HANDLER) != null) + pipeline.remove(HTTP_HANDLER); + + if (HttpUtil.isSecure(scheme)) { + if (pipeline.get(SSL_HANDLER) == null) { + pipeline.addFirst(HTTP_HANDLER, createHttpClientCodec()); + pipeline.addFirst(SSL_HANDLER, createSslHandler(host, port)); + } else { + pipeline.addAfter(SSL_HANDLER, HTTP_HANDLER, createHttpClientCodec()); + } + + } else { + pipeline.addFirst(HTTP_HANDLER, createHttpClientCodec()); + } + + if (HttpUtil.isWebSocket(scheme)) + pipeline.replace(HTTP_PROCESSOR, WS_PROCESSOR, webSocketProcessor); + } + + public boolean validateWebSocketRequest(Request request, AsyncHandler asyncHandler) { + return request.getMethod().equals(HttpMethod.GET.getName()) && asyncHandler instanceof WebSocketUpgradeHandler; + } + + public String getPoolKey(NettyResponseFuture future) { + return getPoolKey(future.getURI(), future.getProxyServer(), future.getConnectionPoolKeyStrategy()); + } + + public String getPoolKey(UriComponents uri, ProxyServer proxy, ConnectionPoolKeyStrategy strategy) { + String serverPart = strategy.getKey(uri); + return proxy != null ? proxy.getUrl() + serverPart : serverPart; + } + + public Channel verifyChannelPipeline(Channel channel, String scheme) throws IOException, GeneralSecurityException { + + if (channel.getPipeline().get(SSL_HANDLER) != null && HttpUtil.HTTP.equalsIgnoreCase(scheme)) { + channel.getPipeline().remove(SSL_HANDLER); + } else if (channel.getPipeline().get(HTTP_HANDLER) != null && HttpUtil.HTTP.equalsIgnoreCase(scheme)) { + return channel; + } else if (channel.getPipeline().get(SSL_HANDLER) == null && HttpUtil.isSecure(scheme)) { + channel.getPipeline().addFirst(SSL_HANDLER, new SslInitializer(this)); + } + return channel; + } + + public ClientBootstrap getBootstrap(String scheme, boolean useProxy, boolean useSSl) { + return (scheme.startsWith(HttpUtil.WEBSOCKET) && !useProxy) ? (useSSl ? secureWebSocketBootstrap : webSocketBootstrap) + : (useSSl ? secureBootstrap : plainBootstrap); + } } diff --git a/src/main/java/com/ning/http/client/providers/netty/util/CleanupChannelGroup.java b/src/main/java/com/ning/http/client/providers/netty/channel/CleanupChannelGroup.java similarity index 98% rename from src/main/java/com/ning/http/client/providers/netty/util/CleanupChannelGroup.java rename to src/main/java/com/ning/http/client/providers/netty/channel/CleanupChannelGroup.java index c09f28084e..0e447d2ee3 100644 --- a/src/main/java/com/ning/http/client/providers/netty/util/CleanupChannelGroup.java +++ b/src/main/java/com/ning/http/client/providers/netty/channel/CleanupChannelGroup.java @@ -26,7 +26,7 @@ * limitations under the License. */ -package com.ning.http.client.providers.netty.util; +package com.ning.http.client.providers.netty.channel; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFuture; diff --git a/src/main/java/com/ning/http/client/providers/netty/channel/SslInitializer.java b/src/main/java/com/ning/http/client/providers/netty/channel/SslInitializer.java index eb4d458c7d..47027fbdd6 100644 --- a/src/main/java/com/ning/http/client/providers/netty/channel/SslInitializer.java +++ b/src/main/java/com/ning/http/client/providers/netty/channel/SslInitializer.java @@ -20,8 +20,6 @@ import org.jboss.netty.channel.SimpleChannelDownstreamHandler; import org.jboss.netty.handler.ssl.SslHandler; -import com.ning.http.client.providers.netty.NettyAsyncHttpProvider; - import java.net.InetSocketAddress; /** @@ -31,21 +29,21 @@ */ public class SslInitializer extends SimpleChannelDownstreamHandler { - private final NettyAsyncHttpProvider provider; + private final ChannelManager channelManager; - public SslInitializer(NettyAsyncHttpProvider provider) { - this.provider = provider; + public SslInitializer(ChannelManager channelManager) { + this.channelManager = channelManager; } public void connectRequested(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { - + InetSocketAddress remoteInetSocketAddress = (InetSocketAddress) e.getValue(); String peerHost = remoteInetSocketAddress.getHostName(); int peerPort = remoteInetSocketAddress.getPort(); - SslHandler sslHandler = provider.createSslHandler(peerHost, peerPort); + SslHandler sslHandler = channelManager.createSslHandler(peerHost, peerPort); - ctx.getPipeline().replace(NettyAsyncHttpProvider.SSL_HANDLER, NettyAsyncHttpProvider.SSL_HANDLER, sslHandler); + ctx.getPipeline().replace(ChannelManager.SSL_HANDLER, ChannelManager.SSL_HANDLER, sslHandler); ctx.sendDownstream(e); } diff --git a/src/main/java/com/ning/http/client/providers/netty/channel/pool/DefaultChannelPool.java b/src/main/java/com/ning/http/client/providers/netty/channel/pool/DefaultChannelPool.java index dde0e362e5..894211aeaa 100644 --- a/src/main/java/com/ning/http/client/providers/netty/channel/pool/DefaultChannelPool.java +++ b/src/main/java/com/ning/http/client/providers/netty/channel/pool/DefaultChannelPool.java @@ -31,6 +31,7 @@ import org.slf4j.LoggerFactory; import com.ning.http.client.AsyncHttpClientConfig; +import com.ning.http.client.providers.netty.channel.ChannelManager; import com.ning.http.client.providers.netty.channel.Channels; import com.ning.http.client.providers.netty.future.NettyResponseFuture; diff --git a/src/main/java/com/ning/http/client/providers/netty/future/NettyResponseFuture.java b/src/main/java/com/ning/http/client/providers/netty/future/NettyResponseFuture.java index 70d7289dca..49d27f4e41 100755 --- a/src/main/java/com/ning/http/client/providers/netty/future/NettyResponseFuture.java +++ b/src/main/java/com/ning/http/client/providers/netty/future/NettyResponseFuture.java @@ -17,18 +17,6 @@ import static com.ning.http.util.DateUtils.millisTime; -import java.net.SocketAddress; -import java.util.concurrent.CancellationException; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; -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; @@ -44,6 +32,18 @@ import com.ning.http.client.providers.netty.request.timeout.TimeoutsHolder; import com.ning.http.client.uri.UriComponents; +import java.net.SocketAddress; +import java.util.concurrent.CancellationException; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicReference; + /** * A {@link Future} that can be used to track when an asynchronous HTTP request has been fully processed. * diff --git a/src/main/java/com/ning/http/client/providers/netty/handler/HttpProtocol.java b/src/main/java/com/ning/http/client/providers/netty/handler/HttpProtocol.java new file mode 100644 index 0000000000..160d007a21 --- /dev/null +++ b/src/main/java/com/ning/http/client/providers/netty/handler/HttpProtocol.java @@ -0,0 +1,537 @@ +package com.ning.http.client.providers.netty.handler; + +import static com.ning.http.util.MiscUtils.isNonEmpty; + +import org.jboss.netty.channel.Channel; +import org.jboss.netty.channel.ChannelStateEvent; +import org.jboss.netty.channel.ExceptionEvent; +import org.jboss.netty.channel.MessageEvent; +import org.jboss.netty.handler.codec.http.HttpChunk; +import org.jboss.netty.handler.codec.http.HttpChunkTrailer; +import org.jboss.netty.handler.codec.http.HttpHeaders; +import org.jboss.netty.handler.codec.http.HttpMethod; +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.AsyncHandler.STATE; +import com.ning.http.client.AsyncHttpClientConfig; +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.ProxyServer; +import com.ning.http.client.Realm; +import com.ning.http.client.Request; +import com.ning.http.client.RequestBuilder; +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.ntlm.NTLMEngine; +import com.ning.http.client.ntlm.NTLMEngineException; +import com.ning.http.client.providers.netty.Callback; +import com.ning.http.client.providers.netty.channel.ChannelManager; +import com.ning.http.client.providers.netty.channel.Channels; +import com.ning.http.client.providers.netty.future.NettyResponseFuture; +import com.ning.http.client.providers.netty.request.NettyRequestSender; +import com.ning.http.client.providers.netty.response.ResponseBodyPart; +import com.ning.http.client.providers.netty.response.ResponseHeaders; +import com.ning.http.client.providers.netty.response.ResponseStatus; +import com.ning.http.client.providers.netty.spnego.SpnegoEngine; +import com.ning.http.client.providers.netty.util.HttpUtil; +import com.ning.http.client.uri.UriComponents; +import com.ning.http.util.AsyncHttpProviderUtils; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.util.List; + +public class HttpProtocol extends Protocol { + + private static final Logger LOGGER = LoggerFactory.getLogger(HttpProtocol.class); + + private final Processor webSocketProcessor; + + public HttpProtocol(ChannelManager channelManager, AsyncHttpClientConfig config, NettyRequestSender nettyRequestSender, Processor webSocketProcessor) { + super(channelManager, config, nettyRequestSender); + this.webSocketProcessor = webSocketProcessor; + } + + private void markAsDone(final NettyResponseFuture future, final Channel channel) throws MalformedURLException { + // We need to make sure everything is OK before adding the connection back to the pool. + try { + future.done(); + } catch (Throwable t) { + // Never propagate exception once we know we are done. + LOGGER.debug(t.getMessage(), t); + } + + if (!future.isKeepAlive() || !channel.isReadable()) { + channelManager.closeChannel(channel); + } + } + + private final void configureKeepAlive(NettyResponseFuture future, HttpResponse response) { + String connectionHeader = response.headers().get(HttpHeaders.Names.CONNECTION); + future.setKeepAlive(connectionHeader == null || connectionHeader.equalsIgnoreCase(HttpHeaders.Values.KEEP_ALIVE)); + } + + private Realm kerberosChallenge(List proxyAuth, Request request, ProxyServer proxyServer, + FluentCaseInsensitiveStringsMap headers, Realm realm, NettyResponseFuture future, boolean proxyInd) + throws NTLMEngineException { + + UriComponents uri = request.getURI(); + String host = request.getVirtualHost() != null ? request.getVirtualHost() : uri.getHost(); + String server = proxyServer == null ? host : proxyServer.getHost(); + try { + String challengeHeader = SpnegoEngine.INSTANCE.generateToken(server); + headers.remove(HttpHeaders.Names.AUTHORIZATION); + headers.add(HttpHeaders.Names.AUTHORIZATION, "Negotiate " + challengeHeader); + + Realm.RealmBuilder realmBuilder; + if (realm != null) { + realmBuilder = new Realm.RealmBuilder().clone(realm); + } else { + realmBuilder = new Realm.RealmBuilder(); + } + return realmBuilder.setUri(uri).setMethodName(request.getMethod()).setScheme(Realm.AuthScheme.KERBEROS).build(); + } catch (Throwable throwable) { + if (HttpUtil.isNTLM(proxyAuth)) + return ntlmChallenge(proxyAuth, request, proxyServer, headers, realm, future, proxyInd); + nettyRequestSender.abort(future, throwable); + return null; + } + } + + private String authorizationHeaderName(boolean proxyInd) { + return proxyInd ? HttpHeaders.Names.PROXY_AUTHORIZATION : HttpHeaders.Names.AUTHORIZATION; + } + + private void addNTLMAuthorization(FluentCaseInsensitiveStringsMap headers, String challengeHeader, boolean proxyInd) { + headers.add(authorizationHeaderName(proxyInd), "NTLM " + challengeHeader); + } + + private void addType3NTLMAuthorizationHeader(List auth, FluentCaseInsensitiveStringsMap headers, String username, + String password, String domain, String workstation, boolean proxyInd) throws NTLMEngineException { + headers.remove(authorizationHeaderName(proxyInd)); + + // Beware of space!, see #462 + if (isNonEmpty(auth) && auth.get(0).startsWith("NTLM ")) { + String serverChallenge = auth.get(0).trim().substring("NTLM ".length()); + String challengeHeader = NTLMEngine.INSTANCE.generateType3Msg(username, password, domain, workstation, serverChallenge); + addNTLMAuthorization(headers, challengeHeader, proxyInd); + } + } + + private Realm ntlmChallenge(List wwwAuth, Request request, ProxyServer proxyServer, FluentCaseInsensitiveStringsMap headers, + Realm realm, NettyResponseFuture future, boolean proxyInd) throws NTLMEngineException { + + boolean useRealm = (proxyServer == null && realm != null); + + String ntlmDomain = useRealm ? realm.getNtlmDomain() : proxyServer.getNtlmDomain(); + String ntlmHost = useRealm ? realm.getNtlmHost() : proxyServer.getHost(); + String principal = useRealm ? realm.getPrincipal() : proxyServer.getPrincipal(); + String password = useRealm ? realm.getPassword() : proxyServer.getPassword(); + UriComponents uri = request.getURI(); + + Realm.RealmBuilder realmBuilder; + if (realm != null && !realm.isNtlmMessageType2Received()) { + String challengeHeader = NTLMEngine.INSTANCE.generateType1Msg(ntlmDomain, ntlmHost); + addNTLMAuthorization(headers, challengeHeader, proxyInd); + realmBuilder = new Realm.RealmBuilder().clone(realm).setScheme(realm.getAuthScheme()).setNtlmMessageType2Received(true); + future.getAndSetAuth(false); + } else { + addType3NTLMAuthorizationHeader(wwwAuth, headers, principal, password, ntlmDomain, ntlmHost, proxyInd); + + if (realm != null) { + realmBuilder = new Realm.RealmBuilder().clone(realm).setScheme(realm.getAuthScheme()); + } else { + realmBuilder = new Realm.RealmBuilder().setScheme(Realm.AuthScheme.NTLM); + } + } + + return realmBuilder.setUri(uri).setMethodName(request.getMethod()).build(); + } + + private Realm ntlmProxyChallenge(List wwwAuth, Request request, ProxyServer proxyServer, + FluentCaseInsensitiveStringsMap headers, Realm realm, NettyResponseFuture future) throws NTLMEngineException { + future.getAndSetAuth(false); + + addType3NTLMAuthorizationHeader(wwwAuth, headers, proxyServer.getPrincipal(), proxyServer.getPassword(), + proxyServer.getNtlmDomain(), proxyServer.getHost(), true); + + Realm.RealmBuilder realmBuilder = new Realm.RealmBuilder(); + if (realm != null) { + realmBuilder = realmBuilder.clone(realm); + } + return realmBuilder.setUri(request.getURI()).setMethodName(request.getMethod()).build(); + } + + private final boolean exitAfterProcessingFilters(Channel channel, NettyResponseFuture future, HttpResponse response, + AsyncHandler handler, Request request, HttpResponseStatus status, HttpResponseHeaders responseHeaders) throws IOException { + if (!config.getResponseFilters().isEmpty()) { + FilterContext fc = new FilterContext.FilterContextBuilder().asyncHandler(handler).request(request).responseStatus(status) + .responseHeaders(responseHeaders).build(); + + for (ResponseFilter asyncFilter : config.getResponseFilters()) { + try { + fc = asyncFilter.filter(fc); + if (fc == null) { + throw new NullPointerException("FilterContext is null"); + } + } catch (FilterException efe) { + nettyRequestSender.abort(future, efe); + } + } + + // The handler may have been wrapped. + future.setAsyncHandler(fc.getAsyncHandler()); + + // The request has changed + if (fc.replayRequest()) { + replayRequest(future, fc, channel); + return true; + } + } + return false; + } + + private final boolean exitAfterHandling401(// + final Channel channel,// + final NettyResponseFuture future,// + HttpResponse response,// + Request request,// + int statusCode,// + Realm realm,// + ProxyServer proxyServer,// + final RequestBuilder requestBuilder) throws Exception { + + if (statusCode == 401 && realm != null && !future.getAndSetAuth(true)) { + + List wwwAuthHeaders = HttpUtil.getNettyHeaderValuesByCaseInsensitiveName(response.headers(), + HttpHeaders.Names.WWW_AUTHENTICATE); + + if (!wwwAuthHeaders.isEmpty()) { + future.setState(NettyResponseFuture.STATE.NEW); + Realm newRealm = null; + + FluentCaseInsensitiveStringsMap requestHeaders = request.getHeaders(); + + if (!wwwAuthHeaders.contains("Kerberos") && (HttpUtil.isNTLM(wwwAuthHeaders) || (wwwAuthHeaders.contains("Negotiate")))) { + // NTLM + newRealm = ntlmChallenge(wwwAuthHeaders, request, proxyServer, requestHeaders, realm, future, false); + } else if (wwwAuthHeaders.contains("Negotiate")) { + // SPNEGO KERBEROS + newRealm = kerberosChallenge(wwwAuthHeaders, request, proxyServer, requestHeaders, realm, future, false); + if (newRealm == null) + return true; + } else { + newRealm = new Realm.RealmBuilder().clone(realm) // + .setScheme(realm.getAuthScheme()) // + .setUri(request.getURI()) // + .setMethodName(request.getMethod()) // + .setUsePreemptiveAuth(true) // + .parseWWWAuthenticateHeader(wwwAuthHeaders.get(0))// + .build(); + } + + final Realm nr = newRealm; + + LOGGER.debug("Sending authentication to {}", request.getURI()); + final Request nextRequest = requestBuilder.setHeaders(requestHeaders).setRealm(nr).build(); + Callback ac = new Callback(future) { + public void call() throws Exception { + // not waiting for the channel to be drained, so we might ended up pooling the initial channel and creating a new one + nettyRequestSender.drainChannel(channel, future); + nettyRequestSender.nextRequest(nextRequest, future); + } + }; + + if (future.isKeepAlive() && response.isChunked()) + // we must make sure there is no chunk left before executing the next request + Channels.setAttachment(channel, ac); + else + // FIXME couldn't we reuse the channel right now? + ac.call(); + return true; + } + } + return false; + } + + private final boolean exitAfterHandling407(// + NettyResponseFuture future,// + HttpResponse response,// + Request request,// + int statusCode,// + Realm realm,// + ProxyServer proxyServer,// + final RequestBuilder requestBuilder) throws Exception { + + if (statusCode == 407 && realm != null && !future.getAndSetAuth(true)) { + List proxyAuth = HttpUtil.getNettyHeaderValuesByCaseInsensitiveName(response.headers(), + HttpHeaders.Names.PROXY_AUTHENTICATE); + if (!proxyAuth.isEmpty()) { + LOGGER.debug("Sending proxy authentication to {}", request.getURI()); + + future.setState(NettyResponseFuture.STATE.NEW); + Realm newRealm = null; + FluentCaseInsensitiveStringsMap requestHeaders = request.getHeaders(); + + if (!proxyAuth.contains("Kerberos") && (HttpUtil.isNTLM(proxyAuth) || (proxyAuth.contains("Negotiate")))) { + newRealm = ntlmProxyChallenge(proxyAuth, request, proxyServer, requestHeaders, realm, future); + // SPNEGO KERBEROS + } else if (proxyAuth.contains("Negotiate")) { + newRealm = kerberosChallenge(proxyAuth, request, proxyServer, requestHeaders, realm, future, true); + if (newRealm == null) + return true; + } else { + newRealm = new Realm.RealmBuilder().clone(realm)// + .setScheme(realm.getAuthScheme())// + .setUri(request.getURI())// + .setMethodName("CONNECT")// + .setTargetProxy(true)// + .setUsePreemptiveAuth(true)// + .parseProxyAuthenticateHeader(proxyAuth.get(0))// + .build(); + } + + Request req = requestBuilder.setHeaders(requestHeaders).setRealm(newRealm).build(); + future.setReuseChannel(true); + future.setConnectAllowed(true); + nettyRequestSender.nextRequest(req, future); + return true; + } + } + return false; + } + + private boolean exitAfterHandling100(Channel channel, NettyResponseFuture future, int statusCode) { + if (statusCode == 100) { + future.getAndSetWriteHeaders(false); + future.getAndSetWriteBody(true); + nettyRequestSender.writeRequest(channel, config, future); + return true; + } + return false; + } + + private boolean exitAfterHandlingConnect(Channel channel,// + NettyResponseFuture future,// + Request request,// + ProxyServer proxyServer,// + int statusCode,// + RequestBuilder requestBuilder,// + HttpRequest nettyRequest) throws IOException { + + if (nettyRequest.getMethod().equals(HttpMethod.CONNECT) && statusCode == 200) { + + LOGGER.debug("Connected to {}:{}", proxyServer.getHost(), proxyServer.getPort()); + + if (future.isKeepAlive()) { + future.attachChannel(channel, true); + } + + try { + UriComponents requestURI = request.getURI(); + String scheme = requestURI.getScheme(); + String host = requestURI.getHost(); + int port = AsyncHttpProviderUtils.getDefaultPort(requestURI); + + LOGGER.debug("Connecting to proxy {} for scheme {}", proxyServer, scheme); + channelManager.upgradeProtocol(channel.getPipeline(), scheme, host, port, webSocketProcessor); + + } catch (Throwable ex) { + nettyRequestSender.abort(future, ex); + } + Request req = requestBuilder.build(); + future.setReuseChannel(true); + future.setConnectAllowed(false); + nettyRequestSender.nextRequest(req, future); + return true; + } + return false; + } + + private final boolean updateStatusAndInterrupt(AsyncHandler handler, HttpResponseStatus c) throws Exception { + return handler.onStatusReceived(c) != STATE.CONTINUE; + } + + private final boolean updateHeadersAndInterrupt(AsyncHandler handler, HttpResponseHeaders c) throws Exception { + return handler.onHeadersReceived(c) != STATE.CONTINUE; + } + + private final boolean updateBodyAndInterrupt(final NettyResponseFuture future, AsyncHandler handler, HttpResponseBodyPart c) + throws Exception { + boolean state = handler.onBodyPartReceived(c) != STATE.CONTINUE; + if (c.isUnderlyingConnectionToBeClosed()) + future.setKeepAlive(false); + return state; + } + + private final boolean exitAfterHandlingStatus(Channel channel, NettyResponseFuture future, HttpResponse response, + AsyncHandler handler, HttpResponseStatus status) throws IOException, Exception { + if (!future.getAndSetStatusReceived(true) && updateStatusAndInterrupt(handler, status)) { + finishUpdate(future, channel, response.isChunked()); + return true; + } + return false; + } + + private final boolean exitAfterHandlingHeaders(Channel channel, NettyResponseFuture future, HttpResponse response, + AsyncHandler handler, HttpResponseHeaders responseHeaders) throws IOException, Exception { + if (!response.headers().isEmpty() && updateHeadersAndInterrupt(handler, responseHeaders)) { + finishUpdate(future, channel, response.isChunked()); + return true; + } + return false; + } + + private final boolean exitAfterHandlingBody(Channel channel, NettyResponseFuture future, HttpResponse response, + AsyncHandler handler) throws Exception { + if (!response.isChunked()) { + updateBodyAndInterrupt(future, handler, new ResponseBodyPart(response, null, true)); + finishUpdate(future, channel, false); + return true; + } + return false; + } + + private final boolean exitAfterHandlingHead(Channel channel, NettyResponseFuture future, HttpResponse response, + AsyncHandler handler, HttpRequest nettyRequest) throws Exception { + if (nettyRequest.getMethod().equals(HttpMethod.HEAD)) { + updateBodyAndInterrupt(future, handler, new ResponseBodyPart(response, null, true)); + markAsDone(future, channel); + nettyRequestSender.drainChannel(channel, future); + } + return false; + } + + private final void handleHttpResponse(final HttpResponse response, final Channel channel, final NettyResponseFuture future, + AsyncHandler handler) throws Exception { + + HttpRequest nettyRequest = future.getNettyRequest(); + Request request = future.getRequest(); + ProxyServer proxyServer = future.getProxyServer(); + LOGGER.debug("\n\nRequest {}\n\nResponse {}\n", nettyRequest, response); + + // Required if there is some trailing headers. + future.setHttpResponse(response); + + configureKeepAlive(future, response); + + HttpResponseStatus status = new ResponseStatus(future.getURI(), config, response); + HttpResponseHeaders responseHeaders = new ResponseHeaders(response); + + if (exitAfterProcessingFilters(channel, future, response, handler, request, status, responseHeaders)) + return; + + final RequestBuilder requestBuilder = new RequestBuilder(future.getRequest()); + + Realm realm = request.getRealm() != null ? request.getRealm() : config.getRealm(); + + int statusCode = response.getStatus().getCode(); + + // FIXME + if (exitAfterHandling401(channel, future, response, request, statusCode, realm, proxyServer, requestBuilder) || // + exitAfterHandling407(future, response, request, statusCode, realm, proxyServer, requestBuilder) || // + exitAfterHandling100(channel, future, statusCode) || // + exitAfterHandlingRedirect(channel, future, request, response, statusCode) || // + exitAfterHandlingConnect(channel, future, request, proxyServer, statusCode, requestBuilder, nettyRequest) || // + exitAfterHandlingStatus(channel, future, response, handler, status) || // + exitAfterHandlingHeaders(channel, future, response, handler, responseHeaders) || // + exitAfterHandlingBody(channel, future, response, handler) || // + exitAfterHandlingHead(channel, future, response, handler, nettyRequest)) { + return; + } + } + + private final void handleChunk(final HttpChunk chunk, final Channel channel, final NettyResponseFuture future, + final AsyncHandler handler) throws Exception { + boolean last = chunk.isLast(); + // we don't notify updateBodyAndInterrupt with the last chunk as it's empty + if (last || updateBodyAndInterrupt(future, handler, new ResponseBodyPart(null, chunk, last))) { + + if (chunk instanceof HttpChunkTrailer) { + HttpChunkTrailer chunkTrailer = (HttpChunkTrailer) chunk; + if (!chunkTrailer.trailingHeaders().isEmpty()) { + ResponseHeaders responseHeaders = new ResponseHeaders(future.getHttpResponse(), chunkTrailer); + updateHeadersAndInterrupt(handler, responseHeaders); + } + } + finishUpdate(future, channel, !chunk.isLast()); + } + } + + private FilterContext handleIoException(FilterContext fc, NettyResponseFuture future) { + for (IOExceptionFilter asyncFilter : config.getIOExceptionFilters()) { + try { + fc = asyncFilter.filter(fc); + if (fc == null) { + throw new NullPointerException("FilterContext is null"); + } + } catch (FilterException efe) { + nettyRequestSender.abort(future, efe); + } + } + return fc; + } + + private void finishUpdate(final NettyResponseFuture future, Channel channel, boolean expectOtherChunks) throws IOException { + boolean keepAlive = future.isKeepAlive(); + if (expectOtherChunks && keepAlive) + nettyRequestSender.drainChannel(channel, future); + else + channelManager.tryToOfferChannelToPool(channel, keepAlive, channelManager.getPoolKey(future)); + markAsDone(future, channel); + } + + public void handle(final Channel channel, final MessageEvent e, final NettyResponseFuture future) throws Exception { + + // The connect timeout occurred. + if (future.isDone()) { + channelManager.closeChannel(channel); + return; + } + + future.touch(); + + AsyncHandler handler = future.getAsyncHandler(); + Object message = e.getMessage(); + try { + if (message instanceof HttpResponse) + handleHttpResponse((HttpResponse) message, channel, future, handler); + + else if (message instanceof HttpChunk) + handleChunk((HttpChunk) message, channel, future, handler); + + } catch (Exception t) { + if (t instanceof IOException && !config.getIOExceptionFilters().isEmpty()) { + FilterContext fc = new FilterContext.FilterContextBuilder().asyncHandler(handler).request(future.getRequest()) + .ioException(IOException.class.cast(t)).build(); + fc = handleIoException(fc, future); + + if (fc.replayRequest()) { + replayRequest(future, fc, channel); + return; + } + } + + try { + nettyRequestSender.abort(future, t); + } finally { + finishUpdate(future, channel, false); + throw t; + } + } + } + + public void onError(Channel channel, ExceptionEvent e) { + } + + public void onClose(Channel channel, ChannelStateEvent e) { + } +} diff --git a/src/main/java/com/ning/http/client/providers/netty/handler/Processor.java b/src/main/java/com/ning/http/client/providers/netty/handler/Processor.java new file mode 100644 index 0000000000..985d12a7bc --- /dev/null +++ b/src/main/java/com/ning/http/client/providers/netty/handler/Processor.java @@ -0,0 +1,239 @@ +/* + * Copyright 2010-2013 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.handler; + +import org.jboss.netty.channel.Channel; +import org.jboss.netty.channel.ChannelHandlerContext; +import org.jboss.netty.channel.ChannelStateEvent; +import org.jboss.netty.channel.ExceptionEvent; +import org.jboss.netty.channel.MessageEvent; +import org.jboss.netty.channel.SimpleChannelUpstreamHandler; +import org.jboss.netty.handler.codec.PrematureChannelClosureException; +import org.jboss.netty.handler.codec.http.HttpChunk; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.ning.http.client.AsyncHttpClientConfig; +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.providers.netty.Callback; +import com.ning.http.client.providers.netty.DiscardEvent; +import com.ning.http.client.providers.netty.channel.ChannelManager; +import com.ning.http.client.providers.netty.channel.Channels; +import com.ning.http.client.providers.netty.future.NettyResponseFuture; +import com.ning.http.client.providers.netty.future.StackTraceInspector; +import com.ning.http.client.providers.netty.request.NettyRequestSender; + +import java.io.IOException; +import java.nio.channels.ClosedChannelException; + +public class Processor extends SimpleChannelUpstreamHandler { + + private static final Logger LOGGER = LoggerFactory.getLogger(Processor.class); + + public static final IOException REMOTELY_CLOSED_EXCEPTION = new IOException("Remotely Closed"); + public static final IOException CHANNEL_CLOSED_EXCEPTION = new IOException("Channel Closed"); + static { + REMOTELY_CLOSED_EXCEPTION.setStackTrace(new StackTraceElement[0]); + CHANNEL_CLOSED_EXCEPTION.setStackTrace(new StackTraceElement[0]); + } + + private final AsyncHttpClientConfig config; + private final ChannelManager channelManager; + private final NettyRequestSender nettyRequestSender; + private final Protocol protocol; + + public Processor(AsyncHttpClientConfig config, ChannelManager channelManager, NettyRequestSender nettyRequestSender, Protocol protocol) { + this.config = config; + this.channelManager = channelManager; + this.nettyRequestSender = nettyRequestSender; + this.protocol = protocol; + } + + @Override + public void messageReceived(final ChannelHandlerContext ctx, MessageEvent e) throws Exception { + + // call super to reset the read timeout + super.messageReceived(ctx, e); + + Channel channel = ctx.getChannel(); + Object attachment = Channels.getAttachment(channel); + + if (attachment == null) + LOGGER.debug("ChannelHandlerContext doesn't have any attachment"); + + if (attachment == DiscardEvent.INSTANCE) { + // discard + + } else if (attachment instanceof Callback) { + Object message = e.getMessage(); + Callback ac = (Callback) attachment; + if (message instanceof HttpChunk) { + // the AsyncCallable is to be processed on the last chunk + if (HttpChunk.class.cast(message).isLast()) + // process the AsyncCallable before passing the message to the protocol + ac.call(); + } else { + ac.call(); + Channels.setDiscard(channel); + } + + } else if (attachment instanceof NettyResponseFuture) { + protocol.handle(channel, e, NettyResponseFuture.class.cast(attachment)); + + } else { + // unhandled message + try { + ctx.getChannel().close(); + } catch (Throwable t) { + LOGGER.trace("Closing an orphan channel {}", ctx.getChannel()); + } + } + } + + private FilterContext handleIoException(FilterContext fc, NettyResponseFuture future) { + for (IOExceptionFilter asyncFilter : config.getIOExceptionFilters()) { + try { + fc = asyncFilter.filter(fc); + if (fc == null) { + throw new NullPointerException("FilterContext is null"); + } + } catch (FilterException efe) { + nettyRequestSender.abort(future, efe); + } + } + return fc; + } + + @Override + public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { + + if (nettyRequestSender.isClosed()) + return; + + Channel channel = ctx.getChannel(); + channelManager.removeAll(channel); + + try { + super.channelClosed(ctx, e); + } catch (Exception ex) { + LOGGER.trace("super.channelClosed", ex); + } + + Object attachment = Channels.getAttachment(channel); + LOGGER.debug("Channel Closed: {} with attachment {}", channel, attachment); + + if (attachment instanceof Callback) { + Callback ac = (Callback) attachment; + Channels.setAttachment(channel, ac.future()); + ac.call(); + + } else if (attachment instanceof NettyResponseFuture) { + NettyResponseFuture future = (NettyResponseFuture) attachment; + future.touch(); + + if (!config.getIOExceptionFilters().isEmpty()) { + FilterContext fc = new FilterContext.FilterContextBuilder().asyncHandler(future.getAsyncHandler()) + .request(future.getRequest()).ioException(CHANNEL_CLOSED_EXCEPTION).build(); + fc = handleIoException(fc, future); + + if (fc.replayRequest() && future.canBeReplay()) { + nettyRequestSender.replayRequest(future, fc, channel); + return; + } + } + + protocol.onClose(channel, e); + + if (future == null || future.isDone()) + channelManager.closeChannel(channel); + + else if (!nettyRequestSender.retry(ctx.getChannel(), future)) + nettyRequestSender.abort(future, REMOTELY_CLOSED_EXCEPTION); + } + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { + Channel channel = ctx.getChannel(); + Throwable cause = e.getCause(); + NettyResponseFuture future = null; + + if (e.getCause() instanceof PrematureChannelClosureException) + return; + + LOGGER.debug("Unexpected I/O exception on channel {}", channel, cause); + + try { + if (cause instanceof ClosedChannelException) { + return; + } + + Object attachment = Channels.getAttachment(channel); + if (attachment instanceof NettyResponseFuture) { + future = (NettyResponseFuture) attachment; + future.attachChannel(null, false); + future.touch(); + + 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(); + fc = handleIoException(fc, future); + + if (fc.replayRequest()) { + nettyRequestSender.replayRequest(future, fc, channel); + return; + } + } else { + // Close the channel so the recovering can occurs. + try { + channel.close(); + } catch (Throwable t) { + // Swallow. + } + return; + } + } + + if (StackTraceInspector.abortOnReadOrWriteException(cause)) { + LOGGER.debug("Trying to recover from dead Channel: {}", channel); + return; + } + } else if (attachment instanceof Callback) { + future = ((Callback) attachment).future(); + } + } catch (Throwable t) { + cause = t; + } + + if (future != null) { + try { + LOGGER.debug("Was unable to recover Future: {}", future); + nettyRequestSender.abort(future, cause); + } catch (Throwable t) { + LOGGER.error(t.getMessage(), t); + } + } + + protocol.onError(channel, e); + + channelManager.closeChannel(channel); + ctx.sendUpstream(e); + } +} diff --git a/src/main/java/com/ning/http/client/providers/netty/handler/Protocol.java b/src/main/java/com/ning/http/client/providers/netty/handler/Protocol.java new file mode 100644 index 0000000000..1c5a3193b4 --- /dev/null +++ b/src/main/java/com/ning/http/client/providers/netty/handler/Protocol.java @@ -0,0 +1,144 @@ +/* + * 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.providers.netty.handler; + +import static com.ning.http.util.MiscUtils.isNonEmpty; + +import org.jboss.netty.channel.Channel; +import org.jboss.netty.channel.ChannelStateEvent; +import org.jboss.netty.channel.ExceptionEvent; +import org.jboss.netty.channel.MessageEvent; +import org.jboss.netty.handler.codec.http.HttpHeaders; +import org.jboss.netty.handler.codec.http.HttpResponse; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.ning.http.client.AsyncHandlerExtensions; +import com.ning.http.client.AsyncHttpClientConfig; +import com.ning.http.client.MaxRedirectException; +import com.ning.http.client.Request; +import com.ning.http.client.RequestBuilder; +import com.ning.http.client.cookie.CookieDecoder; +import com.ning.http.client.filter.FilterContext; +import com.ning.http.client.providers.netty.Callback; +import com.ning.http.client.providers.netty.channel.ChannelManager; +import com.ning.http.client.providers.netty.channel.Channels; +import com.ning.http.client.providers.netty.future.NettyResponseFuture; +import com.ning.http.client.providers.netty.request.NettyRequestSender; +import com.ning.http.client.providers.netty.util.HttpUtil; +import com.ning.http.client.uri.UriComponents; +import com.ning.http.util.AsyncHttpProviderUtils; + +import java.io.IOException; +import java.util.List; + +public abstract class Protocol { + + private static final Logger LOGGER = LoggerFactory.getLogger(Protocol.class); + + protected final ChannelManager channelManager; + protected final AsyncHttpClientConfig config; + protected final NettyRequestSender nettyRequestSender; + + public Protocol(ChannelManager channelManager, AsyncHttpClientConfig config, NettyRequestSender nettyRequestSender) { + this.channelManager = channelManager; + this.config = config; + this.nettyRequestSender = nettyRequestSender; + } + + protected void replayRequest(final NettyResponseFuture future, FilterContext fc, Channel channel) throws IOException { + if (future.getAsyncHandler() instanceof AsyncHandlerExtensions) + AsyncHandlerExtensions.class.cast(future.getAsyncHandler()).onRetry(); + + final Request newRequest = fc.getRequest(); + future.setAsyncHandler(fc.getAsyncHandler()); + future.setState(NettyResponseFuture.STATE.NEW); + future.touch(); + + LOGGER.debug("\n\nReplaying Request {}\n for Future {}\n", newRequest, future); + nettyRequestSender.drainChannel(channel, future); + nettyRequestSender.nextRequest(newRequest, future); + return; + } + + protected boolean exitAfterHandlingRedirect(Channel channel, NettyResponseFuture future, Request request, HttpResponse response, + int statusCode) throws Exception { + + if (AsyncHttpProviderUtils.followRedirect(config, request) + && (statusCode == 302 || statusCode == 301 || statusCode == 303 || statusCode == 307)) { + + if (future.incrementAndGetCurrentRedirectCount() < config.getMaxRedirects()) { + // allow 401 handling again + future.getAndSetAuth(false); + + HttpHeaders responseHeaders = response.headers(); + + String location = responseHeaders.get(HttpHeaders.Names.LOCATION); + UriComponents uri = UriComponents.create(future.getURI(), location); + if (!uri.equals(future.getURI())) { + final RequestBuilder nBuilder = new RequestBuilder(future.getRequest()); + + if (config.isRemoveQueryParamOnRedirect()) + nBuilder.resetQuery(); + else + nBuilder.addQueryParams(future.getRequest().getQueryParams()); + + if (!(statusCode < 302 || statusCode > 303) && !(statusCode == 302 && config.isStrict302Handling())) { + nBuilder.setMethod("GET"); + } + final boolean initialConnectionKeepAlive = future.isKeepAlive(); + final String initialPoolKey = channelManager.getPoolKey(future); + future.setURI(uri); + UriComponents newURI = uri; + String targetScheme = request.getURI().getScheme(); + if (targetScheme.equals(HttpUtil.WEBSOCKET)) { + newURI = newURI.withNewScheme(HttpUtil.WEBSOCKET); + } + if (targetScheme.equals(HttpUtil.WEBSOCKET_SSL)) { + newURI = newURI.withNewScheme(HttpUtil.WEBSOCKET_SSL); + } + + LOGGER.debug("Redirecting to {}", newURI); + List setCookieHeaders = responseHeaders.getAll(HttpHeaders.Names.SET_COOKIE2); + if (!isNonEmpty(setCookieHeaders)) { + setCookieHeaders = responseHeaders.getAll(HttpHeaders.Names.SET_COOKIE); + } + + for (String cookieStr : setCookieHeaders) { + nBuilder.addOrReplaceCookie(CookieDecoder.decode(cookieStr)); + } + + Callback ac = nettyRequestSender.newDrainCallable(future, channel, initialConnectionKeepAlive, initialPoolKey); + + if (response.isChunked()) { + // We must make sure there is no bytes left before executing the next request. + Channels.setAttachment(channel, ac); + } else { + ac.call(); + } + nettyRequestSender.nextRequest(nBuilder.setURI(newURI).build(), future); + return true; + } + } else { + throw new MaxRedirectException("Maximum redirect reached: " + config.getMaxRedirects()); + } + } + return false; + } + + public abstract void handle(Channel channel, MessageEvent e, NettyResponseFuture future) throws Exception; + + public abstract void onError(Channel channel, ExceptionEvent e); + + public abstract void onClose(Channel channel, ChannelStateEvent e); +} diff --git a/src/main/java/com/ning/http/client/providers/netty/handler/WebSocketProtocol.java b/src/main/java/com/ning/http/client/providers/netty/handler/WebSocketProtocol.java new file mode 100644 index 0000000000..d5367a95ee --- /dev/null +++ b/src/main/java/com/ning/http/client/providers/netty/handler/WebSocketProtocol.java @@ -0,0 +1,250 @@ +package com.ning.http.client.providers.netty.handler; + +import org.jboss.netty.buffer.ChannelBuffer; +import org.jboss.netty.buffer.ChannelBuffers; +import org.jboss.netty.channel.Channel; +import org.jboss.netty.channel.ChannelStateEvent; +import org.jboss.netty.channel.ExceptionEvent; +import org.jboss.netty.channel.MessageEvent; +import org.jboss.netty.handler.codec.http.HttpChunk; +import org.jboss.netty.handler.codec.http.HttpHeaders; +import org.jboss.netty.handler.codec.http.HttpResponse; +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; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.ning.http.client.AsyncHandler.STATE; +import com.ning.http.client.AsyncHttpClientConfig; +import com.ning.http.client.HttpResponseHeaders; +import com.ning.http.client.HttpResponseStatus; +import com.ning.http.client.Request; +import com.ning.http.client.filter.FilterContext; +import com.ning.http.client.filter.FilterException; +import com.ning.http.client.filter.ResponseFilter; +import com.ning.http.client.providers.netty.channel.ChannelManager; +import com.ning.http.client.providers.netty.channel.Channels; +import com.ning.http.client.providers.netty.future.NettyResponseFuture; +import com.ning.http.client.providers.netty.request.NettyRequestSender; +import com.ning.http.client.providers.netty.response.ResponseBodyPart; +import com.ning.http.client.providers.netty.response.ResponseHeaders; +import com.ning.http.client.providers.netty.response.ResponseStatus; +import com.ning.http.client.providers.netty.ws.NettyWebSocket; +import com.ning.http.client.providers.netty.ws.WebSocketUtil; +import com.ning.http.client.websocket.WebSocketUpgradeHandler; +import com.ning.http.util.StandardCharsets; + +import java.io.IOException; + +public class WebSocketProtocol extends Protocol { + + private static final Logger LOGGER = LoggerFactory.getLogger(WebSocketProtocol.class); + + 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; + + public WebSocketProtocol(ChannelManager channelManager, AsyncHttpClientConfig config, NettyRequestSender nettyRequestSender) { + super(channelManager, config, nettyRequestSender); + } + + // We don't need to synchronize as replacing the "ws-decoder" will process using the same thread. + private void invokeOnSucces(Channel channel, WebSocketUpgradeHandler h) { + if (!h.touchSuccess()) { + try { + h.onSuccess(new NettyWebSocket(channel)); + } catch (Exception ex) { + LOGGER.warn("onSuccess unexexpected exception", ex); + } + } + } + + @Override + public void handle(Channel channel, MessageEvent e, final NettyResponseFuture future) throws Exception { + + WebSocketUpgradeHandler wsUpgradeHandler = (WebSocketUpgradeHandler) future.getAsyncHandler(); + Request request = future.getRequest(); + + if (e.getMessage() instanceof HttpResponse) { + HttpResponse response = (HttpResponse) e.getMessage(); + HttpHeaders nettyResponseHeaders = response.headers(); + + HttpResponseStatus s = new ResponseStatus(future.getURI(), config, response); + HttpResponseHeaders responseHeaders = new ResponseHeaders(response); + FilterContext fc = new FilterContext.FilterContextBuilder().asyncHandler(wsUpgradeHandler).request(request) + .responseStatus(s).responseHeaders(responseHeaders).build(); + for (ResponseFilter asyncFilter : config.getResponseFilters()) { + try { + fc = asyncFilter.filter(fc); + if (fc == null) { + throw new NullPointerException("FilterContext is null"); + } + } catch (FilterException efe) { + nettyRequestSender.abort(future, efe); + } + } + + // The handler may have been wrapped. + future.setAsyncHandler(fc.getAsyncHandler()); + + // The request has changed + if (fc.replayRequest()) { + replayRequest(future, fc, channel); + return; + } + + future.setHttpResponse(response); + if (exitAfterHandlingRedirect(channel, future, request, response, response.getStatus().getCode())) + return; + + 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 = nettyResponseHeaders.contains(HttpHeaders.Names.UPGRADE); + String c = nettyResponseHeaders.get(HttpHeaders.Names.CONNECTION); + if (c == null) { + c = nettyResponseHeaders.get("connection"); + } + + final boolean validConnection = c == null ? false : c.equalsIgnoreCase(HttpHeaders.Values.UPGRADE); + + s = new ResponseStatus(future.getURI(), config, response); + final boolean statusReceived = wsUpgradeHandler.onStatusReceived(s) == STATE.UPGRADE; + + if (!statusReceived) { + try { + wsUpgradeHandler.onCompleted(); + } finally { + future.done(); + } + return; + } + + final boolean headerOK = wsUpgradeHandler.onHeadersReceived(responseHeaders) == STATE.CONTINUE; + if (!headerOK || !validStatus || !validUpgrade || !validConnection) { + nettyRequestSender.abort(future, new IOException("Invalid handshake response")); + return; + } + + String accept = nettyResponseHeaders.get(HttpHeaders.Names.SEC_WEBSOCKET_ACCEPT); + String key = WebSocketUtil.getAcceptKey(future.getNettyRequest().headers().get(HttpHeaders.Names.SEC_WEBSOCKET_KEY)); + if (accept == null || !accept.equals(key)) { + nettyRequestSender.abort(future, new IOException(String.format("Invalid challenge. Actual: %s. Expected: %s", accept, key))); + return; + } + + // FIXME + channel.getPipeline().replace(ChannelManager.HTTP_HANDLER, "ws-encoder", new WebSocket08FrameEncoder(true)); + channel.getPipeline().addBefore(ChannelManager.WS_PROCESSOR, "ws-decoder", new WebSocket08FrameDecoder(false, false)); + + invokeOnSucces(channel, wsUpgradeHandler); + future.done(); + } else if (e.getMessage() instanceof WebSocketFrame) { + + invokeOnSucces(channel, wsUpgradeHandler); + + final WebSocketFrame frame = (WebSocketFrame) e.getMessage(); + + byte pendingOpcode = OPCODE_UNKNOWN; + if (frame instanceof TextWebSocketFrame) { + pendingOpcode = OPCODE_TEXT; + } else if (frame instanceof BinaryWebSocketFrame) { + pendingOpcode = OPCODE_BINARY; + } + + if (frame.getBinaryData() != null) { + + HttpChunk webSocketChunk = new HttpChunk() { + private ChannelBuffer content = ChannelBuffers.wrappedBuffer(frame.getBinaryData()); + + @Override + public boolean isLast() { + return false; + } + + @Override + public ChannelBuffer getContent() { + return content; + } + + @Override + public void setContent(ChannelBuffer content) { + throw new UnsupportedOperationException(); + } + }; + + ResponseBodyPart rp = new ResponseBodyPart(null, webSocketChunk, true); + wsUpgradeHandler.onBodyPartReceived(rp); + + NettyWebSocket webSocket = NettyWebSocket.class.cast(wsUpgradeHandler.onCompleted()); + + if (webSocket != null) { + if (pendingOpcode == OPCODE_BINARY) { + webSocket.onBinaryFragment(rp.getBodyPartBytes(), frame.isFinalFragment()); + } else if (pendingOpcode == OPCODE_TEXT) { + webSocket.onTextFragment(frame.getBinaryData().toString(StandardCharsets.UTF_8), frame.isFinalFragment()); + } + + if (frame instanceof CloseWebSocketFrame) { + try { + Channels.setDiscard(channel); + webSocket.onClose(CloseWebSocketFrame.class.cast(frame).getStatusCode(), + CloseWebSocketFrame.class.cast(frame).getReasonText()); + } finally { + wsUpgradeHandler.resetSuccess(); + } + } + } else { + LOGGER.debug("UpgradeHandler returned a null NettyWebSocket "); + } + } + } else { + LOGGER.error("Invalid message {}", e.getMessage()); + } + } + + @Override + public void onError(Channel channel, ExceptionEvent e) { + try { + Object attachment = Channels.getAttachment(channel); + LOGGER.warn("onError {}", e); + if (!(attachment instanceof NettyResponseFuture)) { + return; + } + + NettyResponseFuture nettyResponse = (NettyResponseFuture) attachment; + WebSocketUpgradeHandler h = WebSocketUpgradeHandler.class.cast(nettyResponse.getAsyncHandler()); + + NettyWebSocket webSocket = NettyWebSocket.class.cast(h.onCompleted()); + if (webSocket != null) { + webSocket.onError(e.getCause()); + webSocket.close(); + } + } catch (Throwable t) { + LOGGER.error("onError", t); + } + } + + @Override + public void onClose(Channel channel, ChannelStateEvent e) { + LOGGER.trace("onClose {}", e); + + Object attachment = Channels.getAttachment(channel); + if (attachment instanceof NettyResponseFuture) { + try { + NettyResponseFuture nettyResponse = (NettyResponseFuture) attachment; + WebSocketUpgradeHandler h = WebSocketUpgradeHandler.class.cast(nettyResponse.getAsyncHandler()); + h.resetSuccess(); + + } catch (Throwable t) { + LOGGER.error("onError", t); + } + } + } +} diff --git a/src/main/java/com/ning/http/client/providers/netty/request/NettyConnectListener.java b/src/main/java/com/ning/http/client/providers/netty/request/NettyConnectListener.java index e13a0edd5a..7774638a6c 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/NettyConnectListener.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/NettyConnectListener.java @@ -25,7 +25,6 @@ import org.slf4j.LoggerFactory; import com.ning.http.client.AsyncHttpClientConfig; -import com.ning.http.client.providers.netty.NettyAsyncHttpProvider; import com.ning.http.client.providers.netty.channel.ChannelManager; import com.ning.http.client.providers.netty.channel.Channels; import com.ning.http.client.providers.netty.future.NettyResponseFuture; @@ -47,21 +46,21 @@ public final class NettyConnectListener implements ChannelFutureListener { private final AsyncHttpClientConfig config; private final NettyResponseFuture future; private final HttpRequest nettyRequest; - private final NettyAsyncHttpProvider provider; + private final NettyRequestSender nettyRequestSender; private final ChannelManager channelManager; private final boolean channelPreempted; private final String poolKey; public NettyConnectListener(AsyncHttpClientConfig config,// NettyResponseFuture future,// - NettyAsyncHttpProvider provider,// + NettyRequestSender nettyRequestSender,// ChannelManager channelManager,// boolean channelPreempted,// String poolKey) { this.config = config; this.future = future; this.nettyRequest = future.getNettyRequest(); - this.provider = provider; + this.nettyRequestSender = nettyRequestSender; this.channelManager = channelManager; this.channelPreempted = channelPreempted; this.poolKey = poolKey; @@ -87,14 +86,14 @@ private void writeRequest(Channel channel, String poolKey) { channelManager.registerOpenChannel(channel); future.attachChannel(channel, false); - provider.writeRequest(channel, config, future); + nettyRequestSender.writeRequest(channel, config, future); } public final void operationComplete(ChannelFuture f) throws Exception { Channel channel = f.getChannel(); if (f.isSuccess()) { Channels.setAttachment(channel, future); - final SslHandler sslHandler = (SslHandler) channel.getPipeline().get(NettyAsyncHttpProvider.SSL_HANDLER); + final SslHandler sslHandler = (SslHandler) channel.getPipeline().get(ChannelManager.SSL_HANDLER); final HostnameVerifier hostnameVerifier = config.getHostnameVerifier(); if (hostnameVerifier != null && sslHandler != null) { @@ -136,7 +135,7 @@ public void operationComplete(ChannelFuture handshakeFuture) throws Exception { && (cause instanceof ClosedChannelException || future.getState() != NettyResponseFuture.STATE.NEW || StackTraceInspector.abortOnDisconnectException(cause))) { LOGGER.debug("Retrying {} ", nettyRequest); - if (!provider.retry(channel, future)) + if (!nettyRequestSender.retry(channel, future)) return; } diff --git a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java new file mode 100644 index 0000000000..750ccac448 --- /dev/null +++ b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java @@ -0,0 +1,840 @@ +/* + * Copyright (c) 2014 AsyncHttpClient Project. 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.providers.netty.request; + +import static com.ning.http.util.AsyncHttpProviderUtils.DEFAULT_CHARSET; +import static com.ning.http.util.AsyncHttpProviderUtils.getNonEmptyPath; +import static com.ning.http.util.MiscUtils.isNonEmpty; + +import org.jboss.netty.bootstrap.ClientBootstrap; +import org.jboss.netty.buffer.ChannelBuffer; +import org.jboss.netty.buffer.ChannelBuffers; +import org.jboss.netty.channel.Channel; +import org.jboss.netty.channel.ChannelFuture; +import org.jboss.netty.channel.FileRegion; +import org.jboss.netty.handler.codec.http.DefaultHttpRequest; +import org.jboss.netty.handler.codec.http.HttpHeaders; +import org.jboss.netty.handler.codec.http.HttpMethod; +import org.jboss.netty.handler.codec.http.HttpRequest; +import org.jboss.netty.handler.codec.http.HttpVersion; +import org.jboss.netty.handler.ssl.SslHandler; +import org.jboss.netty.handler.stream.ChunkedFile; +import org.jboss.netty.util.Timeout; +import org.jboss.netty.util.Timer; +import org.jboss.netty.util.TimerTask; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.ning.http.client.AsyncHandler; +import com.ning.http.client.AsyncHandlerExtensions; +import com.ning.http.client.AsyncHttpClientConfig; +import com.ning.http.client.Body; +import com.ning.http.client.BodyGenerator; +import com.ning.http.client.ConnectionPoolKeyStrategy; +import com.ning.http.client.FluentCaseInsensitiveStringsMap; +import com.ning.http.client.ListenableFuture; +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.cookie.CookieEncoder; +import com.ning.http.client.filter.FilterContext; +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.Callback; +import com.ning.http.client.providers.netty.NettyAsyncHttpProvider; +import com.ning.http.client.providers.netty.NettyAsyncHttpProviderConfig; +import com.ning.http.client.providers.netty.channel.ChannelManager; +import com.ning.http.client.providers.netty.channel.Channels; +import com.ning.http.client.providers.netty.future.NettyResponseFuture; +import com.ning.http.client.providers.netty.request.body.BodyChunkedInput; +import com.ning.http.client.providers.netty.request.body.BodyFileRegion; +import com.ning.http.client.providers.netty.request.body.OptimizedFileRegion; +import com.ning.http.client.providers.netty.request.timeout.ReadTimeoutTimerTask; +import com.ning.http.client.providers.netty.request.timeout.RequestTimeoutTimerTask; +import com.ning.http.client.providers.netty.request.timeout.TimeoutsHolder; +import com.ning.http.client.providers.netty.spnego.SpnegoEngine; +import com.ning.http.client.providers.netty.util.HttpUtil; +import com.ning.http.client.providers.netty.ws.WebSocketUtil; +import com.ning.http.client.uri.UriComponents; +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.ProxyUtils; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.net.InetSocketAddress; +import java.nio.charset.Charset; +import java.security.NoSuchAlgorithmException; +import java.util.List; +import java.util.Map.Entry; +import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + +public class NettyRequestSender { + + private static final Logger LOGGER = LoggerFactory.getLogger(NettyRequestSender.class); + public static final String GZIP_DEFLATE = HttpHeaders.Values.GZIP + "," + HttpHeaders.Values.DEFLATE; + + private final AsyncHttpClientConfig config; + private final NettyAsyncHttpProviderConfig nettyConfig; + private final ChannelManager channelManager; + private final Timer nettyTimer; + private final AtomicBoolean closed; + private final boolean disableZeroCopy; + + public NettyRequestSender(AsyncHttpClientConfig config, NettyAsyncHttpProviderConfig nettyConfig, ChannelManager channelManager, + Timer nettyTimer, AtomicBoolean closed) { + this.config = config; + this.nettyConfig = nettyConfig; + this.channelManager = channelManager; + this.nettyTimer = nettyTimer; + this.closed = closed; + disableZeroCopy = nettyConfig.isDisableZeroCopy(); + } + + public void abort(NettyResponseFuture future, Throwable t) { + Channel channel = future.channel(); + if (channel != null) + channelManager.closeChannel(channel); + + if (!future.isDone()) { + LOGGER.debug("Aborting Future {}\n", future); + LOGGER.debug(t.getMessage(), t); + } + + future.abort(t); + } + + public Timeout newTimeout(TimerTask task, long delay) { + return nettyTimer.newTimeout(task, delay, TimeUnit.MILLISECONDS); + } + + public final void writeRequest(final Channel channel, final AsyncHttpClientConfig config, final NettyResponseFuture future) { + + HttpRequest nettyRequest = future.getNettyRequest(); + HttpHeaders nettyRequestHeaders = nettyRequest.headers(); + boolean ssl = channel.getPipeline().get(SslHandler.class) != null; + + 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 channelClosed do it's work. + */ + if (!channel.isOpen() || !channel.isConnected()) { + return; + } + + Body body = null; + if (!nettyRequest.getMethod().equals(HttpMethod.CONNECT)) { + BodyGenerator bg = future.getRequest().getBodyGenerator(); + + if (bg == null && future.getRequest().getStreamData() != null) { + bg = new InputStreamBodyGenerator(future.getRequest().getStreamData()); + } + + if (bg != null) { + // Netty issue with chunking. + if (bg instanceof InputStreamBodyGenerator) { + InputStreamBodyGenerator.class.cast(bg).patchNettyChunkingIssue(true); + } + + try { + body = bg.createBody(); + } catch (IOException ex) { + throw new IllegalStateException(ex); + } + long length = body.getContentLength(); + if (length >= 0) { + nettyRequestHeaders.set(HttpHeaders.Names.CONTENT_LENGTH, length); + } else { + nettyRequestHeaders.set(HttpHeaders.Names.TRANSFER_ENCODING, HttpHeaders.Values.CHUNKED); + } + + } else if (isNonEmpty(future.getRequest().getParts())) { + String contentType = nettyRequestHeaders.get(HttpHeaders.Names.CONTENT_TYPE); + String contentLength = nettyRequestHeaders.get(HttpHeaders.Names.CONTENT_LENGTH); + + long length = -1; + if (contentLength != null) { + length = Long.parseLong(contentLength); + } else { + nettyRequestHeaders.add(HttpHeaders.Names.TRANSFER_ENCODING, HttpHeaders.Values.CHUNKED); + } + + body = new MultipartBody(future.getRequest().getParts(), contentType, length); + } + } + + if (future.getAsyncHandler() instanceof TransferCompletionHandler) { + + FluentCaseInsensitiveStringsMap h = new FluentCaseInsensitiveStringsMap(); + for (String s : nettyRequestHeaders.names()) { + for (String header : nettyRequestHeaders.getAll(s)) { + h.add(s, header); + } + } + + TransferCompletionHandler.class.cast(future.getAsyncHandler()).transferAdapter( + new NettyTransferAdapter(h, nettyRequest.getContent(), future.getRequest().getFile())); + } + + // Leave it to true. + if (future.getAndSetWriteHeaders(true)) { + try { + if (future.getAsyncHandler() instanceof AsyncHandlerExtensions) + AsyncHandlerExtensions.class.cast(future.getAsyncHandler()).onRequestSent(); + + channel.write(nettyRequest).addListener(new ProgressListener(config, true, future.getAsyncHandler(), future)); + } catch (Throwable cause) { + LOGGER.debug(cause.getMessage(), cause); + try { + channel.close(); + } catch (RuntimeException ex) { + LOGGER.debug(ex.getMessage(), ex); + } + return; + } + } + + if (future.getAndSetWriteBody(true)) { + if (!nettyRequest.getMethod().equals(HttpMethod.CONNECT)) { + + if (future.getRequest().getFile() != null) { + final File file = future.getRequest().getFile(); + final RandomAccessFile raf = new RandomAccessFile(file, "r"); + + try { + ChannelFuture writeFuture; + if (disableZeroCopy || ssl) { + writeFuture = channel.write(new ChunkedFile(raf, 0, raf.length(), nettyConfig.getChunkedFileChunkSize())); + } else { + final FileRegion region = new OptimizedFileRegion(raf, 0, raf.length()); + writeFuture = channel.write(region); + } + writeFuture.addListener(new ProgressListener(config, false, future.getAsyncHandler(), future) { + public void operationComplete(ChannelFuture cf) { + try { + raf.close(); + } catch (IOException e) { + LOGGER.warn("Failed to close request body: {}", e.getMessage(), e); + } + super.operationComplete(cf); + } + }); + } catch (IOException ex) { + if (raf != null) { + try { + raf.close(); + } catch (IOException e) { + } + } + throw ex; + } + } else if (body != null) { + final Body b = body; + + ChannelFuture writeFuture; + if (disableZeroCopy || ssl || !(body instanceof RandomAccessBody)) { + BodyChunkedInput bodyChunkedInput = new BodyChunkedInput(body); + writeFuture = channel.write(bodyChunkedInput); + } else { + BodyFileRegion bodyFileRegion = new BodyFileRegion((RandomAccessBody) body); + writeFuture = channel.write(bodyFileRegion); + } + writeFuture.addListener(new ProgressListener(config, false, future.getAsyncHandler(), future) { + public void operationComplete(ChannelFuture cf) { + try { + b.close(); + } catch (IOException e) { + LOGGER.warn("Failed to close request body: {}", e.getMessage(), e); + } + super.operationComplete(cf); + } + }); + } + } + } + } catch (Throwable ioe) { + try { + channel.close(); + } catch (RuntimeException ex) { + LOGGER.debug(ex.getMessage(), ex); + } + } + + try { + future.touch(); + int requestTimeout = AsyncHttpProviderUtils.requestTimeout(config, future.getRequest()); + TimeoutsHolder timeoutsHolder = new TimeoutsHolder(); + if (requestTimeout != -1) { + timeoutsHolder.requestTimeout = newTimeout(new RequestTimeoutTimerTask(future, this, timeoutsHolder, requestTimeout), + requestTimeout); + } + + int readTimeout = config.getReadTimeout(); + if (readTimeout != -1 && readTimeout <= requestTimeout) { + // no need for a idleConnectionTimeout that's less than the requestTimeout + timeoutsHolder.readTimeout = newTimeout( + new ReadTimeoutTimerTask(future, this, timeoutsHolder, requestTimeout, readTimeout), readTimeout); + } + future.setTimeoutsHolder(timeoutsHolder); + + } catch (RejectedExecutionException ex) { + abort(future, ex); + } + } + + public void nextRequest(final Request request, final NettyResponseFuture future) throws IOException { + nextRequest(request, future, true); + } + + private void nextRequest(final Request request, final NettyResponseFuture future, final boolean useCache) throws IOException { + execute(request, future, useCache, true); + } + + private void execute(final Request request, final NettyResponseFuture f, boolean useCache, boolean reclaimCache) + throws IOException { + doConnect(request, f.getAsyncHandler(), f, useCache, reclaimCache); + } + + private Channel lookupInCache(UriComponents uri, ProxyServer proxy, ConnectionPoolKeyStrategy strategy) { + final Channel channel = channelManager.poll(channelManager.getPoolKey(uri, proxy, strategy)); + + if (channel != null) { + LOGGER.debug("Using cached Channel {}\n for uri {}\n", channel, uri); + + try { + // Always make sure the channel who got cached support the proper protocol. It could + // only occurs when a HttpMethod.CONNECT is used against a proxy that requires upgrading from http to + // https. + return channelManager.verifyChannelPipeline(channel, uri.getScheme()); + } catch (Exception ex) { + LOGGER.debug(ex.getMessage(), ex); + } + } + return null; + } + + private NettyResponseFuture newFuture(UriComponents uri, Request request, AsyncHandler asyncHandler, + HttpRequest nettyRequest, AsyncHttpClientConfig config, ProxyServer proxyServer) { + + NettyResponseFuture f = new NettyResponseFuture(uri,// + request,// + asyncHandler,// + nettyRequest,// + config.getMaxRequestRetry(),// + request.getConnectionPoolKeyStrategy(),// + proxyServer); + + String expectHeader = request.getHeaders().getFirstValue(HttpHeaders.Names.EXPECT); + if (expectHeader != null && expectHeader.equalsIgnoreCase(HttpHeaders.Values.CONTINUE)) { + f.getAndSetWriteBody(false); + } + return f; + } + + private NettyResponseFuture buildNettyResponseFutureWithCachedChannel(Request request, AsyncHandler asyncHandler, + NettyResponseFuture f, ProxyServer proxyServer, UriComponents uri, ChannelBuffer bufferedBytes, int maxTry) + throws IOException { + + for (int i = 0; i < maxTry; i++) { + if (maxTry == 0) + return null; + + Channel channel = null; + if (f != null && f.reuseChannel() && f.channel() != null) { + channel = f.channel(); + } else { + channel = lookupInCache(uri, proxyServer, request.getConnectionPoolKeyStrategy()); + } + + if (channel == null) + return null; + else { + HttpRequest nettyRequest = null; + + if (f == null) { + nettyRequest = buildRequest(config, request, uri, false, bufferedBytes, proxyServer); + f = newFuture(uri, request, asyncHandler, nettyRequest, config, proxyServer); + } else if (i == 0) { + // only build request on first try + nettyRequest = buildRequest(config, request, uri, f.isConnectAllowed(), bufferedBytes, proxyServer); + f.setNettyRequest(nettyRequest); + } + f.setState(NettyResponseFuture.STATE.POOLED); + f.attachChannel(channel, false); + + if (channel.isOpen() && channel.isConnected()) { + Channels.setAttachment(channel, f); + return f; + } else + // else, channel was closed by the server since we fetched it from the pool, starting over + f.attachChannel(null); + } + } + return null; + } + + private String computeNonConnectRequestPath(AsyncHttpClientConfig config, UriComponents uri, ProxyServer proxyServer) { + if (proxyServer != null && !(HttpUtil.isSecure(uri) && config.isUseRelativeURIsWithSSLProxies())) + return uri.toString(); + else { + String path = getNonEmptyPath(uri); + return uri.getQuery() != null ? path + "?" + uri.getQuery() : path; + } + } + + private HttpRequest construct(AsyncHttpClientConfig config, Request request, HttpMethod m, UriComponents uri, ChannelBuffer buffer, + ProxyServer proxyServer) throws IOException { + + HttpRequest nettyRequest; + + if (m.equals(HttpMethod.CONNECT)) { + nettyRequest = new DefaultHttpRequest(HttpVersion.HTTP_1_0, m, AsyncHttpProviderUtils.getAuthority(uri)); + } else { + String path = computeNonConnectRequestPath(config, uri, proxyServer); + nettyRequest = new DefaultHttpRequest(HttpVersion.HTTP_1_1, m, path); + } + + HttpHeaders nettyRequestHeaders = nettyRequest.headers(); + + boolean webSocket = HttpUtil.isWebSocket(uri.getScheme()); + if (webSocket && !m.equals(HttpMethod.CONNECT)) { + nettyRequestHeaders.add(HttpHeaders.Names.UPGRADE, HttpHeaders.Values.WEBSOCKET); + nettyRequestHeaders.add(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.UPGRADE); + nettyRequestHeaders.add(HttpHeaders.Names.ORIGIN, "http://" + uri.getHost() + ":" + uri.getPort()); + nettyRequestHeaders.add(HttpHeaders.Names.SEC_WEBSOCKET_KEY, WebSocketUtil.getKey()); + nettyRequestHeaders.add(HttpHeaders.Names.SEC_WEBSOCKET_VERSION, "13"); + } + + String host = request.getVirtualHost() != null ? request.getVirtualHost() : uri.getHost(); + String hostHeader = request.getVirtualHost() != null || uri.getPort() == -1 ? host : host + ":" + uri.getPort(); + nettyRequestHeaders.set(HttpHeaders.Names.HOST, hostHeader); + + if (!m.equals(HttpMethod.CONNECT)) { + for (Entry> header : request.getHeaders()) { + String name = header.getKey(); + if (!HttpHeaders.Names.HOST.equalsIgnoreCase(name)) { + for (String value : header.getValue()) { + nettyRequestHeaders.add(name, value); + } + } + } + + if (config.isCompressionEnabled()) { + nettyRequestHeaders.set(HttpHeaders.Names.ACCEPT_ENCODING, GZIP_DEFLATE); + } + } else { + List auth = request.getHeaders().get(HttpHeaders.Names.PROXY_AUTHORIZATION); + if (HttpUtil.isNTLM(auth)) { + nettyRequestHeaders.add(HttpHeaders.Names.PROXY_AUTHORIZATION, auth.get(0)); + } + } + Realm realm = request.getRealm() != null ? request.getRealm() : config.getRealm(); + + if (realm != null && realm.getUsePreemptiveAuth()) { + + String domain = realm.getNtlmDomain(); + if (proxyServer != null && proxyServer.getNtlmDomain() != null) { + domain = proxyServer.getNtlmDomain(); + } + + String authHost = realm.getNtlmHost(); + if (proxyServer != null && proxyServer.getHost() != null) { + host = proxyServer.getHost(); + } + + switch (realm.getAuthScheme()) { + case BASIC: + nettyRequestHeaders.add(HttpHeaders.Names.AUTHORIZATION, AuthenticatorUtils.computeBasicAuthentication(realm)); + break; + case DIGEST: + if (isNonEmpty(realm.getNonce())) { + try { + nettyRequestHeaders.add(HttpHeaders.Names.AUTHORIZATION, AuthenticatorUtils.computeDigestAuthentication(realm)); + } catch (NoSuchAlgorithmException e) { + throw new SecurityException(e); + } + } + break; + case NTLM: + try { + nettyRequestHeaders.add(HttpHeaders.Names.AUTHORIZATION, NTLMEngine.INSTANCE.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 = SpnegoEngine.INSTANCE.generateToken(server); + } catch (Throwable e) { + IOException ie = new IOException(); + ie.initCause(e); + throw ie; + } + nettyRequestHeaders.add(HttpHeaders.Names.AUTHORIZATION, "Negotiate " + challengeHeader); + break; + case NONE: + break; + default: + throw new IllegalStateException(String.format("Invalid Authentication %s", realm.toString())); + } + } + + if (!webSocket && !request.getHeaders().containsKey(HttpHeaders.Names.CONNECTION)) { + nettyRequestHeaders.set(HttpHeaders.Names.CONNECTION, AsyncHttpProviderUtils.keepAliveHeaderValue(config)); + } + + if (proxyServer != null) { + if (!request.getHeaders().containsKey("Proxy-Connection")) { + nettyRequestHeaders.set("Proxy-Connection", AsyncHttpProviderUtils.keepAliveHeaderValue(config)); + } + + if (proxyServer.getPrincipal() != null) { + if (isNonEmpty(proxyServer.getNtlmDomain())) { + + List auth = request.getHeaders().get(HttpHeaders.Names.PROXY_AUTHORIZATION); + if (!HttpUtil.isNTLM(auth)) { + try { + String msg = NTLMEngine.INSTANCE.generateType1Msg(proxyServer.getNtlmDomain(), proxyServer.getHost()); + nettyRequestHeaders.set(HttpHeaders.Names.PROXY_AUTHORIZATION, "NTLM " + msg); + } catch (NTLMEngineException e) { + IOException ie = new IOException(); + ie.initCause(e); + throw ie; + } + } + } else { + nettyRequestHeaders.set(HttpHeaders.Names.PROXY_AUTHORIZATION, + AuthenticatorUtils.computeBasicAuthentication(proxyServer)); + } + } + } + + // Add default accept headers. + if (!request.getHeaders().containsKey(HttpHeaders.Names.ACCEPT)) { + nettyRequestHeaders.set(HttpHeaders.Names.ACCEPT, "*/*"); + } + + String userAgentHeader = request.getHeaders().getFirstValue(HttpHeaders.Names.USER_AGENT); + if (userAgentHeader != null) { + nettyRequestHeaders.set(HttpHeaders.Names.USER_AGENT, userAgentHeader); + } else if (config.getUserAgent() != null) { + nettyRequestHeaders.set(HttpHeaders.Names.USER_AGENT, config.getUserAgent()); + } else { + nettyRequestHeaders.set(HttpHeaders.Names.USER_AGENT, AsyncHttpProviderUtils.constructUserAgent(NettyAsyncHttpProvider.class)); + } + + if (!m.equals(HttpMethod.CONNECT)) { + if (isNonEmpty(request.getCookies())) { + nettyRequestHeaders.set(HttpHeaders.Names.COOKIE, CookieEncoder.encode(request.getCookies())); + } + + Charset bodyCharset = request.getBodyEncoding() == null ? DEFAULT_CHARSET : Charset.forName(request.getBodyEncoding()); + + // We already have processed the body. + if (buffer != null && buffer.writerIndex() != 0) { + nettyRequestHeaders.set(HttpHeaders.Names.CONTENT_LENGTH, buffer.writerIndex()); + nettyRequest.setContent(buffer); + + } else if (request.getByteData() != null) { + nettyRequestHeaders.set(HttpHeaders.Names.CONTENT_LENGTH, String.valueOf(request.getByteData().length)); + nettyRequest.setContent(ChannelBuffers.wrappedBuffer(request.getByteData())); + + } else if (request.getStringData() != null) { + byte[] bytes = request.getStringData().getBytes(bodyCharset); + nettyRequestHeaders.set(HttpHeaders.Names.CONTENT_LENGTH, String.valueOf(bytes.length)); + nettyRequest.setContent(ChannelBuffers.wrappedBuffer(bytes)); + + } else if (isNonEmpty(request.getFormParams())) { + String formBody = AsyncHttpProviderUtils.formParams2UTF8String(request.getFormParams()); + nettyRequestHeaders.set(HttpHeaders.Names.CONTENT_LENGTH, String.valueOf(formBody.length())); + nettyRequest.setContent(ChannelBuffers.wrappedBuffer(formBody.getBytes(bodyCharset))); + + if (!request.getHeaders().containsKey(HttpHeaders.Names.CONTENT_TYPE)) { + nettyRequestHeaders.set(HttpHeaders.Names.CONTENT_TYPE, HttpHeaders.Values.APPLICATION_X_WWW_FORM_URLENCODED); + } + + } else if (isNonEmpty(request.getParts())) { + MultipartRequestEntity mre = AsyncHttpProviderUtils.createMultipartRequestEntity(request.getParts(), request.getHeaders()); + + nettyRequestHeaders.set(HttpHeaders.Names.CONTENT_TYPE, mre.getContentType()); + long contentLength = mre.getContentLength(); + if (contentLength >= 0) { + nettyRequestHeaders.set(HttpHeaders.Names.CONTENT_LENGTH, String.valueOf(contentLength)); + } + + } else if (request.getFile() != null) { + File file = request.getFile(); + if (!file.isFile()) { + throw new IOException(String.format("File %s is not a file or doesn't exist", file.getAbsolutePath())); + } + nettyRequestHeaders.set(HttpHeaders.Names.CONTENT_LENGTH, file.length()); + } + } + return nettyRequest; + } + + private final HttpRequest buildRequest(AsyncHttpClientConfig config, Request request, UriComponents uri, boolean allowConnect, + ChannelBuffer buffer, ProxyServer proxyServer) throws IOException { + + String method = request.getMethod(); + if (allowConnect && proxyServer != null && HttpUtil.isSecure(uri)) { + method = HttpMethod.CONNECT.toString(); + } + return construct(config, request, new HttpMethod(method), uri, buffer, proxyServer); + } + + private NettyResponseFuture buildConnectListenerFuture(AsyncHttpClientConfig config,// + Request request,// + AsyncHandler asyncHandler,// + NettyResponseFuture future,// + ChannelBuffer buffer,// + UriComponents uri) throws IOException { + ProxyServer proxyServer = ProxyUtils.getProxyServer(config, request); + HttpRequest nettyRequest = buildRequest(config, request, uri, true, buffer, proxyServer); + if (future == null) { + return newFuture(uri, request, asyncHandler, nettyRequest, config, proxyServer); + } else { + future.setNettyRequest(nettyRequest); + future.setRequest(request); + return future; + } + } + + public ListenableFuture doConnect(final Request request, final AsyncHandler asyncHandler, NettyResponseFuture f, + boolean useCache, boolean reclaimCache) throws IOException { + + if (isClosed()) { + throw new IOException("Closed"); + } + + UriComponents uri = request.getURI(); + + if (uri.getScheme().startsWith(HttpUtil.WEBSOCKET) && !channelManager.validateWebSocketRequest(request, asyncHandler)) + throw new IOException("WebSocket method must be a GET"); + + ProxyServer proxyServer = ProxyUtils.getProxyServer(config, request); + + boolean resultOfAConnect = f != null && f.getNettyRequest() != null && f.getNettyRequest().getMethod().equals(HttpMethod.CONNECT); + boolean useProxy = proxyServer != null && !resultOfAConnect; + + ChannelBuffer bufferedBytes = null; + if (f != null && f.getRequest().getFile() == null + && !f.getNettyRequest().getMethod().getName().equals(HttpMethod.CONNECT.getName())) { + bufferedBytes = f.getNettyRequest().getContent(); + } + + boolean useSSl = HttpUtil.isSecure(uri) && !useProxy; + + if (useCache) { + // 3 tentatives + NettyResponseFuture connectedFuture = buildNettyResponseFutureWithCachedChannel(request, asyncHandler, f, proxyServer, uri, + bufferedBytes, 3); + + if (connectedFuture != null) { + LOGGER.debug("\nUsing cached Channel {}\n for request \n{}\n", connectedFuture.channel(), connectedFuture.getNettyRequest()); + + try { + writeRequest(connectedFuture.channel(), config, connectedFuture); + } catch (Exception ex) { + LOGGER.debug("writeRequest failure", ex); + if (useSSl && ex.getMessage() != null && ex.getMessage().contains("SSLEngine")) { + LOGGER.debug("SSLEngine failure", ex); + connectedFuture = null; + } else { + try { + asyncHandler.onThrowable(ex); + } catch (Throwable t) { + LOGGER.warn("doConnect.writeRequest()", t); + } + IOException ioe = new IOException(ex.getMessage()); + ioe.initCause(ex); + throw ioe; + } + } + return connectedFuture; + } + } + + NettyResponseFuture connectListenerFuture = buildConnectListenerFuture(config, request, asyncHandler, f, bufferedBytes, uri); + + boolean channelPreempted = false; + String poolKey = null; + + // Do not throw an exception when we need an extra connection for a redirect. + if (!reclaimCache) { + + // only compute when maxConnectionPerHost is enabled + // FIXME clean up + if (config.getMaxConnectionsPerHost() > 0) + poolKey = channelManager.getPoolKey(connectListenerFuture); + + if (channelManager.preemptChannel(poolKey)) { + channelPreempted = true; + } else { + IOException ex = new IOException(String.format("Too many connections %s", config.getMaxConnections())); + try { + asyncHandler.onThrowable(ex); + } catch (Exception e) { + LOGGER.warn("asyncHandler.onThrowable crashed", e); + } + throw ex; + } + } + + NettyConnectListener connectListener = new NettyConnectListener(config, connectListenerFuture, this, channelManager, + channelPreempted, poolKey); + + ChannelFuture channelFuture; + ClientBootstrap bootstrap = channelManager.getBootstrap(request.getURI().getScheme(), useProxy, useSSl); + + try { + InetSocketAddress remoteAddress; + if (request.getInetAddress() != null) { + remoteAddress = new InetSocketAddress(request.getInetAddress(), AsyncHttpProviderUtils.getDefaultPort(uri)); + } else if (!useProxy) { + remoteAddress = new InetSocketAddress(uri.getHost(), AsyncHttpProviderUtils.getDefaultPort(uri)); + } else { + remoteAddress = new InetSocketAddress(proxyServer.getHost(), proxyServer.getPort()); + } + + if (request.getLocalAddress() != null) { + channelFuture = bootstrap.connect(remoteAddress, new InetSocketAddress(request.getLocalAddress(), 0)); + } else { + channelFuture = bootstrap.connect(remoteAddress); + } + + channelFuture.addListener(connectListener); + + } catch (Throwable t) { + if (channelPreempted) + channelManager.abortChannelPreemption(poolKey); + abort(connectListener.future(), t.getCause() == null ? t : t.getCause()); + } + + return connectListener.future(); + } + + private static class NettyTransferAdapter extends TransferCompletionHandler.TransferAdapter { + + private final ChannelBuffer content; + private final FileInputStream file; + private int byteRead = 0; + + public NettyTransferAdapter(FluentCaseInsensitiveStringsMap headers, ChannelBuffer content, File file) throws IOException { + super(headers); + this.content = content; + if (file != null) { + this.file = new FileInputStream(file); + } else { + this.file = null; + } + } + + @Override + public void getBytes(byte[] bytes) { + if (content.writableBytes() != 0) { + content.getBytes(byteRead, bytes); + byteRead += bytes.length; + } else if (file != null) { + try { + byteRead += file.read(bytes); + } catch (IOException e) { + LOGGER.error(e.getMessage(), e); + } + } + } + } + + public boolean retry(Channel channel, NettyResponseFuture future) { + + if (isClosed()) + return false; + + if (future == null) { + Object attachment = Channels.getAttachment(channel); + if (attachment instanceof NettyResponseFuture) + future = (NettyResponseFuture) attachment; + } + + if (future != null && future.canBeReplay()) { + future.setState(NettyResponseFuture.STATE.RECONNECTED); + + LOGGER.debug("Trying to recover request {}\n", future.getNettyRequest()); + if (future.getAsyncHandler() instanceof AsyncHandlerExtensions) + AsyncHandlerExtensions.class.cast(future.getAsyncHandler()).onRetry(); + + try { + nextRequest(future.getRequest(), future); + return true; + + } catch (IOException iox) { + future.setState(NettyResponseFuture.STATE.CLOSED); + future.abort(iox); + LOGGER.error("Remotely Closed, unable to recover", iox); + return false; + } + + } else { + LOGGER.debug("Unable to recover future {}\n", future); + return false; + } + } + + public final Callback newDrainCallable(final NettyResponseFuture future, final Channel channel, final boolean keepAlive, + final String poolKey) { + + return new Callback(future) { + public void call() throws Exception { + channelManager.tryToOfferChannelToPool(channel, keepAlive, poolKey); + } + }; + } + + public void drainChannel(final Channel channel, final NettyResponseFuture future) { + Channels.setAttachment(channel, newDrainCallable(future, channel, future.isKeepAlive(), channelManager.getPoolKey(future))); + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + public void replayRequest(final NettyResponseFuture future, FilterContext fc, Channel channel) throws IOException { + if (future.getAsyncHandler() instanceof AsyncHandlerExtensions) { + AsyncHandlerExtensions.class.cast(future.getAsyncHandler()).onRetry(); + } + final Request newRequest = fc.getRequest(); + future.setAsyncHandler(fc.getAsyncHandler()); + future.setState(NettyResponseFuture.STATE.NEW); + future.touch(); + + LOGGER.debug("\n\nReplaying Request {}\n for Future {}\n", newRequest, future); + drainChannel(channel, future); + nextRequest(newRequest, future); + return; + } + + public boolean isClosed() { + return closed.get(); + } +} diff --git a/src/main/java/com/ning/http/client/providers/netty/request/timeout/ReadTimeoutTimerTask.java b/src/main/java/com/ning/http/client/providers/netty/request/timeout/ReadTimeoutTimerTask.java index 75e4eb0f39..4f6d56d5c9 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/timeout/ReadTimeoutTimerTask.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/timeout/ReadTimeoutTimerTask.java @@ -16,24 +16,24 @@ import org.jboss.netty.util.Timeout; -import com.ning.http.client.providers.netty.NettyAsyncHttpProvider; import com.ning.http.client.providers.netty.future.NettyResponseFuture; +import com.ning.http.client.providers.netty.request.NettyRequestSender; public class ReadTimeoutTimerTask extends TimeoutTimerTask { private final long readTimeout; private final long requestTimeoutInstant; - public ReadTimeoutTimerTask(NettyResponseFuture nettyResponseFuture, NettyAsyncHttpProvider provider, TimeoutsHolder timeoutsHolder, + public ReadTimeoutTimerTask(NettyResponseFuture nettyResponseFuture, NettyRequestSender nettyRequestSender, TimeoutsHolder timeoutsHolder, long requestTimeout, long readTimeout) { - super(nettyResponseFuture, provider, timeoutsHolder); + super(nettyResponseFuture, nettyRequestSender, timeoutsHolder); this.readTimeout = readTimeout; requestTimeoutInstant = requestTimeout >= 0 ? nettyResponseFuture.getStart() + requestTimeout : Long.MAX_VALUE; } public void run(Timeout timeout) throws Exception { - if (provider.isClose() || nettyResponseFuture.isDone()) { + if (nettyRequestSender.isClosed() || nettyResponseFuture.isDone()) { timeoutsHolder.cancel(); return; } @@ -51,7 +51,7 @@ public void run(Timeout timeout) throws Exception { } else if (currentReadTimeoutInstant < requestTimeoutInstant) { // reschedule - timeoutsHolder.readTimeout = provider.newTimeout(this, durationBeforeCurrentReadTimeout); + timeoutsHolder.readTimeout = nettyRequestSender.newTimeout(this, durationBeforeCurrentReadTimeout); } else { // otherwise, no need to reschedule: requestTimeout will happen sooner diff --git a/src/main/java/com/ning/http/client/providers/netty/request/timeout/RequestTimeoutTimerTask.java b/src/main/java/com/ning/http/client/providers/netty/request/timeout/RequestTimeoutTimerTask.java index 25ffcf834d..6a4822f555 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/timeout/RequestTimeoutTimerTask.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/timeout/RequestTimeoutTimerTask.java @@ -16,15 +16,15 @@ import org.jboss.netty.util.Timeout; -import com.ning.http.client.providers.netty.NettyAsyncHttpProvider; import com.ning.http.client.providers.netty.future.NettyResponseFuture; +import com.ning.http.client.providers.netty.request.NettyRequestSender; public class RequestTimeoutTimerTask extends TimeoutTimerTask { private final long requestTimeout; - public RequestTimeoutTimerTask(NettyResponseFuture nettyResponseFuture, NettyAsyncHttpProvider provider, TimeoutsHolder timeoutsHolder, long requestTimeout) { - super(nettyResponseFuture, provider, timeoutsHolder); + public RequestTimeoutTimerTask(NettyResponseFuture nettyResponseFuture, NettyRequestSender nettyRequestSender, TimeoutsHolder timeoutsHolder, long requestTimeout) { + super(nettyResponseFuture, nettyRequestSender, timeoutsHolder); this.requestTimeout = requestTimeout; } @@ -33,9 +33,8 @@ public void run(Timeout timeout) throws Exception { // in any case, cancel possible idleConnectionTimeout timeoutsHolder.cancel(); - if (provider.isClose() || nettyResponseFuture.isDone()) { + if (nettyRequestSender.isClosed() || nettyResponseFuture.isDone()) return; - } String message = "Request timed out to " + nettyResponseFuture.getChannelRemoteAddress() + " of " + requestTimeout + " ms"; long age = millisTime() - nettyResponseFuture.getStart(); diff --git a/src/main/java/com/ning/http/client/providers/netty/request/timeout/TimeoutTimerTask.java b/src/main/java/com/ning/http/client/providers/netty/request/timeout/TimeoutTimerTask.java index ceed91777f..3ccfd3e918 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/timeout/TimeoutTimerTask.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/timeout/TimeoutTimerTask.java @@ -12,31 +12,31 @@ */ package com.ning.http.client.providers.netty.request.timeout; -import java.util.concurrent.TimeoutException; - import org.jboss.netty.util.TimerTask; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.ning.http.client.providers.netty.NettyAsyncHttpProvider; import com.ning.http.client.providers.netty.future.NettyResponseFuture; +import com.ning.http.client.providers.netty.request.NettyRequestSender; + +import java.util.concurrent.TimeoutException; public abstract class TimeoutTimerTask implements TimerTask { private static final Logger LOGGER = LoggerFactory.getLogger(TimeoutTimerTask.class); protected final NettyResponseFuture nettyResponseFuture; - protected final NettyAsyncHttpProvider provider; + protected final NettyRequestSender nettyRequestSender; protected final TimeoutsHolder timeoutsHolder; - public TimeoutTimerTask(NettyResponseFuture nettyResponseFuture, NettyAsyncHttpProvider provider, TimeoutsHolder timeoutsHolder) { + public TimeoutTimerTask(NettyResponseFuture nettyResponseFuture, NettyRequestSender nettyRequestSender, TimeoutsHolder timeoutsHolder) { this.nettyResponseFuture = nettyResponseFuture; - this.provider = provider; + this.nettyRequestSender = nettyRequestSender; this.timeoutsHolder = timeoutsHolder; } protected void expire(String message, long time) { LOGGER.debug("{} for {} after {} ms", message, nettyResponseFuture, time); - provider.abort(nettyResponseFuture, new TimeoutException(message)); + nettyRequestSender.abort(nettyResponseFuture, new TimeoutException(message)); } } diff --git a/src/main/java/com/ning/http/client/providers/netty/spnego/SpnegoEngine.java b/src/main/java/com/ning/http/client/providers/netty/spnego/SpnegoEngine.java index 58417958be..79f2ae7a2b 100644 --- a/src/main/java/com/ning/http/client/providers/netty/spnego/SpnegoEngine.java +++ b/src/main/java/com/ning/http/client/providers/netty/spnego/SpnegoEngine.java @@ -37,7 +37,6 @@ package com.ning.http.client.providers.netty.spnego; -import com.ning.http.util.Base64; import org.ietf.jgss.GSSContext; import org.ietf.jgss.GSSException; import org.ietf.jgss.GSSManager; @@ -46,6 +45,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.ning.http.util.Base64; + import java.io.IOException; /** @@ -55,6 +56,7 @@ * @since 4.1 */ public class SpnegoEngine { + private static final String SPNEGO_OID = "1.3.6.1.5.5.2"; private static final String KERBEROS_OID = "1.2.840.113554.1.2.2"; @@ -62,6 +64,8 @@ public class SpnegoEngine { private final SpnegoTokenGenerator spnegoGenerator; + public static final SpnegoEngine INSTANCE = new SpnegoEngine(); + public SpnegoEngine(final SpnegoTokenGenerator spnegoGenerator) { this.spnegoGenerator = spnegoGenerator; } diff --git a/src/main/java/com/ning/http/client/providers/netty/util/HttpUtil.java b/src/main/java/com/ning/http/client/providers/netty/util/HttpUtil.java new file mode 100644 index 0000000000..d52ab8966d --- /dev/null +++ b/src/main/java/com/ning/http/client/providers/netty/util/HttpUtil.java @@ -0,0 +1,48 @@ +package com.ning.http.client.providers.netty.util; + +import static com.ning.http.util.MiscUtils.isNonEmpty; + +import org.jboss.netty.handler.codec.http.HttpHeaders; + +import com.ning.http.client.uri.UriComponents; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map.Entry; + +public final class HttpUtil { + + public static final String HTTP = "http"; + public static final String HTTPS = "https"; + public static final String WEBSOCKET = "ws"; + public static final String WEBSOCKET_SSL = "wss"; + + private HttpUtil() { + } + + public static boolean isNTLM(List auth) { + return isNonEmpty(auth) && auth.get(0).startsWith("NTLM"); + } + + public static List getNettyHeaderValuesByCaseInsensitiveName(HttpHeaders headers, String name) { + ArrayList l = new ArrayList(); + for (Entry e : headers) { + if (e.getKey().equalsIgnoreCase(name)) { + l.add(e.getValue().trim()); + } + } + return l; + } + + public static boolean isWebSocket(String scheme) { + return WEBSOCKET.equalsIgnoreCase(scheme) || WEBSOCKET_SSL.equalsIgnoreCase(scheme); + } + + public static boolean isSecure(String scheme) { + return HTTPS.equalsIgnoreCase(scheme) || WEBSOCKET_SSL.equalsIgnoreCase(scheme); + } + + public static boolean isSecure(UriComponents uri) { + return isSecure(uri.getScheme()); + } +} From 803d64a9a9ebab30f372772c6b46106abeaa0963 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 22 Jul 2014 16:34:57 +0200 Subject: [PATCH 462/701] Fix webdav --- .../webdav/WebDavCompletionHandlerBase.java | 144 +++++++++++++++--- .../http/client/webdav/WebDavResponse.java | 2 +- 2 files changed, 125 insertions(+), 21 deletions(-) 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 e766755047..239ad73843 100644 --- a/src/main/java/com/ning/http/client/webdav/WebDavCompletionHandlerBase.java +++ b/src/main/java/com/ning/http/client/webdav/WebDavCompletionHandlerBase.java @@ -13,12 +13,6 @@ package com.ning.http.client.webdav; -import com.ning.http.client.AsyncCompletionHandlerBase; -import com.ning.http.client.AsyncHandler; -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.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; @@ -27,13 +21,25 @@ import org.w3c.dom.NodeList; import org.xml.sax.SAXException; +import com.ning.http.client.AsyncCompletionHandlerBase; +import com.ning.http.client.AsyncHandler; +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.Response; +import com.ning.http.client.cookie.Cookie; +import com.ning.http.client.uri.UriComponents; + import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; + import java.io.IOException; import java.io.InputStream; +import java.nio.ByteBuffer; import java.util.ArrayList; -import java.util.List; import java.util.Collections; +import java.util.List; /** * Simple {@link AsyncHandler} that add support for WebDav's response manipulation. @@ -96,7 +102,7 @@ public void onThrowable(Throwable t) { private class HttpStatusWrapper extends HttpResponseStatus { - private final HttpResponseStatus wrapper; + private final HttpResponseStatus wrapped; private final String statusText; @@ -104,44 +110,142 @@ private class HttpStatusWrapper extends HttpResponseStatus { public HttpStatusWrapper(HttpResponseStatus wrapper, String statusText, int statusCode) { super(wrapper.getUri(), wrapper.getConfig()); - this.wrapper = wrapper; + this.wrapped = wrapper; this.statusText = statusText; this.statusCode = statusCode; } + @Override + public Response prepareResponse(HttpResponseHeaders headers, List bodyParts) { + final Response wrappedResponse = wrapped.prepareResponse(headers, bodyParts); + + return new Response() { + + @Override + public int getStatusCode() { + return statusCode; + } + + @Override + public String getStatusText() { + return statusText; + } + + @Override + public byte[] getResponseBodyAsBytes() throws IOException { + return wrappedResponse.getResponseBodyAsBytes(); + } + + @Override + public ByteBuffer getResponseBodyAsByteBuffer() throws IOException { + return wrappedResponse.getResponseBodyAsByteBuffer(); + } + + @Override + public InputStream getResponseBodyAsStream() throws IOException { + return wrappedResponse.getResponseBodyAsStream(); + } + + @Override + public String getResponseBodyExcerpt(int maxLength, String charset) throws IOException { + return wrappedResponse.getResponseBodyExcerpt(maxLength, charset); + } + + @Override + public String getResponseBody(String charset) throws IOException { + return wrappedResponse.getResponseBody(charset); + } + + @Override + public String getResponseBodyExcerpt(int maxLength) throws IOException { + return wrappedResponse.getResponseBodyExcerpt(maxLength); + } + + @Override + public String getResponseBody() throws IOException { + return wrappedResponse.getResponseBody(); + } + + @Override + public UriComponents getUri() { + return wrappedResponse.getUri(); + } + + @Override + public String getContentType() { + return wrappedResponse.getContentType(); + } + + @Override + public String getHeader(String name) { + return wrappedResponse.getHeader(name); + } + + @Override + public List getHeaders(String name) { + return wrappedResponse.getHeaders(name); + } + + @Override + public FluentCaseInsensitiveStringsMap getHeaders() { + return wrappedResponse.getHeaders(); + } + + @Override + public boolean isRedirected() { + return wrappedResponse.isRedirected(); + } + + @Override + public List getCookies() { + return wrappedResponse.getCookies(); + } + + @Override + public boolean hasResponseStatus() { + return wrappedResponse.hasResponseStatus(); + } + + @Override + public boolean hasResponseHeaders() { + return wrappedResponse.hasResponseHeaders(); + } + + @Override + public boolean hasResponseBody() { + return wrappedResponse.hasResponseBody(); + } + }; + } + @Override public int getStatusCode() { - return (statusText == null ? wrapper.getStatusCode() : statusCode); + return (statusText == null ? wrapped.getStatusCode() : statusCode); } @Override public String getStatusText() { - return (statusText == null ? wrapper.getStatusText() : statusText); + return (statusText == null ? wrapped.getStatusText() : statusText); } @Override public String getProtocolName() { - return wrapper.getProtocolName(); + return wrapped.getProtocolName(); } @Override public int getProtocolMajorVersion() { - return wrapper.getProtocolMajorVersion(); + return wrapped.getProtocolMajorVersion(); } @Override public int getProtocolMinorVersion() { - return wrapper.getProtocolMinorVersion(); + return wrapped.getProtocolMinorVersion(); } @Override public String getProtocolText() { - return wrapper.getStatusText(); - } - - @Override - public Response prepareResponse(HttpResponseHeaders headers, List bodyParts) { - return wrapper.prepareResponse(headers, bodyParts); + return wrapped.getStatusText(); } } 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 bfc14eebe2..f8beebf5e7 100644 --- a/src/main/java/com/ning/http/client/webdav/WebDavResponse.java +++ b/src/main/java/com/ning/http/client/webdav/WebDavResponse.java @@ -51,7 +51,7 @@ public byte[] getResponseBodyAsBytes() throws IOException { } public ByteBuffer getResponseBodyAsByteBuffer() throws IOException { - return ByteBuffer.wrap(getResponseBodyAsBytes()); + return response.getResponseBodyAsByteBuffer(); } public InputStream getResponseBodyAsStream() throws IOException { From 8c07188c1862a4d9efa488e67f809e8b36026782 Mon Sep 17 00:00:00 2001 From: oleksiys Date: Tue, 22 Jul 2014 21:29:23 -0700 Subject: [PATCH 463/701] [1.9.x] + fix issue #631 https://github.com/AsyncHttpClient/async-http-client/issues/631 "Grizzly provider aggressively set cookie missing domain and path to /" --- .../providers/grizzly/GrizzlyAsyncHttpProvider.java | 13 +++---------- .../grizzly/GrizzlyAsyncProviderBasicTest.java | 9 +-------- 2 files changed, 4 insertions(+), 18 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 5350d9b374..769f58480b 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 @@ -1078,15 +1078,8 @@ private void convertCookies(final Collection cookies, final org.glassfish.grizzly.http.Cookie[] gCookies) { int idx = 0; for (final Cookie cookie : cookies) { - final org.glassfish.grizzly.http.Cookie gCookie = - new org.glassfish.grizzly.http.Cookie(cookie.getName(), cookie.getValue()); - gCookie.setDomain(cookie.getDomain()); - gCookie.setPath(cookie.getPath()); - gCookie.setVersion(1); - gCookie.setMaxAge(cookie.getMaxAge()); - gCookie.setSecure(cookie.isSecure()); - gCookies[idx] = gCookie; - idx++; + gCookies[idx++] = new org.glassfish.grizzly.http.Cookie( + cookie.getName(), cookie.getValue()); } } @@ -1477,7 +1470,7 @@ protected boolean onHttpPacketParsed(HttpHeader httpHeader, FilterChainContext c if (handler != null) { try { context.result(handler.onCompleted()); - } catch (Exception e) { + } catch (Throwable e) { context.abort(e); } } else { 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 38a87df634..60abfeff86 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012 Sonatype, Inc. All rights reserved. + * Copyright (c) 2012-2014 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. @@ -18,7 +18,6 @@ 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; @@ -52,10 +51,4 @@ public void customize(TCPNIOTransport transport, FilterChainBuilder builder) { protected String generatedAcceptEncodingHeader() { return "gzip"; } - - // FIXME server replies with a foo=bar cookie and yet Grizzly decodes it into foo=value; domain=/; path=/ - // see https://github.com/AsyncHttpClient/async-http-client/issues/631 - @Test(groups = { "standalone", "default_provider", "async" }, enabled = false) - public void asyncDoGetCookieTest() throws Throwable { - } } From 070f120de34ac58a3f9e84c1f02aec1d2245d6e9 Mon Sep 17 00:00:00 2001 From: oleksiys Date: Tue, 22 Jul 2014 21:43:16 -0700 Subject: [PATCH 464/701] [1.9.x] catch Throwable to abort HTTP request future --- .../client/providers/grizzly/GrizzlyAsyncHttpProvider.java | 4 ++-- 1 file changed, 2 insertions(+), 2 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 769f58480b..3164b7795c 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 @@ -1266,7 +1266,7 @@ protected void onInitialLineParsed(HttpHeader httpHeader, try { context.result(handler.onCompleted()); context.done(); - } catch (Exception e) { + } catch (Throwable e) { context.abort(e); } } @@ -1397,7 +1397,7 @@ protected void onHttpHeadersParsed(HttpHeader httpHeader, "WebSocket protocol error: unexpected HTTP response status during handshake."); context.result(null); } - } catch (Exception e) { + } catch (Throwable e) { httpHeader.setSkipRemainder(true); context.abort(e); } From 4411c2d450de7863faa850b89c0d202abb0eaae9 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 22 Jul 2014 18:32:40 +0200 Subject: [PATCH 465/701] Align 1.9 and 2 APIs, close #636 --- .../com/ning/http/client/AsyncHttpClient.java | 3 +- .../com/ning/http/client/ByteArrayPart.java | 54 - .../client/ConnectionPoolKeyStrategy.java | 2 +- .../client/DefaultConnectionPoolStrategy.java | 5 +- .../java/com/ning/http/client/FilePart.java | 53 - .../ning/http/client/ListenableFuture.java | 17 - .../java/com/ning/http/client/Request.java | 7 +- .../com/ning/http/client/RequestBuilder.java | 7 +- .../ning/http/client/RequestBuilderBase.java | 17 +- .../http/client/SimpleAsyncHttpClient.java | 19 +- .../java/com/ning/http/client/StringPart.java | 54 - .../client/generators/FileBodyGenerator.java | 12 + .../generators/InputStreamBodyGenerator.java | 4 + .../listener/TransferCompletionHandler.java | 155 +-- .../client/listener/TransferListener.java | 11 +- .../client/multipart/AbstractFilePart.java | 116 +++ .../http/client/multipart/ByteArrayPart.java | 78 ++ .../client/multipart/CounterPartVisitor.java | 34 + .../ning/http/client/multipart/FilePart.java | 161 +++ .../multipart/FilePartStallHandler.java | 61 ++ .../multipart/FileUploadStalledException.java | 4 +- .../http/client/multipart/MultipartBody.java | 241 +++++ .../multipart/MultipartRequestEntity.java | 22 +- .../http/client/multipart/MultipartUtils.java | 202 ++++ .../OutputStreamPartVisitor.java} | 32 +- .../com/ning/http/client/multipart/Part.java | 135 +++ .../ning/http/client/multipart/PartBase.java | 229 ++++ .../http/client/multipart/PartVisitor.java | 21 + .../{ => client}/multipart/RequestEntity.java | 2 +- .../http/client/multipart/StringPart.java | 111 ++ .../apache/ApacheAsyncHttpProvider.java | 79 +- .../apache/ApacheResponseFuture.java | 19 - .../grizzly/GrizzlyAsyncHttpProvider.java | 183 ++-- .../providers/jdk/JDKAsyncHttpProvider.java | 78 +- .../providers/jdk/JDKDelegateFuture.java | 5 +- .../http/client/providers/jdk/JDKFuture.java | 18 - .../netty/NettyAsyncHttpProvider.java | 64 +- .../netty/NettyAsyncHttpProviderConfig.java | 21 +- .../netty/channel/ChannelManager.java | 158 +-- .../providers/netty/channel/Channels.java | 4 + .../netty/channel/CleanupChannelGroup.java | 21 +- .../channel/pool/DefaultChannelPool.java | 25 +- .../netty/future/NettyResponseFuture.java | 202 ++-- .../providers/netty/handler/HttpProtocol.java | 513 ++++----- .../providers/netty/handler/Processor.java | 124 +-- .../providers/netty/handler/Protocol.java | 186 ++-- .../netty/handler/WebSocketProtocol.java | 261 +++-- .../netty/request/FeedableBodyGenerator.java | 120 +++ .../providers/netty/request/NettyRequest.java | 37 + .../netty/request/NettyRequestFactory.java | 324 ++++++ .../netty/request/NettyRequestSender.java | 974 ++++++------------ .../netty/request/ProgressListener.java | 9 +- .../netty/request/body/BodyChunkedInput.java | 5 +- .../netty/request/body/BodyFileRegion.java | 5 +- .../netty/request/body/NettyBody.java | 30 + .../netty/request/body/NettyBodyBody.java | 80 ++ .../request/body/NettyByteArrayBody.java | 55 + .../{ => body}/NettyConnectListener.java | 40 +- .../netty/request/body/NettyFileBody.java | 109 ++ .../request/body/NettyInputStreamBody.java | 97 ++ .../request/body/NettyMultipartBody.java | 41 + .../request/timeout/ReadTimeoutTimerTask.java | 14 +- .../timeout/RequestTimeoutTimerTask.java | 12 +- .../request/timeout/TimeoutTimerTask.java | 8 +- .../netty/response/NettyResponse.java | 31 +- .../netty/response/ResponseBodyPart.java | 27 +- .../netty/response/ResponseHeaders.java | 49 +- .../netty/response/ResponseStatus.java | 21 +- .../netty/util/ChannelBufferUtil.java | 35 - .../netty/util/ChannelBufferUtils.java | 33 + .../util/{HttpUtil.java => HttpUtils.java} | 17 +- .../providers/netty/ws/NettyWebSocket.java | 5 +- ...WebSocketUtil.java => WebSocketUtils.java} | 7 +- .../http/multipart/ByteArrayPartSource.java | 74 -- .../com/ning/http/multipart/FilePart.java | 221 ---- .../ning/http/multipart/FilePartSource.java | 118 --- .../http/multipart/FilePartStallHandler.java | 61 -- .../ning/http/multipart/MultipartBody.java | 602 ----------- .../http/multipart/MultipartEncodingUtil.java | 61 -- .../java/com/ning/http/multipart/Part.java | 514 --------- .../com/ning/http/multipart/PartBase.java | 144 --- .../com/ning/http/multipart/PartSource.java | 52 - .../com/ning/http/multipart/StringPart.java | 127 --- .../http/util/AsyncHttpProviderUtils.java | 83 +- .../com/ning/http/util/StandardCharsets.java | 1 + .../client/async/AsyncProvidersBasicTest.java | 44 +- .../async/FastUnauthorizedUploadTest.java | 21 +- .../client/async/FilePartLargeFileTest.java | 24 +- .../client/async/MultipartUploadTest.java | 33 +- .../client/async/ProxyTunnellingTest.java | 6 +- .../async/SimpleAsyncHttpClientTest.java | 23 +- .../client/async/TransferListenerTest.java | 51 +- .../multipart/MultipartBodyTest.java | 31 +- 93 files changed, 3971 insertions(+), 4335 deletions(-) delete mode 100644 src/main/java/com/ning/http/client/ByteArrayPart.java delete mode 100644 src/main/java/com/ning/http/client/FilePart.java delete mode 100644 src/main/java/com/ning/http/client/StringPart.java create mode 100644 src/main/java/com/ning/http/client/multipart/AbstractFilePart.java create mode 100644 src/main/java/com/ning/http/client/multipart/ByteArrayPart.java create mode 100644 src/main/java/com/ning/http/client/multipart/CounterPartVisitor.java create mode 100644 src/main/java/com/ning/http/client/multipart/FilePart.java create mode 100644 src/main/java/com/ning/http/client/multipart/FilePartStallHandler.java rename src/main/java/com/ning/http/{ => client}/multipart/FileUploadStalledException.java (92%) create mode 100644 src/main/java/com/ning/http/client/multipart/MultipartBody.java rename src/main/java/com/ning/http/{ => client}/multipart/MultipartRequestEntity.java (80%) create mode 100644 src/main/java/com/ning/http/client/multipart/MultipartUtils.java rename src/main/java/com/ning/http/client/{Part.java => multipart/OutputStreamPartVisitor.java} (52%) create mode 100644 src/main/java/com/ning/http/client/multipart/Part.java create mode 100644 src/main/java/com/ning/http/client/multipart/PartBase.java create mode 100644 src/main/java/com/ning/http/client/multipart/PartVisitor.java rename src/main/java/com/ning/http/{ => client}/multipart/RequestEntity.java (97%) create mode 100644 src/main/java/com/ning/http/client/multipart/StringPart.java create mode 100644 src/main/java/com/ning/http/client/providers/netty/request/FeedableBodyGenerator.java create mode 100644 src/main/java/com/ning/http/client/providers/netty/request/NettyRequest.java create mode 100644 src/main/java/com/ning/http/client/providers/netty/request/NettyRequestFactory.java create mode 100644 src/main/java/com/ning/http/client/providers/netty/request/body/NettyBody.java create mode 100644 src/main/java/com/ning/http/client/providers/netty/request/body/NettyBodyBody.java create mode 100644 src/main/java/com/ning/http/client/providers/netty/request/body/NettyByteArrayBody.java rename src/main/java/com/ning/http/client/providers/netty/request/{ => body}/NettyConnectListener.java (80%) create mode 100644 src/main/java/com/ning/http/client/providers/netty/request/body/NettyFileBody.java create mode 100644 src/main/java/com/ning/http/client/providers/netty/request/body/NettyInputStreamBody.java create mode 100644 src/main/java/com/ning/http/client/providers/netty/request/body/NettyMultipartBody.java delete mode 100644 src/main/java/com/ning/http/client/providers/netty/util/ChannelBufferUtil.java create mode 100644 src/main/java/com/ning/http/client/providers/netty/util/ChannelBufferUtils.java rename src/main/java/com/ning/http/client/providers/netty/util/{HttpUtil.java => HttpUtils.java} (64%) rename src/main/java/com/ning/http/client/providers/netty/ws/{WebSocketUtil.java => WebSocketUtils.java} (91%) delete mode 100644 src/main/java/com/ning/http/multipart/ByteArrayPartSource.java delete mode 100644 src/main/java/com/ning/http/multipart/FilePart.java delete mode 100644 src/main/java/com/ning/http/multipart/FilePartSource.java delete mode 100644 src/main/java/com/ning/http/multipart/FilePartStallHandler.java delete mode 100644 src/main/java/com/ning/http/multipart/MultipartBody.java delete mode 100644 src/main/java/com/ning/http/multipart/MultipartEncodingUtil.java delete mode 100644 src/main/java/com/ning/http/multipart/Part.java delete mode 100644 src/main/java/com/ning/http/multipart/PartBase.java delete mode 100644 src/main/java/com/ning/http/multipart/PartSource.java delete mode 100644 src/main/java/com/ning/http/multipart/StringPart.java rename src/test/java/com/ning/http/{ => client}/multipart/MultipartBodyTest.java (75%) diff --git a/src/main/java/com/ning/http/client/AsyncHttpClient.java b/src/main/java/com/ning/http/client/AsyncHttpClient.java index 7226e16c69..693aaa94d3 100755 --- a/src/main/java/com/ning/http/client/AsyncHttpClient.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClient.java @@ -35,6 +35,7 @@ import com.ning.http.client.filter.FilterContext; import com.ning.http.client.filter.FilterException; import com.ning.http.client.filter.RequestFilter; +import com.ning.http.client.multipart.Part; import com.ning.http.client.providers.jdk.JDKAsyncHttpProvider; import com.ning.http.client.resumable.ResumableAsyncHandler; @@ -124,7 +125,7 @@ *

    * String bodyResponse = f.get(); * * This class can also be used without the need of {@link AsyncHandler}

    diff --git a/src/main/java/com/ning/http/client/ByteArrayPart.java b/src/main/java/com/ning/http/client/ByteArrayPart.java deleted file mode 100644 index 1660accc81..0000000000 --- a/src/main/java/com/ning/http/client/ByteArrayPart.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * 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; - -public class ByteArrayPart implements Part { - private final String name; - private final String fileName; - private final byte[] data; - private final String mimeType; - private final String charSet; - - public ByteArrayPart(String name, String fileName, byte[] data, String mimeType, String charSet) { - this.name = name; - this.fileName = fileName; - this.data = data; - this.mimeType = mimeType; - this.charSet = charSet; - } - - @Override - public String getName() { - return name; - } - - public String getFileName() { - return fileName; - } - - public byte[] getData() { - return data; - } - - public String getMimeType() { - return mimeType; - } - - public String getCharSet() { - return charSet; - } -} diff --git a/src/main/java/com/ning/http/client/ConnectionPoolKeyStrategy.java b/src/main/java/com/ning/http/client/ConnectionPoolKeyStrategy.java index 11e4401433..c0c2172d01 100644 --- a/src/main/java/com/ning/http/client/ConnectionPoolKeyStrategy.java +++ b/src/main/java/com/ning/http/client/ConnectionPoolKeyStrategy.java @@ -19,5 +19,5 @@ public interface ConnectionPoolKeyStrategy { - String getKey(UriComponents uri); + String getKey(UriComponents uri, ProxyServer proxyServer); } diff --git a/src/main/java/com/ning/http/client/DefaultConnectionPoolStrategy.java b/src/main/java/com/ning/http/client/DefaultConnectionPoolStrategy.java index f77b77dc79..4369a8a102 100644 --- a/src/main/java/com/ning/http/client/DefaultConnectionPoolStrategy.java +++ b/src/main/java/com/ning/http/client/DefaultConnectionPoolStrategy.java @@ -22,7 +22,8 @@ public enum DefaultConnectionPoolStrategy implements ConnectionPoolKeyStrategy { INSTANCE; - public String getKey(UriComponents uri) { - return AsyncHttpProviderUtils.getBaseUrl(uri); + public String getKey(UriComponents uri, ProxyServer proxyServer) { + String serverPart = AsyncHttpProviderUtils.getBaseUrl(uri); + return proxyServer != null ? proxyServer.getUrl() + serverPart : serverPart; } } diff --git a/src/main/java/com/ning/http/client/FilePart.java b/src/main/java/com/ning/http/client/FilePart.java deleted file mode 100644 index 92824799db..0000000000 --- a/src/main/java/com/ning/http/client/FilePart.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * 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.io.File; - -/** - * A file multipart part. - */ -public class FilePart implements Part { - private final String name; - private final File file; - private final String mimeType; - private final String charSet; - - public FilePart(String name, File file, String mimeType, String charSet) { - this.name = name; - this.file = file; - this.mimeType = mimeType; - this.charSet = charSet; - } - - @Override - public String getName() { - return name; - } - - public File getFile() { - return file; - } - - public String getMimeType() { - return mimeType; - } - - public String getCharSet() { - return charSet; - } -} \ No newline at end of file diff --git a/src/main/java/com/ning/http/client/ListenableFuture.java b/src/main/java/com/ning/http/client/ListenableFuture.java index b119f26597..e2f75fb45d 100755 --- a/src/main/java/com/ning/http/client/ListenableFuture.java +++ b/src/main/java/com/ning/http/client/ListenableFuture.java @@ -54,28 +54,11 @@ public interface ListenableFuture extends Future { */ void abort(Throwable t); - /** - * Set the content that will be returned by this instance - * - * @param v the content that will be returned by this instance - */ - void content(V v); - /** * Touch the current instance to prevent external service to times out. */ void touch(); - /** - * Write the {@link Request} headers - */ - boolean getAndSetWriteHeaders(boolean writeHeader); - - /** - * Write the {@link Request} body - */ - boolean getAndSetWriteBody(boolean writeBody); - /** *

    Adds a listener and executor to the ListenableFuture. * The listener will be {@linkplain java.util.concurrent.Executor#execute(Runnable) passed diff --git a/src/main/java/com/ning/http/client/Request.java b/src/main/java/com/ning/http/client/Request.java index cd37e49ec2..e517cb479a 100644 --- a/src/main/java/com/ning/http/client/Request.java +++ b/src/main/java/com/ning/http/client/Request.java @@ -16,15 +16,16 @@ */ package com.ning.http.client; +import com.ning.http.client.cookie.Cookie; +import com.ning.http.client.multipart.Part; +import com.ning.http.client.uri.UriComponents; + import java.io.File; import java.io.InputStream; import java.net.InetAddress; import java.util.Collection; import java.util.List; -import com.ning.http.client.cookie.Cookie; -import com.ning.http.client.uri.UriComponents; - /** * The Request class can be used to construct HTTP request: *

    diff --git a/src/main/java/com/ning/http/client/RequestBuilder.java b/src/main/java/com/ning/http/client/RequestBuilder.java
    index 861570143b..00d1ca7fc1 100644
    --- a/src/main/java/com/ning/http/client/RequestBuilder.java
    +++ b/src/main/java/com/ning/http/client/RequestBuilder.java
    @@ -15,14 +15,15 @@
      */
     package com.ning.http.client;
     
    +import com.ning.http.client.cookie.Cookie;
    +import com.ning.http.client.multipart.Part;
    +import com.ning.http.util.QueryComputer;
    +
     import java.io.InputStream;
     import java.util.Collection;
     import java.util.List;
     import java.util.Map;
     
    -import com.ning.http.client.cookie.Cookie;
    -import com.ning.http.util.QueryComputer;
    -
     /**
      * Builder for a {@link Request}.
      * Warning: mutable and not thread-safe! Beware that it holds a reference on the Request instance it builds,
    diff --git a/src/main/java/com/ning/http/client/RequestBuilderBase.java b/src/main/java/com/ning/http/client/RequestBuilderBase.java
    index f4ab066579..e68735912c 100644
    --- a/src/main/java/com/ning/http/client/RequestBuilderBase.java
    +++ b/src/main/java/com/ning/http/client/RequestBuilderBase.java
    @@ -17,6 +17,15 @@
     
     import static com.ning.http.util.MiscUtils.isNonEmpty;
     
    +import org.slf4j.Logger;
    +import org.slf4j.LoggerFactory;
    +
    +import com.ning.http.client.cookie.Cookie;
    +import com.ning.http.client.multipart.Part;
    +import com.ning.http.client.uri.UriComponents;
    +import com.ning.http.util.AsyncHttpProviderUtils;
    +import com.ning.http.util.QueryComputer;
    +
     import java.io.File;
     import java.io.InputStream;
     import java.net.InetAddress;
    @@ -26,14 +35,6 @@
     import java.util.List;
     import java.util.Map;
     
    -import org.slf4j.Logger;
    -import org.slf4j.LoggerFactory;
    -
    -import com.ning.http.client.cookie.Cookie;
    -import com.ning.http.client.uri.UriComponents;
    -import com.ning.http.util.AsyncHttpProviderUtils;
    -import com.ning.http.util.QueryComputer;
    -
     /**
      * Builder for {@link Request}
      * 
    diff --git a/src/main/java/com/ning/http/client/SimpleAsyncHttpClient.java b/src/main/java/com/ning/http/client/SimpleAsyncHttpClient.java
    index 98c65b3a90..d428f38628 100644
    --- a/src/main/java/com/ning/http/client/SimpleAsyncHttpClient.java
    +++ b/src/main/java/com/ning/http/client/SimpleAsyncHttpClient.java
    @@ -12,25 +12,26 @@
      */
     package com.ning.http.client;
     
    -import java.io.IOException;
    -import java.util.Collection;
    -import java.util.List;
    -import java.util.Map;
    -import java.util.concurrent.ExecutorService;
    -import java.util.concurrent.Future;
    -
    -import javax.net.ssl.SSLContext;
    -
     import org.slf4j.Logger;
     import org.slf4j.LoggerFactory;
     
     import com.ning.http.client.cookie.Cookie;
    +import com.ning.http.client.multipart.Part;
     import com.ning.http.client.resumable.ResumableAsyncHandler;
     import com.ning.http.client.resumable.ResumableIOExceptionFilter;
     import com.ning.http.client.simple.HeaderMap;
     import com.ning.http.client.simple.SimpleAHCTransferListener;
     import com.ning.http.client.uri.UriComponents;
     
    +import javax.net.ssl.SSLContext;
    +
    +import java.io.IOException;
    +import java.util.Collection;
    +import java.util.List;
    +import java.util.Map;
    +import java.util.concurrent.ExecutorService;
    +import java.util.concurrent.Future;
    +
     /**
      * Simple implementation of {@link AsyncHttpClient} and it's related builders ({@link com.ning.http.client.AsyncHttpClientConfig},
      * {@link Realm}, {@link com.ning.http.client.ProxyServer} and {@link com.ning.http.client.AsyncHandler}. You can
    diff --git a/src/main/java/com/ning/http/client/StringPart.java b/src/main/java/com/ning/http/client/StringPart.java
    deleted file mode 100644
    index 54d9672b90..0000000000
    --- a/src/main/java/com/ning/http/client/StringPart.java
    +++ /dev/null
    @@ -1,54 +0,0 @@
    -/*
    - * 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 com.ning.http.util.StandardCharsets;
    -
    -/**
    - * A string multipart part.
    - */
    -public class StringPart implements Part {
    -    private final String name;
    -    private final String value;
    -    private final String charset;
    -
    -    public StringPart(String name, String value, String charset) {
    -        this.name = name;
    -        this.value = value;
    -        this.charset = charset;
    -    }
    -
    -    public StringPart(String name, String value) {
    -        this.name = name;
    -        this.value = value;
    -        this.charset = StandardCharsets.UTF_8.name();
    -    }
    -
    -    @Override
    -    public String getName() {
    -        return name;
    -    }
    -
    -    public String getValue() {
    -        return value;
    -    }
    -
    -    public String getCharset() {
    -        return charset;
    -    }
    -
    -}
    \ No newline at end of file
    diff --git a/src/main/java/com/ning/http/client/generators/FileBodyGenerator.java b/src/main/java/com/ning/http/client/generators/FileBodyGenerator.java
    index 7b8dce4d22..086a98b6db 100644
    --- a/src/main/java/com/ning/http/client/generators/FileBodyGenerator.java
    +++ b/src/main/java/com/ning/http/client/generators/FileBodyGenerator.java
    @@ -53,6 +53,18 @@ public RandomAccessBody createBody()
                 throws IOException {
             return new FileBody(file, regionSeek, regionLength);
         }
    +    
    +    public File getFile() {
    +        return file;
    +    }
    +
    +    public long getRegionSeek() {
    +        return regionSeek;
    +    }
    +
    +    public long getRegionLength() {
    +        return regionLength;
    +    }
     
         protected static class FileBody
                 implements RandomAccessBody {
    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 94b02ec507..a79a2e6b9e 100644
    --- a/src/main/java/com/ning/http/client/generators/InputStreamBodyGenerator.java
    +++ b/src/main/java/com/ning/http/client/generators/InputStreamBodyGenerator.java
    @@ -48,6 +48,10 @@ public InputStreamBodyGenerator(InputStream inputStream) {
             }
         }
     
    +    public InputStream getInputStream() {
    +        return inputStream;
    +    }
    +
         @Override
         public Body createBody() throws IOException {
             return new ISBody();
    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 4ff443bc85..8d305bd528 100644
    --- a/src/main/java/com/ning/http/client/listener/TransferCompletionHandler.java
    +++ b/src/main/java/com/ning/http/client/listener/TransferCompletionHandler.java
    @@ -12,27 +12,24 @@
      */
     package com.ning.http.client.listener;
     
    +import org.slf4j.Logger;
    +import org.slf4j.LoggerFactory;
    +
     import com.ning.http.client.AsyncCompletionHandlerBase;
     import com.ning.http.client.FluentCaseInsensitiveStringsMap;
     import com.ning.http.client.HttpResponseBodyPart;
     import com.ning.http.client.HttpResponseHeaders;
     import com.ning.http.client.Response;
     
    -import org.slf4j.Logger;
    -import org.slf4j.LoggerFactory;
    -
    -import java.io.IOException;
    -import java.nio.ByteBuffer;
    -import java.util.List;
     import java.util.concurrent.ConcurrentLinkedQueue;
     import java.util.concurrent.atomic.AtomicLong;
     
    -import static com.ning.http.util.MiscUtils.isNonEmpty;
    -
     /**
    - * A {@link com.ning.http.client.AsyncHandler} that can be used to notify a set of {@link com.ning.http.client.listener.TransferListener}
    + * A {@link org.asynchttpclient.AsyncHandler} that can be used to notify a set of {@link TransferListener}
      * 

    - *

    + * 
    + * + *
      * AsyncHttpClient client = new AsyncHttpClient();
      * TransferCompletionHandler tl = new TransferCompletionHandler();
      * tl.addTransferListener(new TransferListener() {
    @@ -46,7 +43,7 @@
      * public void onBytesReceived(ByteBuffer buffer) {
      * }
      * 

    - * public void onBytesSent(ByteBuffer buffer) { + * public void onBytesSent(long amount, long current, long total) { * } *

    * public void onRequestResponseCompleted() { @@ -57,39 +54,42 @@ * }); *

    * Response response = httpClient.prepareGet("http://...").execute(tl).get(); - *

    + *
    + * + *
    */ public class TransferCompletionHandler extends AsyncCompletionHandlerBase { private final static Logger logger = LoggerFactory.getLogger(TransferCompletionHandler.class); private final ConcurrentLinkedQueue listeners = new ConcurrentLinkedQueue(); private final boolean accumulateResponseBytes; - private TransferAdapter transferAdapter; - private AtomicLong bytesTransferred = new AtomicLong(); - private AtomicLong totalBytesToTransfer = new AtomicLong(0); + private FluentCaseInsensitiveStringsMap headers; + private long expectedTotal; + private long seen; /** - * Create a TransferCompletionHandler that will not accumulate bytes. The resulting {@link com.ning.http.client.Response#getResponseBody()}, - * {@link com.ning.http.client.Response#getResponseBodyAsStream()} and {@link Response#getResponseBodyExcerpt(int)} will - * throw an IllegalStateException if called. + * Create a TransferCompletionHandler that will not accumulate bytes. The resulting {@link org.asynchttpclient.Response#getResponseBody()}, + * {@link org.asynchttpclient.Response#getResponseBodyAsStream()} and {@link Response#getResponseBodyExcerpt(int)} will throw an IllegalStateException if called. */ public TransferCompletionHandler() { this(false); } /** - * Create a TransferCompletionHandler that can or cannot accumulate bytes and make it available when - * {@link com.ning.http.client.Response#getResponseBody()} get called. The default is false. - * - * @param accumulateResponseBytes true to accumulates bytes in memory. + * Create a TransferCompletionHandler that can or cannot accumulate bytes and make it available when {@link org.asynchttpclient.Response#getResponseBody()} get called. The + * default is false. + * + * @param accumulateResponseBytes + * true to accumulates bytes in memory. */ public TransferCompletionHandler(boolean accumulateResponseBytes) { this.accumulateResponseBytes = accumulateResponseBytes; } /** - * Add a {@link com.ning.http.client.listener.TransferListener} - * - * @param t a {@link com.ning.http.client.listener.TransferListener} + * Add a {@link TransferListener} + * + * @param t + * a {@link TransferListener} * @return this */ public TransferCompletionHandler addTransferListener(TransferListener t) { @@ -98,9 +98,10 @@ public TransferCompletionHandler addTransferListener(TransferListener t) { } /** - * Remove a {@link com.ning.http.client.listener.TransferListener} - * - * @param t a {@link com.ning.http.client.listener.TransferListener} + * Remove a {@link TransferListener} + * + * @param t + * a {@link TransferListener} * @return this */ public TransferCompletionHandler removeTransferListener(TransferListener t) { @@ -109,12 +110,17 @@ public TransferCompletionHandler removeTransferListener(TransferListener t) { } /** - * Associate a {@link com.ning.http.client.listener.TransferCompletionHandler.TransferAdapter} with this listener. - * - * @param transferAdapter {@link TransferAdapter} + * Set headers to this listener. + * + * @param headers + * {@link FluentCaseInsensitiveStringsMap} */ - public void transferAdapter(TransferAdapter transferAdapter) { - this.transferAdapter = transferAdapter; + public void headers(FluentCaseInsensitiveStringsMap headers) { + this.headers = headers; + // Netty 3 bug hack: last chunk is not notified, fixed in Netty 4 + String contentLength = headers.getFirstValue("Content-Length"); + if (contentLength != null) + expectedTotal = Long.valueOf(contentLength); } @Override @@ -135,48 +141,30 @@ public STATE onBodyPartReceived(final HttpResponseBodyPart content) throws Excep @Override public Response onCompleted(Response response) throws Exception { + // some chunks weren't notified, probably the last one + if (seen < expectedTotal) { + // do once + fireOnBytesSent(expectedTotal - seen, expectedTotal, expectedTotal); + } fireOnEnd(); return response; } @Override public STATE onHeaderWriteCompleted() { - List list = transferAdapter.getHeaders().get("Content-Length"); - if (isNonEmpty(list) && list.get(0) != "") { - totalBytesToTransfer.set(Long.valueOf(list.get(0))); + if (headers != null) { + fireOnHeadersSent(headers); } - - fireOnHeadersSent(transferAdapter.getHeaders()); - return STATE.CONTINUE; - } - - @Override - public STATE onContentWriteCompleted() { return STATE.CONTINUE; } @Override public STATE onContentWriteProgress(long amount, long current, long total) { - if (bytesTransferred.get() == -1) { - return STATE.CONTINUE; - } - - if (totalBytesToTransfer.get() == 0) { - totalBytesToTransfer.set(total); - } - - // We need to track the count because all is asynchronous and Netty may not invoke us on time. - bytesTransferred.addAndGet(amount); - - if (transferAdapter != null) { - byte[] bytes = new byte[(int) (amount)]; - transferAdapter.getBytes(bytes); - fireOnBytesSent(bytes); - } + seen += amount; + fireOnBytesSent(amount, current, total); return STATE.CONTINUE; } - @Override public void onThrowable(Throwable t) { fireOnThrowable(t); @@ -193,6 +181,7 @@ private void fireOnHeadersSent(FluentCaseInsensitiveStringsMap headers) { } private void fireOnHeaderReceived(FluentCaseInsensitiveStringsMap headers) { + for (TransferListener l : listeners) { try { l.onResponseHeadersReceived(headers); @@ -203,32 +192,6 @@ private void fireOnHeaderReceived(FluentCaseInsensitiveStringsMap headers) { } private void fireOnEnd() { - // There is a probability that the asynchronous listener never gets called, so we fake it at the end once - // we are 100% sure the response has been received. - long count = bytesTransferred.getAndSet(-1); - if (count != totalBytesToTransfer.get()) { - if (transferAdapter != null) { - byte[] bytes = new byte[8192]; - int leftBytes = (int) (totalBytesToTransfer.get() - count); - int length = 8192; - while (leftBytes > 0) { - if (leftBytes > 8192) { - leftBytes -= 8192; - } else { - length = leftBytes; - leftBytes = 0; - } - - if (length < 8192) { - bytes = new byte[length]; - } - - transferAdapter.getBytes(bytes); - fireOnBytesSent(bytes); - } - } - } - for (TransferListener l : listeners) { try { l.onRequestResponseCompleted(); @@ -241,17 +204,17 @@ private void fireOnEnd() { private void fireOnBytesReceived(byte[] b) { for (TransferListener l : listeners) { try { - l.onBytesReceived(ByteBuffer.wrap(b)); + l.onBytesReceived(b); } catch (Throwable t) { l.onThrowable(t); } } } - private void fireOnBytesSent(byte[] b) { + private void fireOnBytesSent(long amount, long current, long total) { for (TransferListener l : listeners) { try { - l.onBytesSent(ByteBuffer.wrap(b)); + l.onBytesSent(amount, current, total); } catch (Throwable t) { l.onThrowable(t); } @@ -267,18 +230,4 @@ private void fireOnThrowable(Throwable t) { } } } - - public abstract static class TransferAdapter { - private final FluentCaseInsensitiveStringsMap headers; - - public TransferAdapter(FluentCaseInsensitiveStringsMap headers) throws IOException { - this.headers = headers; - } - - public FluentCaseInsensitiveStringsMap getHeaders() { - return headers; - } - - public abstract void getBytes(byte[] bytes); - } } diff --git a/src/main/java/com/ning/http/client/listener/TransferListener.java b/src/main/java/com/ning/http/client/listener/TransferListener.java index 1b0b76fbe7..661954e825 100644 --- a/src/main/java/com/ning/http/client/listener/TransferListener.java +++ b/src/main/java/com/ning/http/client/listener/TransferListener.java @@ -15,7 +15,6 @@ import com.ning.http.client.FluentCaseInsensitiveStringsMap; import java.io.IOException; -import java.nio.ByteBuffer; /** * A simple interface an application can implements in order to received byte transfer information. @@ -35,16 +34,18 @@ public interface TransferListener { /** * Invoked every time response's chunk are received. * - * @param buffer a {@link ByteBuffer} + * @param b bytes */ - void onBytesReceived(ByteBuffer buffer) throws IOException; + void onBytesReceived(byte[] b) throws IOException; /** * Invoked every time request's chunk are sent. * - * @param buffer a {@link ByteBuffer} + * @param amount + * @param current + * @param total */ - void onBytesSent(ByteBuffer buffer); + void onBytesSent(long amount, long current, long total); /** * Invoked when the response bytes are been fully received. diff --git a/src/main/java/com/ning/http/client/multipart/AbstractFilePart.java b/src/main/java/com/ning/http/client/multipart/AbstractFilePart.java new file mode 100644 index 0000000000..7b44027950 --- /dev/null +++ b/src/main/java/com/ning/http/client/multipart/AbstractFilePart.java @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2014 AsyncHttpClient Project. 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.multipart; + +import static com.ning.http.util.StandardCharsets.US_ASCII; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +/** + * This class is an adaptation of the Apache HttpClient implementation + * + * @link http://hc.apache.org/httpclient-3.x/ + */ +public abstract class AbstractFilePart extends PartBase { + + /** + * Default content encoding of file attachments. + */ + public static final String DEFAULT_CONTENT_TYPE = "application/octet-stream"; + + /** + * Default transfer encoding of file attachments. + */ + public static final String DEFAULT_TRANSFER_ENCODING = "binary"; + + /** + * Attachment's file name as a byte array + */ + private static final byte[] FILE_NAME_BYTES = "; filename=".getBytes(US_ASCII); + + private long stalledTime = -1L; + + private String fileName; + + /** + * 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 + */ + public AbstractFilePart(String name, String contentType, String charset, String contentId) { + super(name, contentType == null ? DEFAULT_CONTENT_TYPE : contentType, charset, + DEFAULT_TRANSFER_ENCODING, contentId); + } + + protected void visitDispositionHeader(PartVisitor visitor) throws IOException { + super.visitDispositionHeader(visitor); + if (fileName != null) { + visitor.withBytes(FILE_NAME_BYTES); + visitor.withByte(QUOTE_BYTE); + visitor.withBytes(fileName.getBytes(US_ASCII)); + visitor.withByte(QUOTE_BYTE); + } + } + + protected byte[] generateFileStart(byte[] boundary) throws IOException { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + OutputStreamPartVisitor visitor = new OutputStreamPartVisitor(out); + visitStart(visitor, boundary); + visitDispositionHeader(visitor); + visitContentTypeHeader(visitor); + visitTransferEncodingHeader(visitor); + visitContentIdHeader(visitor); + visitEndOfHeader(visitor); + + return out.toByteArray(); + } + + protected byte[] generateFileEnd() throws IOException { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + OutputStreamPartVisitor visitor = new OutputStreamPartVisitor(out); + visitEnd(visitor); + return out.toByteArray(); + } + + public void setStalledTime(long ms) { + stalledTime = ms; + } + + public long getStalledTime() { + return stalledTime; + } + + public void setFileName(String fileName) { + this.fileName = fileName; + } + + public String getFileName() { + return fileName; + } + + @Override + public String toString() { + return new StringBuilder()// + .append(super.toString())// + .append(" filename=").append(fileName)// + .toString(); + } +} diff --git a/src/main/java/com/ning/http/client/multipart/ByteArrayPart.java b/src/main/java/com/ning/http/client/multipart/ByteArrayPart.java new file mode 100644 index 0000000000..6977d3ff4b --- /dev/null +++ b/src/main/java/com/ning/http/client/multipart/ByteArrayPart.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2014 AsyncHttpClient Project. 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.multipart; + +import java.io.IOException; +import java.io.OutputStream; +import java.nio.channels.WritableByteChannel; + +public class ByteArrayPart extends AbstractFilePart { + + private final byte[] bytes; + + public ByteArrayPart(String name, byte[] bytes) { + this(name, bytes, null); + } + + public ByteArrayPart(String name, byte[] bytes, String contentType) { + this(name, bytes, contentType, null); + } + + public ByteArrayPart(String name, byte[] bytes, String contentType, String charset) { + this(name, bytes, contentType, charset, null); + } + + public ByteArrayPart(String name, byte[] bytes, String contentType, String charset, String fileName) { + this(name, bytes, contentType, charset, fileName, null); + } + + public ByteArrayPart(String name, byte[] bytes, String contentType, String charset, String fileName, String contentId) { + super(name, contentType, charset, contentId); + if (bytes == null) { + throw new NullPointerException("bytes"); + } + this.bytes = bytes; + setFileName(fileName); + } + + @Override + protected void sendData(OutputStream out) throws IOException { + out.write(bytes); + } + + @Override + protected long getDataLength() { + return bytes.length; + } + + public byte[] getBytes() { + return bytes; + } + + @Override + public long write(WritableByteChannel target, byte[] boundary) throws IOException { + FilePartStallHandler handler = new FilePartStallHandler(getStalledTime(), this); + + try { + handler.start(); + + long length = MultipartUtils.writeBytesToChannel(target, generateFileStart(boundary)); + length += MultipartUtils.writeBytesToChannel(target, bytes); + length += MultipartUtils.writeBytesToChannel(target, generateFileEnd()); + + return length; + } finally { + handler.completed(); + } + } +} diff --git a/src/main/java/com/ning/http/client/multipart/CounterPartVisitor.java b/src/main/java/com/ning/http/client/multipart/CounterPartVisitor.java new file mode 100644 index 0000000000..6d903243a6 --- /dev/null +++ b/src/main/java/com/ning/http/client/multipart/CounterPartVisitor.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2014 AsyncHttpClient Project. 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.multipart; + +import java.io.IOException; + +public class CounterPartVisitor implements PartVisitor { + + private long count = 0L; + + @Override + public void withBytes(byte[] bytes) throws IOException { + count += bytes.length; + } + + @Override + public void withByte(byte b) throws IOException { + count++; + } + + public long getCount() { + return count; + } +} diff --git a/src/main/java/com/ning/http/client/multipart/FilePart.java b/src/main/java/com/ning/http/client/multipart/FilePart.java new file mode 100644 index 0000000000..64e8727f22 --- /dev/null +++ b/src/main/java/com/ning/http/client/multipart/FilePart.java @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2014 AsyncHttpClient Project. 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.multipart; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.RandomAccessFile; +import java.nio.channels.FileChannel; +import java.nio.channels.WritableByteChannel; + +public class FilePart extends AbstractFilePart { + + private static final Logger LOGGER = LoggerFactory.getLogger(FilePart.class); + + private final File file; + + public FilePart(String name, File file) { + this(name, file, null, null); + } + + public FilePart(String name, File file, String contentType) { + this(name, file, null, contentType, null); + } + + public FilePart(String name, File file, String contentType, String charset) { + this(name, file, null, contentType, charset, null); + } + + public FilePart(String name, File file, String contentType, String charset, String fileName) { + this(name, file, null, contentType, charset, fileName); + } + + public FilePart(String name, File file, String contentType, String charset, String fileName, String contentId) { + super(name, contentType, charset, contentId); + this.file = file; + if (file == null) { + throw new NullPointerException("file"); + } + if (!file.isFile()) { + throw new IllegalArgumentException("File is not a normal file " + file.getAbsolutePath()); + } + if (!file.canRead()) { + throw new IllegalArgumentException("File is not readable " + file.getAbsolutePath()); + } + setFileName(fileName != null ? fileName : file.getName()); + } + + @Override + protected void sendData(OutputStream out) throws IOException { + if (getDataLength() == 0) { + + // this file contains no data, so there is nothing to send. + // we don't want to create a zero length buffer as this will + // cause an infinite loop when reading. + return; + } + + byte[] tmp = new byte[4096]; + InputStream instream = new FileInputStream(file); + try { + int len; + while ((len = instream.read(tmp)) >= 0) { + out.write(tmp, 0, len); + } + } finally { + // we're done with the stream, close it + instream.close(); + } + } + + @Override + protected long getDataLength() { + return file.length(); + } + + public File getFile() { + return file; + } + + @Override + public long write(WritableByteChannel target, byte[] boundary) throws IOException { + FilePartStallHandler handler = new FilePartStallHandler(getStalledTime(), this); + + handler.start(); + + int length = 0; + + length += MultipartUtils.writeBytesToChannel(target, generateFileStart(boundary)); + + RandomAccessFile raf = new RandomAccessFile(file, "r"); + FileChannel fc = raf.getChannel(); + + long l = file.length(); + int fileLength = 0; + long nWrite = 0; + // FIXME why sync? + try { + synchronized (fc) { + while (fileLength != l) { + if (handler.isFailed()) { + LOGGER.debug("Stalled error"); + throw new FileUploadStalledException(); + } + try { + nWrite = fc.transferTo(fileLength, l, target); + + if (nWrite == 0) { + LOGGER.info("Waiting for writing..."); + try { + fc.wait(50); + } catch (InterruptedException e) { + LOGGER.trace(e.getMessage(), e); + } + } else { + handler.writeHappened(); + } + } catch (IOException ex) { + String message = ex.getMessage(); + + // http://bugs.sun.com/view_bug.do?bug_id=5103988 + if (message != null && message.equalsIgnoreCase("Resource temporarily unavailable")) { + try { + fc.wait(1000); + } catch (InterruptedException e) { + LOGGER.trace(e.getMessage(), e); + } + LOGGER.warn("Experiencing NIO issue http://bugs.sun.com/view_bug.do?bug_id=5103988. Retrying"); + continue; + } else { + throw ex; + } + } + fileLength += nWrite; + } + } + } finally { + handler.completed(); + raf.close(); + } + + length += MultipartUtils.writeBytesToChannel(target, generateFileEnd()); + + return length; + } +} diff --git a/src/main/java/com/ning/http/client/multipart/FilePartStallHandler.java b/src/main/java/com/ning/http/client/multipart/FilePartStallHandler.java new file mode 100644 index 0000000000..de1d8f7754 --- /dev/null +++ b/src/main/java/com/ning/http/client/multipart/FilePartStallHandler.java @@ -0,0 +1,61 @@ +/* + * 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.multipart; + +import java.util.Timer; +import java.util.TimerTask; + +/** + * @author Gail Hernandez + */ +public class FilePartStallHandler extends TimerTask { + public FilePartStallHandler(long waitTime, AbstractFilePart filePart) { + _waitTime = waitTime; + _failed = false; + _written = false; + } + + public void completed() { + if (_waitTime > 0) { + _timer.cancel(); + } + } + + public boolean isFailed() { + return _failed; + } + + public void run() { + if (!_written) { + _failed = true; + _timer.cancel(); + } + _written = false; + } + + public void start() { + if (_waitTime > 0) { + _timer = new Timer(); + _timer.scheduleAtFixedRate(this, _waitTime, _waitTime); + } + } + + public void writeHappened() { + _written = true; + } + + private long _waitTime; + private Timer _timer; + private boolean _failed; + private boolean _written; +} diff --git a/src/main/java/com/ning/http/multipart/FileUploadStalledException.java b/src/main/java/com/ning/http/client/multipart/FileUploadStalledException.java similarity index 92% rename from src/main/java/com/ning/http/multipart/FileUploadStalledException.java rename to src/main/java/com/ning/http/client/multipart/FileUploadStalledException.java index 6549929868..0cb1a3b2fe 100644 --- a/src/main/java/com/ning/http/multipart/FileUploadStalledException.java +++ b/src/main/java/com/ning/http/client/multipart/FileUploadStalledException.java @@ -10,13 +10,13 @@ * "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.multipart; +package com.ning.http.client.multipart; import java.io.IOException; /** * @author Gail Hernandez */ +@SuppressWarnings("serial") public class FileUploadStalledException extends IOException { - } diff --git a/src/main/java/com/ning/http/client/multipart/MultipartBody.java b/src/main/java/com/ning/http/client/multipart/MultipartBody.java new file mode 100644 index 0000000000..65ed480c5b --- /dev/null +++ b/src/main/java/com/ning/http/client/multipart/MultipartBody.java @@ -0,0 +1,241 @@ +/* + * 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.multipart; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.ning.http.client.RandomAccessBody; + +import java.io.IOException; +import java.io.RandomAccessFile; +import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; +import java.nio.channels.WritableByteChannel; +import java.util.ArrayList; +import java.util.List; + +public class MultipartBody implements RandomAccessBody { + + private final static Logger LOGGER = LoggerFactory.getLogger(MultipartBody.class); + + private final byte[] boundary; + private final long contentLength; + private final String contentType; + private final List parts; + private final List pendingOpenFiles = new ArrayList(); + + private boolean transfertDone = false; + + private int currentPart = 0; + private byte[] currentBytes; + private int currentBytesPosition = -1; + private boolean doneWritingParts = false; + private FileLocation fileLocation = FileLocation.NONE; + private FileChannel currentFileChannel; + + enum FileLocation { + NONE, START, MIDDLE, END + } + + public MultipartBody(List parts, String contentType, long contentLength, byte[] boundary) { + this.boundary = boundary; + this.contentLength = contentLength; + this.contentType = contentType; + this.parts = parts; + } + + public void close() throws IOException { + for (RandomAccessFile file : pendingOpenFiles) { + file.close(); + } + } + + public long getContentLength() { + return contentLength; + } + + public String getContentType() { + return contentType; + } + + // RandomAccessBody API, suited for HTTP but not for HTTPS + public long transferTo(long position, long count, WritableByteChannel target) throws IOException { + + long overallLength = 0; + + if (transfertDone) { + return contentLength; + } + + for (Part part : parts) { + overallLength += part.write(target, boundary); + } + + overallLength += MultipartUtils.writeBytesToChannel(target, MultipartUtils.getMessageEnd(boundary)); + + transfertDone = true; + + return overallLength; + } + + // Regular Body API + public long read(ByteBuffer buffer) throws IOException { + try { + int overallLength = 0; + + int maxLength = buffer.remaining(); + + if (currentPart == parts.size() && transfertDone) { + return -1; + } + + boolean full = false; + + while (!full && !doneWritingParts) { + Part part = null; + + if (currentPart < parts.size()) { + part = parts.get(currentPart); + } + if (currentFileChannel != null) { + overallLength += writeCurrentFile(buffer); + full = overallLength == maxLength; + + } else if (currentBytesPosition > -1) { + overallLength += writeCurrentBytes(buffer, maxLength - overallLength); + full = overallLength == maxLength; + + if (currentPart == parts.size() && currentBytesFullyRead()) { + doneWritingParts = true; + } + + } else if (part instanceof StringPart) { + StringPart stringPart = (StringPart) part; + // set new bytes, not full, so will loop to writeCurrentBytes above + initializeCurrentBytes(stringPart.getBytes(boundary)); + currentPart++; + + } else if (part instanceof AbstractFilePart) { + + AbstractFilePart filePart = (AbstractFilePart) part; + + switch (fileLocation) { + case NONE: + // set new bytes, not full, so will loop to writeCurrentBytes above + initializeCurrentBytes(filePart.generateFileStart(boundary)); + fileLocation = FileLocation.START; + break; + case START: + // set current file channel so code above executes first + initializeFileBody(filePart); + fileLocation = FileLocation.MIDDLE; + break; + case MIDDLE: + initializeCurrentBytes(filePart.generateFileEnd()); + fileLocation = FileLocation.END; + break; + case END: + currentPart++; + fileLocation = FileLocation.NONE; + if (currentPart == parts.size()) { + doneWritingParts = true; + } + } + } + } + + if (doneWritingParts) { + if (currentBytesPosition == -1) { + initializeCurrentBytes(MultipartUtils.getMessageEnd(boundary)); + } + + if (currentBytesPosition > -1) { + overallLength += writeCurrentBytes(buffer, maxLength - overallLength); + + if (currentBytesFullyRead()) { + currentBytes = null; + currentBytesPosition = -1; + transfertDone = true; + } + } + } + return overallLength; + + } catch (Exception e) { + LOGGER.error("Read exception", e); + return 0; + } + } + + private boolean currentBytesFullyRead() { + return currentBytes == null || currentBytesPosition >= currentBytes.length - 1; + } + + private void initializeFileBody(AbstractFilePart part) throws IOException { + + if (part instanceof FilePart) { + RandomAccessFile raf = new RandomAccessFile(FilePart.class.cast(part).getFile(), "r"); + pendingOpenFiles.add(raf); + currentFileChannel = raf.getChannel(); + + } else if (part instanceof ByteArrayPart) { + initializeCurrentBytes(ByteArrayPart.class.cast(part).getBytes()); + + } else { + throw new IllegalArgumentException("Unknow AbstractFilePart type"); + } + } + + private void initializeCurrentBytes(byte[] bytes) throws IOException { + currentBytes = bytes; + currentBytesPosition = 0; + } + + private int writeCurrentFile(ByteBuffer buffer) throws IOException { + + int read = currentFileChannel.read(buffer); + + if (currentFileChannel.position() == currentFileChannel.size()) { + + currentFileChannel.close(); + currentFileChannel = null; + + int currentFile = pendingOpenFiles.size() - 1; + pendingOpenFiles.get(currentFile).close(); + pendingOpenFiles.remove(currentFile); + } + + return read; + } + + private int writeCurrentBytes(ByteBuffer buffer, int length) throws IOException { + + int available = currentBytes.length - currentBytesPosition; + + int writeLength = Math.min(available, length); + + if (writeLength > 0) { + buffer.put(currentBytes, currentBytesPosition, writeLength); + + if (available <= length) { + currentBytesPosition = -1; + currentBytes = null; + } else { + currentBytesPosition += writeLength; + } + } + + return writeLength; + } +} diff --git a/src/main/java/com/ning/http/multipart/MultipartRequestEntity.java b/src/main/java/com/ning/http/client/multipart/MultipartRequestEntity.java similarity index 80% rename from src/main/java/com/ning/http/multipart/MultipartRequestEntity.java rename to src/main/java/com/ning/http/client/multipart/MultipartRequestEntity.java index 2276347545..94b99038a1 100644 --- a/src/main/java/com/ning/http/multipart/MultipartRequestEntity.java +++ b/src/main/java/com/ning/http/client/multipart/MultipartRequestEntity.java @@ -13,14 +13,16 @@ * License for the specific language governing permissions and limitations * under the License. */ -package com.ning.http.multipart; +package com.ning.http.client.multipart; import static com.ning.http.util.MiscUtils.isNonEmpty; +import static com.ning.http.util.StandardCharsets.US_ASCII; import com.ning.http.client.FluentCaseInsensitiveStringsMap; import java.io.IOException; import java.io.OutputStream; +import java.util.List; import java.util.Random; /** @@ -38,7 +40,7 @@ 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 = "-_1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".getBytes(US_ASCII); /** * Generates a random multipart boundary string. @@ -57,7 +59,7 @@ public static byte[] generateMultipartBoundary() { /** * The MIME parts as set by the constructor */ - protected final Part[] parts; + protected final List parts; private final byte[] multipartBoundary; @@ -69,7 +71,7 @@ public static byte[] generateMultipartBoundary() { * Creates a new multipart entity containing the given parts. * @param parts The parts to include. */ - public MultipartRequestEntity(Part[] parts, FluentCaseInsensitiveStringsMap requestHeaders) { + public MultipartRequestEntity(List parts, FluentCaseInsensitiveStringsMap requestHeaders) { if (parts == null) throw new NullPointerException("parts"); this.parts = parts; @@ -79,7 +81,7 @@ public MultipartRequestEntity(Part[] parts, FluentCaseInsensitiveStringsMap requ if (boundaryLocation != -1) { // boundary defined in existing Content-Type contentType = contentTypeHeader; - multipartBoundary = MultipartEncodingUtil.getAsciiBytes((contentTypeHeader.substring(boundaryLocation + "boundary=".length()).trim())); + multipartBoundary = (contentTypeHeader.substring(boundaryLocation + "boundary=".length()).trim()).getBytes(US_ASCII); } else { // generate boundary and append it to existing Content-Type multipartBoundary = generateMultipartBoundary(); @@ -90,14 +92,14 @@ public MultipartRequestEntity(Part[] parts, FluentCaseInsensitiveStringsMap requ contentType = computeContentType(MULTIPART_FORM_CONTENT_TYPE); } - contentLength = Part.getLengthOfParts(parts, multipartBoundary); + contentLength = MultipartUtils.getLengthOfParts(parts, multipartBoundary); } private String computeContentType(String base) { StringBuilder buffer = new StringBuilder(base); if (!base.endsWith(";")) buffer.append(";"); - return buffer.append(" boundary=").append(MultipartEncodingUtil.getAsciiString(multipartBoundary)).toString(); + return buffer.append(" boundary=").append(new String(multipartBoundary, US_ASCII)).toString(); } /** @@ -105,12 +107,14 @@ private String computeContentType(String base) { * * @return The boundary string of this entity in ASCII encoding. */ - protected byte[] getMultipartBoundary() { + public byte[] getMultipartBoundary() { return multipartBoundary; } public void writeRequest(OutputStream out) throws IOException { - Part.sendParts(out, parts, multipartBoundary); + for (Part part : parts) { + part.write(out, multipartBoundary); + } } public long getContentLength() { diff --git a/src/main/java/com/ning/http/client/multipart/MultipartUtils.java b/src/main/java/com/ning/http/client/multipart/MultipartUtils.java new file mode 100644 index 0000000000..b51a28ea20 --- /dev/null +++ b/src/main/java/com/ning/http/client/multipart/MultipartUtils.java @@ -0,0 +1,202 @@ +/* + * 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.multipart; + +import static com.ning.http.client.multipart.Part.CRLF_BYTES; +import static com.ning.http.client.multipart.Part.EXTRA_BYTES; +import static com.ning.http.util.MiscUtils.isNonEmpty; + +import com.ning.http.client.FluentCaseInsensitiveStringsMap; +import com.ning.http.util.StandardCharsets; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.channels.SelectionKey; +import java.nio.channels.Selector; +import java.nio.channels.SocketChannel; +import java.nio.channels.WritableByteChannel; +import java.util.List; +import java.util.Random; +import java.util.Set; + +public class MultipartUtils { + + private static final Logger LOGGER = LoggerFactory.getLogger(MultipartUtils.class); + + /** + * The Content-Type for multipart/form-data. + */ + private static final String MULTIPART_FORM_CONTENT_TYPE = "multipart/form-data"; + + /** + * The pool of ASCII chars to be used for generating a multipart boundary. + */ + private static byte[] MULTIPART_CHARS = "-_1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + .getBytes(StandardCharsets.US_ASCII); + + private MultipartUtils() { + } + + /** + * Creates a new multipart entity containing the given parts. + * + * @param parts + * The parts to include. + */ + public static MultipartBody newMultipartBody(List parts, FluentCaseInsensitiveStringsMap requestHeaders) { + if (parts == null) { + throw new NullPointerException("parts"); + } + + byte[] multipartBoundary; + String contentType; + + String contentTypeHeader = requestHeaders.getFirstValue("Content-Type"); + if (isNonEmpty(contentTypeHeader)) { + int boundaryLocation = contentTypeHeader.indexOf("boundary="); + if (boundaryLocation != -1) { + // boundary defined in existing Content-Type + contentType = contentTypeHeader; + multipartBoundary = (contentTypeHeader.substring(boundaryLocation + "boundary=".length()).trim()) + .getBytes(StandardCharsets.US_ASCII); + } else { + // generate boundary and append it to existing Content-Type + multipartBoundary = generateMultipartBoundary(); + contentType = computeContentType(contentTypeHeader, multipartBoundary); + } + } else { + multipartBoundary = generateMultipartBoundary(); + contentType = computeContentType(MULTIPART_FORM_CONTENT_TYPE, multipartBoundary); + } + + long contentLength = getLengthOfParts(parts, multipartBoundary); + + return new MultipartBody(parts, contentType, contentLength, multipartBoundary); + } + + private 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++) { + bytes[i] = MULTIPART_CHARS[rand.nextInt(MULTIPART_CHARS.length)]; + } + return bytes; + } + + private static String computeContentType(String base, byte[] multipartBoundary) { + StringBuilder buffer = new StringBuilder(base); + if (!base.endsWith(";")) + buffer.append(";"); + return buffer.append(" boundary=").append(new String(multipartBoundary, StandardCharsets.US_ASCII)).toString(); + } + + public static long writeBytesToChannel(WritableByteChannel target, byte[] bytes) throws IOException { + + int written = 0; + int maxSpin = 0; + synchronized (bytes) { + ByteBuffer message = ByteBuffer.wrap(bytes); + + if (target instanceof SocketChannel) { + final Selector selector = Selector.open(); + try { + final SocketChannel channel = (SocketChannel) target; + channel.register(selector, SelectionKey.OP_WRITE); + + while (written < bytes.length) { + selector.select(1000); + maxSpin++; + final Set selectedKeys = selector.selectedKeys(); + + for (SelectionKey key : selectedKeys) { + if (key.isWritable()) { + written += target.write(message); + maxSpin = 0; + } + } + if (maxSpin >= 10) { + throw new IOException("Unable to write on channel " + target); + } + } + } finally { + selector.close(); + } + } else { + while ((target.isOpen()) && (written < bytes.length)) { + long nWrite = target.write(message); + written += nWrite; + if (nWrite == 0 && maxSpin++ < 10) { + LOGGER.info("Waiting for writing..."); + try { + bytes.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; + } + } + } + } + return written; + } + + public static byte[] getMessageEnd(byte[] partBoundary) throws IOException { + + if (!isNonEmpty(partBoundary)) + throw new IllegalArgumentException("partBoundary may not be empty"); + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + OutputStreamPartVisitor visitor = new OutputStreamPartVisitor(out); + visitor.withBytes(EXTRA_BYTES); + visitor.withBytes(partBoundary); + visitor.withBytes(EXTRA_BYTES); + visitor.withBytes(CRLF_BYTES); + + return out.toByteArray(); + } + + public static long getLengthOfParts(List parts, byte[] partBoundary) { + + try { + if (parts == null) { + throw new NullPointerException("parts"); + } + long total = 0; + for (Part part : parts) { + long l = part.length(partBoundary); + if (l < 0) { + return -1; + } + total += l; + } + total += EXTRA_BYTES.length; + total += partBoundary.length; + total += EXTRA_BYTES.length; + total += CRLF_BYTES.length; + return total; + } catch (Exception e) { + LOGGER.error("An exception occurred while getting the length of the parts", e); + return 0L; + } + } +} diff --git a/src/main/java/com/ning/http/client/Part.java b/src/main/java/com/ning/http/client/multipart/OutputStreamPartVisitor.java similarity index 52% rename from src/main/java/com/ning/http/client/Part.java rename to src/main/java/com/ning/http/client/multipart/OutputStreamPartVisitor.java index b66fe7f850..4d0aade7c4 100644 --- a/src/main/java/com/ning/http/client/Part.java +++ b/src/main/java/com/ning/http/client/multipart/OutputStreamPartVisitor.java @@ -12,13 +12,31 @@ * 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; +package com.ning.http.client.multipart; -/** - * Interface for the parts in a multipart request. - */ -public interface Part { - String getName(); +import java.io.IOException; +import java.io.OutputStream; + +public class OutputStreamPartVisitor implements PartVisitor { + + private final OutputStream out; + + public OutputStreamPartVisitor(OutputStream out) { + this.out = out; + } + + @Override + public void withBytes(byte[] bytes) throws IOException { + out.write(bytes); + } + + @Override + public void withByte(byte b) throws IOException { + out.write(b); + } + + public OutputStream getOutputStream() { + return out; + } } diff --git a/src/main/java/com/ning/http/client/multipart/Part.java b/src/main/java/com/ning/http/client/multipart/Part.java new file mode 100644 index 0000000000..1e86eba420 --- /dev/null +++ b/src/main/java/com/ning/http/client/multipart/Part.java @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2014 AsyncHttpClient Project. 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.multipart; + +import static com.ning.http.util.StandardCharsets.US_ASCII; + +import java.io.IOException; +import java.io.OutputStream; +import java.nio.channels.WritableByteChannel; + +public interface Part { + + /** + * Carriage return/linefeed as a byte array + */ + byte[] CRLF_BYTES = "\r\n".getBytes(US_ASCII); + + /** + * Content dispostion as a byte + */ + byte QUOTE_BYTE = '\"'; + + /** + * Extra characters as a byte array + */ + byte[] EXTRA_BYTES = "--".getBytes(US_ASCII); + + /** + * Content dispostion as a byte array + */ + byte[] CONTENT_DISPOSITION_BYTES = "Content-Disposition: ".getBytes(US_ASCII); + + /** + * form-data as a byte array + */ + byte[] FORM_DATA_DISPOSITION_TYPE_BYTES = "form-data".getBytes(US_ASCII); + + /** + * name as a byte array + */ + byte[] NAME_BYTES = "; name=".getBytes(US_ASCII); + + /** + * Content type header as a byte array + */ + byte[] CONTENT_TYPE_BYTES = "Content-Type: ".getBytes(US_ASCII); + + /** + * Content charset as a byte array + */ + byte[] CHARSET_BYTES = "; charset=".getBytes(US_ASCII); + + /** + * Content type header as a byte array + */ + byte[] CONTENT_TRANSFER_ENCODING_BYTES = "Content-Transfer-Encoding: ".getBytes(US_ASCII); + + /** + * Content type header as a byte array + */ + byte[] CONTENT_ID_BYTES = "Content-ID: ".getBytes(US_ASCII); + + /** + * Return the name of this part. + * + * @return The name. + */ + String getName(); + + /** + * Returns the content type of this part. + * + * @return the content type, or null to exclude the content type header + */ + String getContentType(); + + /** + * Return the character encoding of this part. + * + * @return the character encoding, or null to exclude the character encoding header + */ + String getCharSet(); + + /** + * Return the transfer encoding of this part. + * + * @return the transfer encoding, or null to exclude the transfer encoding header + */ + String getTransferEncoding(); + + /** + * Return the content ID of this part. + * + * @return the content ID, or null to exclude the content ID header + */ + String getContentId(); + + /** + * Gets the disposition-type to be used in Content-Disposition header + * + * @return the disposition-type + */ + String getDispositionType(); + + /** + * 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 + * @param boundary + * the boundary + * @throws IOException + * If an IO problem occurs. + */ + void write(OutputStream out, byte[] boundary) throws IOException; + + /** + * 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. + */ + long length(byte[] boundary); + + long write(WritableByteChannel target, byte[] boundary) throws IOException; +} diff --git a/src/main/java/com/ning/http/client/multipart/PartBase.java b/src/main/java/com/ning/http/client/multipart/PartBase.java new file mode 100644 index 0000000000..8819b0fbba --- /dev/null +++ b/src/main/java/com/ning/http/client/multipart/PartBase.java @@ -0,0 +1,229 @@ +/* + * Copyright (c) 2014 AsyncHttpClient Project. 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.multipart; + +import static com.ning.http.util.StandardCharsets.US_ASCII; + +import java.io.IOException; +import java.io.OutputStream; + +public abstract class PartBase implements Part { + + /** + * The name of the form field, part of the Content-Disposition header + */ + private final String name; + + /** + * The main part of the Content-Type header + */ + private final String contentType; + + /** + * The charset (part of Content-Type header) + */ + private final String charSet; + + /** + * The Content-Transfer-Encoding header value. + */ + private final String transferEncoding; + + /** + * The Content-Id + */ + private final String contentId; + + /** + * The disposition type (part of Content-Disposition) + */ + private String dispositionType; + + /** + * Constructor. + * + * @param name The name of the part, or null + * @param contentType The content type, or null + * @param charSet The character encoding, or null + * @param transferEncoding The transfer encoding, or null + * @param contentId The content id, or null + */ + public PartBase(String name, String contentType, String charSet, String transferEncoding, String contentId) { + this.name = name; + this.contentType = contentType; + this.charSet = charSet; + this.transferEncoding = transferEncoding; + this.contentId = contentId; + } + + protected void visitStart(PartVisitor visitor, byte[] boundary) throws IOException { + visitor.withBytes(EXTRA_BYTES); + visitor.withBytes(boundary); + } + + protected void visitDispositionHeader(PartVisitor visitor) throws IOException { + visitor.withBytes(CRLF_BYTES); + visitor.withBytes(CONTENT_DISPOSITION_BYTES); + visitor.withBytes(getDispositionType() != null ? getDispositionType().getBytes(US_ASCII) : FORM_DATA_DISPOSITION_TYPE_BYTES); + if (getName() != null) { + visitor.withBytes(NAME_BYTES); + visitor.withByte(QUOTE_BYTE); + visitor.withBytes(getName().getBytes(US_ASCII)); + visitor.withByte(QUOTE_BYTE); + } + } + + protected void visitContentTypeHeader(PartVisitor visitor) throws IOException { + String contentType = getContentType(); + if (contentType != null) { + visitor.withBytes(CRLF_BYTES); + visitor.withBytes(CONTENT_TYPE_BYTES); + visitor.withBytes(contentType.getBytes(US_ASCII)); + String charSet = getCharSet(); + if (charSet != null) { + visitor.withBytes(CHARSET_BYTES); + visitor.withBytes(charSet.getBytes(US_ASCII)); + } + } + } + + protected void visitTransferEncodingHeader(PartVisitor visitor) throws IOException { + String transferEncoding = getTransferEncoding(); + if (transferEncoding != null) { + visitor.withBytes(CRLF_BYTES); + visitor.withBytes(CONTENT_TRANSFER_ENCODING_BYTES); + visitor.withBytes(transferEncoding.getBytes(US_ASCII)); + } + } + + protected void visitContentIdHeader(PartVisitor visitor) throws IOException { + String contentId = getContentId(); + if (contentId != null) { + visitor.withBytes(CRLF_BYTES); + visitor.withBytes(CONTENT_ID_BYTES); + visitor.withBytes(contentId.getBytes(US_ASCII)); + } + } + + protected void visitEndOfHeader(PartVisitor visitor) throws IOException { + visitor.withBytes(CRLF_BYTES); + visitor.withBytes(CRLF_BYTES); + } + + protected void visitEnd(PartVisitor visitor) throws IOException { + visitor.withBytes(CRLF_BYTES); + } + + protected abstract long getDataLength(); + + protected abstract void sendData(OutputStream out) throws IOException; + + /** + * 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 + * @param boundary + * the boundary + * @throws IOException + * If an IO problem occurs. + */ + public void write(OutputStream out, byte[] boundary) throws IOException { + + OutputStreamPartVisitor visitor = new OutputStreamPartVisitor(out); + + visitStart(visitor, boundary); + visitDispositionHeader(visitor); + visitContentTypeHeader(visitor); + visitTransferEncodingHeader(visitor); + visitContentIdHeader(visitor); + visitEndOfHeader(visitor); + sendData(visitor.getOutputStream()); + visitEnd(visitor); + } + + /** + * 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. + */ + public long length(byte[] boundary) { + + long dataLength = getDataLength(); + try { + + if (dataLength < 0L) { + return -1L; + } else { + CounterPartVisitor visitor = new CounterPartVisitor(); + visitStart(visitor, boundary); + visitDispositionHeader(visitor); + visitContentTypeHeader(visitor); + visitTransferEncodingHeader(visitor); + visitContentIdHeader(visitor); + visitEndOfHeader(visitor); + visitEnd(visitor); + return dataLength + visitor.getCount(); + } + } catch (IOException e) { + // can't happen + throw new RuntimeException("IOException while computing length, WTF", e); + } + } + + public String toString() { + return new StringBuilder()// + .append(getClass().getSimpleName())// + .append(" name=").append(getName())// + .append(" contentType=").append(getContentType())// + .append(" charset=").append(getCharSet())// + .append(" tranferEncoding=").append(getTransferEncoding())// + .append(" contentId=").append(getContentId())// + .append(" dispositionType=").append(getDispositionType())// + .toString(); + } + + @Override + public String getName() { + return this.name; + } + + @Override + public String getContentType() { + return this.contentType; + } + + @Override + public String getCharSet() { + return this.charSet; + } + + @Override + public String getTransferEncoding() { + return transferEncoding; + } + + @Override + public String getContentId() { + return contentId; + } + + @Override + public String getDispositionType() { + return dispositionType; + } + + public void setDispositionType(String dispositionType) { + this.dispositionType = dispositionType; + } +} diff --git a/src/main/java/com/ning/http/client/multipart/PartVisitor.java b/src/main/java/com/ning/http/client/multipart/PartVisitor.java new file mode 100644 index 0000000000..56c7a32586 --- /dev/null +++ b/src/main/java/com/ning/http/client/multipart/PartVisitor.java @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2014 AsyncHttpClient Project. 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.multipart; + +import java.io.IOException; + +public interface PartVisitor { + + void withBytes(byte[] bytes) throws IOException; + void withByte(byte b) throws IOException; +} diff --git a/src/main/java/com/ning/http/multipart/RequestEntity.java b/src/main/java/com/ning/http/client/multipart/RequestEntity.java similarity index 97% rename from src/main/java/com/ning/http/multipart/RequestEntity.java rename to src/main/java/com/ning/http/client/multipart/RequestEntity.java index ee7fda03e5..82b4ab2785 100644 --- a/src/main/java/com/ning/http/multipart/RequestEntity.java +++ b/src/main/java/com/ning/http/client/multipart/RequestEntity.java @@ -13,7 +13,7 @@ * License for the specific language governing permissions and limitations * under the License. */ -package com.ning.http.multipart; +package com.ning.http.client.multipart; import java.io.IOException; import java.io.OutputStream; diff --git a/src/main/java/com/ning/http/client/multipart/StringPart.java b/src/main/java/com/ning/http/client/multipart/StringPart.java new file mode 100644 index 0000000000..9f46bcd866 --- /dev/null +++ b/src/main/java/com/ning/http/client/multipart/StringPart.java @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2014 AsyncHttpClient Project. 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.multipart; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.nio.channels.WritableByteChannel; +import java.nio.charset.Charset; + +public class StringPart extends PartBase { + + /** + * Default content encoding of string parameters. + */ + public static final String DEFAULT_CONTENT_TYPE = "text/plain"; + + /** + * Default charset of string parameters + */ + public static final String DEFAULT_CHARSET = "US-ASCII"; + + /** + * Default transfer encoding of string parameters + */ + public static final String DEFAULT_TRANSFER_ENCODING = "8bit"; + + /** + * Contents of this StringPart. + */ + private final byte[] content; + private final String value; + + public StringPart(String name, String value, String charset) { + this(name, value, charset, null); + } + + /** + * 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 contentId + * the content id + */ + public StringPart(String name, String value, String charset, String contentId) { + + super(name, DEFAULT_CONTENT_TYPE, charset == null ? DEFAULT_CHARSET : charset, DEFAULT_TRANSFER_ENCODING, contentId); + if (value == null) { + throw new NullPointerException("value"); + } + if (value.indexOf(0) != -1) { + // See RFC 2048, 2.8. "8bit Data" + throw new IllegalArgumentException("NULs may not be present in string parts"); + } + content = value.getBytes(Charset.forName(charset)); + this.value = value; + } + + /** + * Writes the data to the given OutputStream. + * + * @param out + * the OutputStream to write to + * @throws java.io.IOException + * if there is a write error + */ + @Override + protected void sendData(OutputStream out) throws IOException { + out.write(content); + } + + /** + * Return the length of the data. + * + * @return The length of the data. + */ + @Override + protected long getDataLength() { + return content.length; + } + + public byte[] getBytes(byte[] boundary) throws IOException { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + write(outputStream, boundary); + return outputStream.toByteArray(); + } + + @Override + public long write(WritableByteChannel target, byte[] boundary) throws IOException { + return MultipartUtils.writeBytesToChannel(target, getBytes(boundary)); + } + + public String getValue() { + return value; + } +} 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 f17d748ca7..354f722f44 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,42 +12,9 @@ */ package com.ning.http.client.providers.apache; +import static com.ning.http.util.AsyncHttpProviderUtils.DEFAULT_CHARSET; import static com.ning.http.util.MiscUtils.isNonEmpty; -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.ByteArrayPart; -import com.ning.http.client.FilePart; -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.Param; -import com.ning.http.client.Part; -import com.ning.http.client.ProgressAsyncHandler; -import com.ning.http.client.ProxyServer; -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.StringPart; -import com.ning.http.client.cookie.CookieEncoder; -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.listener.TransferCompletionHandler; -import com.ning.http.client.resumable.ResumableAsyncHandler; -import com.ning.http.client.uri.UriComponents; -import com.ning.http.util.AsyncHttpProviderUtils; -import com.ning.http.util.ProxyUtils; -import com.ning.http.util.StandardCharsets; -import com.ning.http.util.UTF8UrlEncoder; - import org.apache.commons.httpclient.CircularRedirectException; import org.apache.commons.httpclient.Credentials; import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler; @@ -82,6 +49,40 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +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.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.Param; +import com.ning.http.client.ProgressAsyncHandler; +import com.ning.http.client.ProxyServer; +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.cookie.CookieEncoder; +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.listener.TransferCompletionHandler; +import com.ning.http.client.multipart.ByteArrayPart; +import com.ning.http.client.multipart.FilePart; +import com.ning.http.client.multipart.Part; +import com.ning.http.client.multipart.StringPart; +import com.ning.http.client.resumable.ResumableAsyncHandler; +import com.ning.http.client.uri.UriComponents; +import com.ning.http.util.AsyncHttpProviderUtils; +import com.ning.http.util.ProxyUtils; +import com.ning.http.util.StandardCharsets; +import com.ning.http.util.UTF8UrlEncoder; + import javax.net.SocketFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLHandshakeException; @@ -118,8 +119,6 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.zip.GZIPInputStream; -import static com.ning.http.util.AsyncHttpProviderUtils.DEFAULT_CHARSET; - /** * An {@link com.ning.http.client.AsyncHttpProvider} for Apache Http Client 3.1 */ @@ -390,7 +389,7 @@ private HttpMethodBase createMethod(HttpClient client, Request request) throws I } else if (config.getUserAgent() != null) { method.setRequestHeader("User-Agent", config.getUserAgent()); } else { - method.setRequestHeader("User-Agent", AsyncHttpProviderUtils.constructUserAgent(ApacheAsyncHttpProvider.class)); + method.setRequestHeader("User-Agent", AsyncHttpProviderUtils.constructUserAgent(ApacheAsyncHttpProvider.class, config)); } if (config.isCompressionEnabled()) { @@ -689,14 +688,14 @@ private MultipartRequestEntity createMultipartRequestEntity(String charset, List } else if (part instanceof FilePart) { parts[i] = new org.apache.commons.httpclient.methods.multipart.FilePart(part.getName(), ((FilePart) part).getFile(), - ((FilePart) part).getMimeType(), + ((FilePart) part).getContentType(), ((FilePart) part).getCharSet()); } else if (part instanceof ByteArrayPart) { - PartSource source = new ByteArrayPartSource(((ByteArrayPart) part).getFileName(), ((ByteArrayPart) part).getData()); + PartSource source = new ByteArrayPartSource(((ByteArrayPart) part).getFileName(), ((ByteArrayPart) part).getBytes()); parts[i] = new org.apache.commons.httpclient.methods.multipart.FilePart(part.getName(), source, - ((ByteArrayPart) part).getMimeType(), + ((ByteArrayPart) part).getContentType(), ((ByteArrayPart) part).getCharSet()); } else if (part == null) { 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 e5a7bc7606..343913e92b 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 @@ -48,16 +48,12 @@ public class ApacheResponseFuture extends AbstractListenableFuture { private final Request request; private final HttpMethodBase method; private Future reaperFuture; - private boolean writeHeaders; - private boolean writeBody; public ApacheResponseFuture(AsyncHandler asyncHandler, int responseTimeoutInMs, Request request, HttpMethodBase method) { this.asyncHandler = asyncHandler; this.responseTimeoutInMs = responseTimeoutInMs == -1 ? Integer.MAX_VALUE : responseTimeoutInMs; this.request = request; this.method = method; - writeHeaders = true; - writeBody = true; } protected void setInnerFuture(Future innerFuture) { @@ -209,19 +205,4 @@ public void touch() { public Request getRequest() { return request; } - - - @Override - public boolean getAndSetWriteHeaders(boolean writeHeaders) { - boolean b = this.writeHeaders; - this.writeHeaders = writeHeaders; - return b; - } - - @Override - public boolean getAndSetWriteBody(boolean writeBody) { - boolean b = this.writeBody; - this.writeBody = writeBody; - return b; - } } 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 3164b7795c..0012b1773b 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,80 +13,12 @@ package com.ning.http.client.providers.grizzly; -import com.ning.http.client.AsyncHandler; -import com.ning.http.client.AsyncHandlerExtensions; -import com.ning.http.client.AsyncHttpClient; -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.FluentCaseInsensitiveStringsMap; -import com.ning.http.client.ListenableFuture; -import com.ning.http.client.MaxRedirectException; -import com.ning.http.client.Param; -import com.ning.http.client.Part; -import com.ning.http.client.ProxyServer; -import com.ning.http.client.Realm; -import com.ning.http.client.Request; -import com.ning.http.client.RequestBuilder; -import com.ning.http.client.UpgradeHandler; -import com.ning.http.client.cookie.Cookie; -import com.ning.http.client.cookie.CookieDecoder; -import com.ning.http.client.filter.FilterContext; -import com.ning.http.client.filter.ResponseFilter; -import com.ning.http.client.listener.TransferCompletionHandler; -import com.ning.http.client.ntlm.NTLMEngine; -import com.ning.http.client.uri.UriComponents; -import com.ning.http.client.websocket.WebSocket; -import com.ning.http.client.websocket.WebSocketByteListener; -import com.ning.http.client.websocket.WebSocketCloseCodeReasonListener; -import com.ning.http.client.websocket.WebSocketListener; -import com.ning.http.client.websocket.WebSocketPingListener; -import com.ning.http.client.websocket.WebSocketPongListener; -import com.ning.http.client.websocket.WebSocketTextListener; -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 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; import static com.ning.http.util.AsyncHttpProviderUtils.getNonEmptyPath; - -import com.ning.http.util.AuthenticatorUtils; - import static com.ning.http.util.MiscUtils.isNonEmpty; -import com.ning.http.util.ProxyUtils; -import com.ning.http.util.SslUtils; - -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.UnsupportedEncodingException; -import java.net.InetSocketAddress; -import java.net.URI; -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; -import java.util.Locale; -import java.util.Map; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Semaphore; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicLong; - -import javax.net.ssl.HostnameVerifier; -import javax.net.ssl.SSLContext; - import org.glassfish.grizzly.Buffer; import org.glassfish.grizzly.CloseListener; import org.glassfish.grizzly.CloseType; @@ -125,6 +57,7 @@ import org.glassfish.grizzly.impl.SafeFutureImpl; import org.glassfish.grizzly.memory.Buffers; import org.glassfish.grizzly.memory.MemoryManager; +import org.glassfish.grizzly.nio.RoundRobinConnectionDistributor; import org.glassfish.grizzly.nio.transport.TCPNIOConnectorHandler; import org.glassfish.grizzly.nio.transport.TCPNIOTransport; import org.glassfish.grizzly.nio.transport.TCPNIOTransportBuilder; @@ -132,6 +65,7 @@ import org.glassfish.grizzly.ssl.SSLFilter; import org.glassfish.grizzly.strategies.SameThreadIOStrategy; import org.glassfish.grizzly.strategies.WorkerThreadIOStrategy; +import org.glassfish.grizzly.threadpool.ThreadPoolConfig; import org.glassfish.grizzly.utils.Charsets; import org.glassfish.grizzly.utils.DelayedExecutor; import org.glassfish.grizzly.utils.Futures; @@ -147,12 +81,73 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -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; +import com.ning.http.client.AsyncHandler; +import com.ning.http.client.AsyncHandlerExtensions; +import com.ning.http.client.AsyncHttpClient; +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.FluentCaseInsensitiveStringsMap; +import com.ning.http.client.ListenableFuture; +import com.ning.http.client.MaxRedirectException; +import com.ning.http.client.Param; +import com.ning.http.client.ProxyServer; +import com.ning.http.client.Realm; +import com.ning.http.client.Request; +import com.ning.http.client.RequestBuilder; +import com.ning.http.client.UpgradeHandler; +import com.ning.http.client.cookie.Cookie; +import com.ning.http.client.cookie.CookieDecoder; +import com.ning.http.client.filter.FilterContext; +import com.ning.http.client.filter.ResponseFilter; +import com.ning.http.client.listener.TransferCompletionHandler; +import com.ning.http.client.multipart.MultipartBody; +import com.ning.http.client.multipart.MultipartUtils; +import com.ning.http.client.multipart.Part; +import com.ning.http.client.ntlm.NTLMEngine; +import com.ning.http.client.uri.UriComponents; +import com.ning.http.client.websocket.WebSocket; +import com.ning.http.client.websocket.WebSocketByteListener; +import com.ning.http.client.websocket.WebSocketCloseCodeReasonListener; +import com.ning.http.client.websocket.WebSocketListener; +import com.ning.http.client.websocket.WebSocketPingListener; +import com.ning.http.client.websocket.WebSocketPongListener; +import com.ning.http.client.websocket.WebSocketTextListener; +import com.ning.http.client.websocket.WebSocketUpgradeHandler; +import com.ning.http.util.AsyncHttpProviderUtils; +import com.ning.http.util.AuthenticatorUtils; +import com.ning.http.util.ProxyUtils; +import com.ning.http.util.SslUtils; -import org.glassfish.grizzly.nio.RoundRobinConnectionDistributor; -import org.glassfish.grizzly.threadpool.ThreadPoolConfig; +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.SSLContext; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; +import java.net.InetSocketAddress; +import java.net.URI; +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; +import java.util.Locale; +import java.util.Map; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; /** * A Grizzly 2.0-based implementation of {@link AsyncHttpProvider}. @@ -940,7 +935,7 @@ private boolean sendAsGrizzlyRequest(final Request request, if (h instanceof TransferCompletionHandler) { final FluentCaseInsensitiveStringsMap map = new FluentCaseInsensitiveStringsMap(request.getHeaders()); - TransferCompletionHandler.class.cast(h).transferAdapter(new GrizzlyTransferAdapter(map)); + TransferCompletionHandler.class.cast(h).headers(map); } requestPacket.setConnection(connection); @@ -2118,9 +2113,9 @@ public boolean doHandle(final FilterChainContext ctx, throws IOException { final List parts = request.getParts(); - final MultipartRequestEntity mre = AsyncHttpProviderUtils.createMultipartRequestEntity(parts, request.getHeaders()); - final long contentLength = mre.getContentLength(); - final String contentType = mre.getContentType(); + final MultipartBody multipartBody = MultipartUtils.newMultipartBody(parts, request.getHeaders()); + final long contentLength = multipartBody.getContentLength(); + final String contentType = multipartBody.getContentType(); requestPacket.setContentLengthLong(contentLength); requestPacket.setContentType(contentType); if (LOGGER.isDebugEnabled()) { @@ -2130,7 +2125,7 @@ public boolean doHandle(final FilterChainContext ctx, final FeedableBodyGenerator generator = new FeedableBodyGenerator() { @Override public Body createBody() throws IOException { - return new MultipartBody(parts, contentType, contentLength); + return multipartBody; } }; generator.setFeeder(new FeedableBodyGenerator.BaseFeeder(generator) { @@ -2522,9 +2517,7 @@ public void updated(Connection result) { } private static String getPoolKey(Request request, ProxyServer proxyServer) { - String serverPart = - request.getConnectionPoolKeyStrategy().getKey(request.getURI()); - return proxyServer != null ? proxyServer.getUrl() + serverPart : serverPart; + return request.getConnectionPoolKeyStrategy().getKey(request.getURI(), proxyServer); } // ------------------------------------------------------ Nested Classes @@ -2668,28 +2661,6 @@ public Object type() { } // END SwitchingSSLFilter - private static final class GrizzlyTransferAdapter extends TransferCompletionHandler.TransferAdapter { - - - // -------------------------------------------------------- Constructors - - - public GrizzlyTransferAdapter(FluentCaseInsensitiveStringsMap headers) throws IOException { - super(headers); - } - - - // ---------------------------------------- Methods from TransferAdapter - - - @Override - public void getBytes(byte[] bytes) { - // TODO implement - } - - } // END GrizzlyTransferAdapter - - private static final class GrizzlyWebSocketAdapter implements WebSocket { final SimpleWebSocket gWebSocket; 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 65ca37fd58..2ad407f9d5 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 @@ -15,38 +15,6 @@ import static com.ning.http.util.AsyncHttpProviderUtils.DEFAULT_CHARSET; import static com.ning.http.util.MiscUtils.isNonEmpty; -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.lang.reflect.Field; -import java.net.Authenticator; -import java.net.ConnectException; -import java.net.HttpURLConnection; -import java.net.InetSocketAddress; -import java.net.PasswordAuthentication; -import java.net.Proxy; -import java.net.SocketAddress; -import java.net.SocketTimeoutException; -import java.net.URISyntaxException; -import java.net.UnknownHostException; -import java.nio.ByteBuffer; -import java.security.GeneralSecurityException; -import java.security.NoSuchAlgorithmException; -import java.util.Map; -import java.util.concurrent.Callable; -import java.util.concurrent.TimeoutException; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.zip.GZIPInputStream; - -import javax.naming.AuthenticationException; -import javax.net.ssl.HttpsURLConnection; -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLHandshakeException; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -69,13 +37,45 @@ import com.ning.http.client.filter.IOExceptionFilter; import com.ning.http.client.filter.ResponseFilter; import com.ning.http.client.listener.TransferCompletionHandler; +import com.ning.http.client.multipart.MultipartRequestEntity; import com.ning.http.client.uri.UriComponents; -import com.ning.http.multipart.MultipartRequestEntity; import com.ning.http.util.AsyncHttpProviderUtils; import com.ning.http.util.AuthenticatorUtils; import com.ning.http.util.ProxyUtils; import com.ning.http.util.SslUtils; +import javax.naming.AuthenticationException; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLHandshakeException; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.lang.reflect.Field; +import java.net.Authenticator; +import java.net.ConnectException; +import java.net.HttpURLConnection; +import java.net.InetSocketAddress; +import java.net.PasswordAuthentication; +import java.net.Proxy; +import java.net.SocketAddress; +import java.net.SocketTimeoutException; +import java.net.URISyntaxException; +import java.net.UnknownHostException; +import java.nio.ByteBuffer; +import java.security.GeneralSecurityException; +import java.security.NoSuchAlgorithmException; +import java.util.Map; +import java.util.concurrent.Callable; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.zip.GZIPInputStream; + public class JDKAsyncHttpProvider implements AsyncHttpProvider { private final static Logger logger = LoggerFactory.getLogger(JDKAsyncHttpProvider.class); @@ -118,7 +118,7 @@ public ListenableFuture execute(Request request, AsyncHandler handler) return execute(request, handler, null); } - public ListenableFuture execute(Request request, AsyncHandler handler, ListenableFuture future) throws IOException { + private ListenableFuture execute(Request request, AsyncHandler handler, JDKFuture future) throws IOException { if (isClose.get()) { throw new IOException("Closed"); } @@ -203,14 +203,14 @@ private final class AsyncHttpUrlConnection implements Callable { private HttpURLConnection urlConnection; private Request request; private final AsyncHandler asyncHandler; - private final ListenableFuture future; + private final JDKFuture future; private int currentRedirectCount; private AtomicBoolean isAuth = new AtomicBoolean(false); private byte[] cachedBytes; private int cachedBytesLenght; private boolean terminate = true; - public AsyncHttpUrlConnection(HttpURLConnection urlConnection, Request request, AsyncHandler asyncHandler, ListenableFuture future) { + public AsyncHttpUrlConnection(HttpURLConnection urlConnection, Request request, AsyncHandler asyncHandler, JDKFuture future) { this.urlConnection = urlConnection; this.request = request; this.asyncHandler = asyncHandler; @@ -473,7 +473,7 @@ private void configure(UriComponents uri, HttpURLConnection urlConnection, Reque ProxyServer proxyServer = ProxyUtils.getProxyServer(config, request); boolean avoidProxy = ProxyUtils.avoidProxy(proxyServer, uri.getHost()); if (!avoidProxy) { - urlConnection.setRequestProperty("Proxy-Connection", ka); + urlConnection.setRequestProperty("Connection", ka); if (proxyServer.getPrincipal() != null) { urlConnection.setRequestProperty("Proxy-Authorization", AuthenticatorUtils.computeBasicAuthentication(proxyServer)); } @@ -523,7 +523,7 @@ private void configure(UriComponents uri, HttpURLConnection urlConnection, Reque } else if (config.getUserAgent() != null) { urlConnection.setRequestProperty("User-Agent", config.getUserAgent()); } else { - urlConnection.setRequestProperty("User-Agent", AsyncHttpProviderUtils.constructUserAgent(JDKAsyncHttpProvider.class)); + urlConnection.setRequestProperty("User-Agent", AsyncHttpProviderUtils.constructUserAgent(JDKAsyncHttpProvider.class, config)); } if (isNonEmpty(request.getCookies())) { @@ -582,7 +582,7 @@ private void configure(UriComponents uri, HttpURLConnection urlConnection, Reque lenght = MAX_BUFFERED_BYTES; } - MultipartRequestEntity mre = AsyncHttpProviderUtils.createMultipartRequestEntity(request.getParts(), request.getHeaders()); + MultipartRequestEntity mre = new MultipartRequestEntity(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/jdk/JDKDelegateFuture.java b/src/main/java/com/ning/http/client/providers/jdk/JDKDelegateFuture.java index 5842691b48..3f3ea2531e 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 @@ -15,7 +15,6 @@ import static com.ning.http.util.DateUtils.millisTime; import com.ning.http.client.AsyncHandler; -import com.ning.http.client.ListenableFuture; import java.net.HttpURLConnection; import java.util.concurrent.ExecutionException; @@ -24,9 +23,9 @@ public class JDKDelegateFuture extends JDKFuture { - private final ListenableFuture delegateFuture; + private final JDKFuture delegateFuture; - public JDKDelegateFuture(AsyncHandler asyncHandler, int responseTimeoutInMs, ListenableFuture delegateFuture, HttpURLConnection urlConnection) { + public JDKDelegateFuture(AsyncHandler asyncHandler, int responseTimeoutInMs, JDKFuture delegateFuture, HttpURLConnection urlConnection) { super(asyncHandler, responseTimeoutInMs, urlConnection); this.delegateFuture = delegateFuture; } 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 3e7d808a5f..c7dcaeb4ec 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 @@ -45,15 +45,11 @@ public class JDKFuture extends AbstractListenableFuture { protected final AtomicLong touch = new AtomicLong(millisTime()); protected final AtomicBoolean contentProcessed = new AtomicBoolean(false); protected final HttpURLConnection urlConnection; - private boolean writeHeaders; - private boolean writeBody; public JDKFuture(AsyncHandler asyncHandler, int responseTimeoutInMs, HttpURLConnection urlConnection) { this.asyncHandler = asyncHandler; this.responseTimeoutInMs = responseTimeoutInMs; this.urlConnection = urlConnection; - writeHeaders = true; - writeBody = true; } protected void setInnerFuture(Future innerFuture) { @@ -158,18 +154,4 @@ public boolean hasExpired() { public void touch() { touch.set(millisTime()); } - - @Override - public boolean getAndSetWriteHeaders(boolean writeHeaders) { - boolean b = this.writeHeaders; - this.writeHeaders = writeHeaders; - return b; - } - - @Override - public boolean getAndSetWriteBody(boolean writeBody) { - boolean b = this.writeBody; - this.writeBody = writeBody; - return b; - } } 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 11aadd3e13..e32f6e870e 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 @@ -1,17 +1,15 @@ /* - * Copyright 2010 Ning, Inc. + * Copyright (c) 2014 AsyncHttpClient Project. All rights reserved. * - * 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: + * 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. * - * 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. + * 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.providers.netty; @@ -27,13 +25,6 @@ import com.ning.http.client.ListenableFuture; import com.ning.http.client.Request; import com.ning.http.client.providers.netty.channel.ChannelManager; -import com.ning.http.client.providers.netty.channel.pool.ChannelPool; -import com.ning.http.client.providers.netty.channel.pool.DefaultChannelPool; -import com.ning.http.client.providers.netty.channel.pool.NoopChannelPool; -import com.ning.http.client.providers.netty.handler.HttpProtocol; -import com.ning.http.client.providers.netty.handler.Processor; -import com.ning.http.client.providers.netty.handler.Protocol; -import com.ning.http.client.providers.netty.handler.WebSocketProtocol; import com.ning.http.client.providers.netty.request.NettyRequestSender; import java.io.IOException; @@ -50,38 +41,21 @@ public class NettyAsyncHttpProvider extends SimpleChannelUpstreamHandler impleme private final boolean allowStopNettyTimer; private final Timer nettyTimer; - private final NettyRequestSender nettyRequestSender; + private final NettyRequestSender requestSender; public NettyAsyncHttpProvider(AsyncHttpClientConfig config) { this.config = config; - - if (config.getAsyncHttpProviderConfig() instanceof NettyAsyncHttpProviderConfig) - nettyConfig = (NettyAsyncHttpProviderConfig) config.getAsyncHttpProviderConfig(); - else - nettyConfig = new NettyAsyncHttpProviderConfig(); + nettyConfig = config.getAsyncHttpProviderConfig() instanceof NettyAsyncHttpProviderConfig ? // + (NettyAsyncHttpProviderConfig) config.getAsyncHttpProviderConfig() + : new NettyAsyncHttpProviderConfig(); allowStopNettyTimer = nettyConfig.getNettyTimer() == null; nettyTimer = allowStopNettyTimer ? newNettyTimer() : nettyConfig.getNettyTimer(); - ChannelPool channelPool = nettyConfig.getChannelPool(); - if (channelPool == null && config.isAllowPoolingConnections()) { - channelPool = new DefaultChannelPool(config, nettyTimer); - } else if (channelPool == null) { - channelPool = new NoopChannelPool(); - } - - channelManager = new ChannelManager(config, nettyConfig, channelPool, nettyTimer); - - nettyRequestSender = new NettyRequestSender(config, nettyConfig, channelManager, nettyTimer, closed); - - Protocol webSocketProtocol = new WebSocketProtocol(channelManager, config, nettyRequestSender); - Processor webSocketProcessor = new Processor(config, channelManager, nettyRequestSender, webSocketProtocol); - - Protocol httpProtocol = new HttpProtocol(channelManager, config, nettyRequestSender, webSocketProcessor); - Processor httpProcessor = new Processor(config, channelManager, nettyRequestSender, httpProtocol); - - channelManager.configureBootstraps(httpProcessor, webSocketProcessor); + channelManager = new ChannelManager(config, nettyConfig, nettyTimer); + requestSender = new NettyRequestSender(config, nettyConfig, channelManager, nettyTimer, closed); + channelManager.configureBootstraps(requestSender, closed); } private Timer newNettyTimer() { @@ -109,10 +83,6 @@ public void close() { @Override public ListenableFuture execute(Request request, final AsyncHandler asyncHandler) throws IOException { - return nettyRequestSender.doConnect(request, asyncHandler, null, true, false); - } - - public boolean isClosed() { - return closed.get(); + return requestSender.sendRequest(request, asyncHandler, null, false); } } 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 d9a512d2c1..eb00258341 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 @@ -1,18 +1,15 @@ /* - * Copyright 2010 Ning, Inc. + * Copyright (c) 2014 AsyncHttpClient Project. All rights reserved. * - * 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. + * 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.providers.netty; diff --git a/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java b/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java index b13dd2ab5b..32f85f7ee6 100644 --- a/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java +++ b/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java @@ -13,6 +13,9 @@ */ package com.ning.http.client.providers.netty.channel; +import static com.ning.http.client.providers.netty.util.HttpUtils.WEBSOCKET; +import static com.ning.http.client.providers.netty.util.HttpUtils.isSecure; +import static com.ning.http.client.providers.netty.util.HttpUtils.isWebSocket; import static org.jboss.netty.channel.Channels.pipeline; import static org.jboss.netty.handler.ssl.SslHandler.getDefaultBufferPool; @@ -26,26 +29,26 @@ import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory; import org.jboss.netty.handler.codec.http.HttpClientCodec; import org.jboss.netty.handler.codec.http.HttpContentDecompressor; -import org.jboss.netty.handler.codec.http.HttpMethod; +import org.jboss.netty.handler.codec.http.websocketx.WebSocket08FrameDecoder; +import org.jboss.netty.handler.codec.http.websocketx.WebSocket08FrameEncoder; import org.jboss.netty.handler.ssl.SslHandler; import org.jboss.netty.handler.stream.ChunkedWriteHandler; import org.jboss.netty.util.Timer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.ning.http.client.AsyncHandler; import com.ning.http.client.AsyncHttpClientConfig; -import com.ning.http.client.ConnectionPoolKeyStrategy; -import com.ning.http.client.ProxyServer; -import com.ning.http.client.Request; -import com.ning.http.client.providers.netty.DiscardEvent; +import com.ning.http.client.providers.netty.Callback; import com.ning.http.client.providers.netty.NettyAsyncHttpProviderConfig; import com.ning.http.client.providers.netty.channel.pool.ChannelPool; +import com.ning.http.client.providers.netty.channel.pool.DefaultChannelPool; +import com.ning.http.client.providers.netty.channel.pool.NoopChannelPool; import com.ning.http.client.providers.netty.future.NettyResponseFuture; +import com.ning.http.client.providers.netty.handler.HttpProtocol; import com.ning.http.client.providers.netty.handler.Processor; -import com.ning.http.client.providers.netty.util.HttpUtil; -import com.ning.http.client.uri.UriComponents; -import com.ning.http.client.websocket.WebSocketUpgradeHandler; +import com.ning.http.client.providers.netty.handler.Protocol; +import com.ning.http.client.providers.netty.handler.WebSocketProtocol; +import com.ning.http.client.providers.netty.request.NettyRequestSender; import com.ning.http.util.SslUtils; import javax.net.ssl.SSLEngine; @@ -57,6 +60,7 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Semaphore; +import java.util.concurrent.atomic.AtomicBoolean; public class ChannelManager { @@ -66,6 +70,11 @@ public class ChannelManager { public static final String SSL_HANDLER = "sslHandler"; public static final String HTTP_PROCESSOR = "httpProcessor"; public static final String WS_PROCESSOR = "wsProcessor"; + public static final String DEFLATER_HANDLER = "deflater"; + public static final String INFLATER_HANDLER = "inflater"; + public static final String CHUNKED_WRITER_HANDLER = "chunkedWriter"; + public static final String WS_DECODER_HANDLER = "ws-decoder"; + public static final String WS_ENCODER_HANDLER = "ws-encoder"; private final AsyncHttpClientConfig config; private final NettyAsyncHttpProviderConfig nettyConfig; @@ -73,7 +82,6 @@ public class ChannelManager { private final boolean maxTotalConnectionsEnabled; private final Semaphore freeChannels; private final ChannelGroup openChannels; - private final int maxConnectionsPerHost; private final boolean maxConnectionsPerHostEnabled; private final ConcurrentHashMap freeChannelsPerHost; private final ConcurrentHashMap channelId2KeyPool; @@ -87,14 +95,24 @@ public class ChannelManager { private final ClientBootstrap webSocketBootstrap; private final ClientBootstrap secureWebSocketBootstrap; - public ChannelManager(AsyncHttpClientConfig config, NettyAsyncHttpProviderConfig nettyConfig, ChannelPool channelPool, Timer nettyTimer) { + private Processor wsProcessor; + + public ChannelManager(AsyncHttpClientConfig config, NettyAsyncHttpProviderConfig nettyConfig, Timer nettyTimer) { this.config = config; this.nettyConfig = nettyConfig; - this.channelPool = channelPool; this.nettyTimer = nettyTimer; + ChannelPool channelPool = nettyConfig.getChannelPool(); + if (channelPool == null && config.isAllowPoolingConnections()) { + channelPool = new DefaultChannelPool(config, nettyTimer); + } else if (channelPool == null) { + channelPool = new NoopChannelPool(); + } + this.channelPool = channelPool; + maxTotalConnectionsEnabled = config.getMaxConnections() > 0; + maxConnectionsPerHostEnabled = config.getMaxConnectionsPerHost() > 0; if (maxTotalConnectionsEnabled) { openChannels = new CleanupChannelGroup("asyncHttpClient") { @@ -121,9 +139,6 @@ public boolean remove(Object o) { freeChannels = null; } - maxConnectionsPerHost = config.getMaxConnectionsPerHost(); - maxConnectionsPerHostEnabled = config.getMaxConnectionsPerHost() > 0; - if (maxConnectionsPerHostEnabled) { freeChannelsPerHost = new ConcurrentHashMap(); channelId2KeyPool = new ConcurrentHashMap(); @@ -157,7 +172,8 @@ public boolean remove(Object o) { DefaultChannelFuture.setUseDeadLockChecker(nettyConfig.isUseDeadLockChecker()); // FIXME isn't there a constant for this name??? - nettyConfig.addProperty("connectTimeoutMillis", config.getConnectionTimeout()); + if (config.getConnectionTimeout() > 0) + nettyConfig.addProperty("connectTimeoutMillis", config.getConnectionTimeout()); for (Entry entry : nettyConfig.propertiesSet()) { String key = entry.getKey(); Object value = entry.getValue(); @@ -168,7 +184,13 @@ public boolean remove(Object o) { } } - public void configureBootstraps(final Processor httpProcessor, final Processor webSocketProcessor) { + public void configureBootstraps(NettyRequestSender requestSender, AtomicBoolean closed) { + + Protocol httpProtocol = new HttpProtocol(this, config, nettyConfig, requestSender); + final Processor httpProcessor = new Processor(config, this, requestSender, httpProtocol); + + Protocol wsProtocol = new WebSocketProtocol(this, config, nettyConfig, requestSender); + wsProcessor = new Processor(config, this, requestSender, wsProtocol); final boolean compressionEnabled = config.isCompressionEnabled(); @@ -176,10 +198,10 @@ public void configureBootstraps(final Processor httpProcessor, final Processor w public ChannelPipeline getPipeline() throws Exception { ChannelPipeline pipeline = pipeline(); - pipeline.addLast(HTTP_HANDLER, createHttpClientCodec()); + pipeline.addLast(HTTP_HANDLER, newHttpClientCodec()); if (compressionEnabled) - pipeline.addLast("inflater", new HttpContentDecompressor()); - pipeline.addLast("chunkedWriter", new ChunkedWriteHandler()); + pipeline.addLast(INFLATER_HANDLER, new HttpContentDecompressor()); + pipeline.addLast(CHUNKED_WRITER_HANDLER, new ChunkedWriteHandler()); pipeline.addLast(HTTP_PROCESSOR, httpProcessor); return pipeline; } @@ -189,8 +211,8 @@ public ChannelPipeline getPipeline() throws Exception { public ChannelPipeline getPipeline() throws Exception { ChannelPipeline pipeline = pipeline(); - pipeline.addLast(HTTP_HANDLER, createHttpClientCodec()); - pipeline.addLast(WS_PROCESSOR, webSocketProcessor); + pipeline.addLast(HTTP_HANDLER, newHttpClientCodec()); + pipeline.addLast(WS_PROCESSOR, wsProcessor); return pipeline; } }); @@ -200,10 +222,10 @@ public ChannelPipeline getPipeline() throws Exception { public ChannelPipeline getPipeline() throws Exception { ChannelPipeline pipeline = pipeline(); pipeline.addLast(SSL_HANDLER, new SslInitializer(ChannelManager.this)); - pipeline.addLast(HTTP_HANDLER, createHttpsClientCodec()); + pipeline.addLast(HTTP_HANDLER, newHttpClientCodec()); if (compressionEnabled) - pipeline.addLast("inflater", new HttpContentDecompressor()); - pipeline.addLast("chunkedWriter", new ChunkedWriteHandler()); + pipeline.addLast(INFLATER_HANDLER, new HttpContentDecompressor()); + pipeline.addLast(CHUNKED_WRITER_HANDLER, new ChunkedWriteHandler()); pipeline.addLast(HTTP_PROCESSOR, httpProcessor); return pipeline; } @@ -214,8 +236,8 @@ public ChannelPipeline getPipeline() throws Exception { public ChannelPipeline getPipeline() throws Exception { ChannelPipeline pipeline = pipeline(); pipeline.addLast(SSL_HANDLER, new SslInitializer(ChannelManager.this)); - pipeline.addLast(HTTP_HANDLER, createHttpsClientCodec()); - pipeline.addLast(WS_PROCESSOR, webSocketProcessor); + pipeline.addLast(HTTP_HANDLER, newHttpClientCodec()); + pipeline.addLast(WS_PROCESSOR, wsProcessor); return pipeline; } }); @@ -250,7 +272,7 @@ private Semaphore getFreeConnectionsForHost(String poolKey) { Semaphore freeConnections = freeChannelsPerHost.get(poolKey); if (freeConnections == null) { // lazy create the semaphore - Semaphore newFreeConnections = new Semaphore(maxConnectionsPerHost); + Semaphore newFreeConnections = new Semaphore(config.getMaxConnectionsPerHost()); freeConnections = freeChannelsPerHost.putIfAbsent(poolKey, newFreeConnections); if (freeConnections == null) freeConnections = newFreeConnections; @@ -278,6 +300,7 @@ public void close() { } } + // FIXME also shutdown in provider config.executorService().shutdown(); if (allowReleaseSocketChannelFactory) { socketChannelFactory.releaseExternalResources(); @@ -315,72 +338,77 @@ public void registerOpenChannel(Channel channel) { openChannels.add(channel); } - private HttpClientCodec createHttpClientCodec() { - return new HttpClientCodec(nettyConfig.getHttpClientCodecMaxInitialLineLength(),// - nettyConfig.getHttpClientCodecMaxHeaderSize(),// - nettyConfig.getHttpClientCodecMaxChunkSize()); - } - - private HttpClientCodec createHttpsClientCodec() { - return new HttpClientCodec(nettyConfig.getHttpClientCodecMaxInitialLineLength(),// + private HttpClientCodec newHttpClientCodec() { + return new HttpClientCodec(// + nettyConfig.getHttpClientCodecMaxInitialLineLength(),// nettyConfig.getHttpClientCodecMaxHeaderSize(),// nettyConfig.getHttpClientCodecMaxChunkSize()); } public SslHandler createSslHandler(String peerHost, int peerPort) throws GeneralSecurityException, IOException { + // FIXME use SslContext.defaultContext SSLEngine sslEngine = SslUtils.getInstance().createClientSSLEngine(config, peerHost, peerPort); return handshakeTimeoutInMillis > 0 ? new SslHandler(sslEngine, getDefaultBufferPool(), false, nettyTimer, handshakeTimeoutInMillis) : new SslHandler(sslEngine); } - public void upgradeProtocol(ChannelPipeline pipeline, String scheme, String host, int port, Processor webSocketProcessor) - throws IOException, GeneralSecurityException { + public void upgradeProtocol(ChannelPipeline pipeline, String scheme, String host, int port) throws IOException, + GeneralSecurityException { if (pipeline.get(HTTP_HANDLER) != null) pipeline.remove(HTTP_HANDLER); - if (HttpUtil.isSecure(scheme)) { + if (isSecure(scheme)) if (pipeline.get(SSL_HANDLER) == null) { - pipeline.addFirst(HTTP_HANDLER, createHttpClientCodec()); + pipeline.addFirst(HTTP_HANDLER, newHttpClientCodec()); pipeline.addFirst(SSL_HANDLER, createSslHandler(host, port)); } else { - pipeline.addAfter(SSL_HANDLER, HTTP_HANDLER, createHttpClientCodec()); + pipeline.addAfter(SSL_HANDLER, HTTP_HANDLER, newHttpClientCodec()); } - } else { - pipeline.addFirst(HTTP_HANDLER, createHttpClientCodec()); - } + else + pipeline.addFirst(HTTP_HANDLER, newHttpClientCodec()); - if (HttpUtil.isWebSocket(scheme)) - pipeline.replace(HTTP_PROCESSOR, WS_PROCESSOR, webSocketProcessor); + if (isWebSocket(scheme)) + pipeline.replace(HTTP_PROCESSOR, WS_PROCESSOR, wsProcessor); } - public boolean validateWebSocketRequest(Request request, AsyncHandler asyncHandler) { - return request.getMethod().equals(HttpMethod.GET.getName()) && asyncHandler instanceof WebSocketUpgradeHandler; + public String getPoolKey(NettyResponseFuture future) { + return future.getConnectionPoolKeyStrategy().getKey(future.getURI(), future.getProxyServer()); } - public String getPoolKey(NettyResponseFuture future) { - return getPoolKey(future.getURI(), future.getProxyServer(), future.getConnectionPoolKeyStrategy()); + public void verifyChannelPipeline(ChannelPipeline pipeline, String scheme) throws IOException, GeneralSecurityException { + + boolean isSecure = isSecure(scheme); + if (pipeline.get(SSL_HANDLER) != null) { + if (!isSecure) + pipeline.remove(SSL_HANDLER); + + } else if (isSecure) + pipeline.addFirst(SSL_HANDLER, new SslInitializer(this)); } - public String getPoolKey(UriComponents uri, ProxyServer proxy, ConnectionPoolKeyStrategy strategy) { - String serverPart = strategy.getKey(uri); - return proxy != null ? proxy.getUrl() + serverPart : serverPart; + public ClientBootstrap getBootstrap(String scheme, boolean useProxy, boolean useSSl) { + return scheme.startsWith(WEBSOCKET) && !useProxy ? (useSSl ? secureWebSocketBootstrap : webSocketBootstrap) : // + (useSSl ? secureBootstrap : plainBootstrap); } - public Channel verifyChannelPipeline(Channel channel, String scheme) throws IOException, GeneralSecurityException { + public void upgradePipelineForWebSockets(ChannelPipeline pipeline) { + pipeline.replace(HTTP_HANDLER, WS_ENCODER_HANDLER, new WebSocket08FrameEncoder(true)); + pipeline.addBefore(WS_PROCESSOR, WS_DECODER_HANDLER, new WebSocket08FrameDecoder(false, false, 10 * 1024)); + } - if (channel.getPipeline().get(SSL_HANDLER) != null && HttpUtil.HTTP.equalsIgnoreCase(scheme)) { - channel.getPipeline().remove(SSL_HANDLER); - } else if (channel.getPipeline().get(HTTP_HANDLER) != null && HttpUtil.HTTP.equalsIgnoreCase(scheme)) { - return channel; - } else if (channel.getPipeline().get(SSL_HANDLER) == null && HttpUtil.isSecure(scheme)) { - channel.getPipeline().addFirst(SSL_HANDLER, new SslInitializer(this)); - } - return channel; + public final Callback newDrainCallback(final NettyResponseFuture future, final Channel channel, final boolean keepAlive, + final String poolKey) { + + return new Callback(future) { + @Override + public void call() throws Exception { + tryToOfferChannelToPool(channel, keepAlive, poolKey); + } + }; } - public ClientBootstrap getBootstrap(String scheme, boolean useProxy, boolean useSSl) { - return (scheme.startsWith(HttpUtil.WEBSOCKET) && !useProxy) ? (useSSl ? secureWebSocketBootstrap : webSocketBootstrap) - : (useSSl ? secureBootstrap : plainBootstrap); + public void drainChannel(final Channel channel, final NettyResponseFuture future) { + Channels.setAttachment(channel, newDrainCallback(future, channel, future.isKeepAlive(), getPoolKey(future))); } } diff --git a/src/main/java/com/ning/http/client/providers/netty/channel/Channels.java b/src/main/java/com/ning/http/client/providers/netty/channel/Channels.java index ced352b1a3..2af934eca4 100644 --- a/src/main/java/com/ning/http/client/providers/netty/channel/Channels.java +++ b/src/main/java/com/ning/http/client/providers/netty/channel/Channels.java @@ -33,4 +33,8 @@ public static Object getAttachment(Channel channel) { public static void setDiscard(Channel channel) { setAttachment(channel, DiscardEvent.INSTANCE); } + + public static boolean isChannelValid(Channel channel) { + return channel != null && channel.isOpen() && channel.isConnected(); + } } diff --git a/src/main/java/com/ning/http/client/providers/netty/channel/CleanupChannelGroup.java b/src/main/java/com/ning/http/client/providers/netty/channel/CleanupChannelGroup.java index 0e447d2ee3..09114c3893 100644 --- a/src/main/java/com/ning/http/client/providers/netty/channel/CleanupChannelGroup.java +++ b/src/main/java/com/ning/http/client/providers/netty/channel/CleanupChannelGroup.java @@ -1,31 +1,16 @@ /* - * Copyright (c) 2010-2012 Sonatype, Inc. All rights reserved. + * Copyright (c) 2014 AsyncHttpClient Project. 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. + * 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. */ -/* - * Copyright 2010 Bruno de Carvalho - * - * Licensed 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.channel; import org.jboss.netty.channel.Channel; diff --git a/src/main/java/com/ning/http/client/providers/netty/channel/pool/DefaultChannelPool.java b/src/main/java/com/ning/http/client/providers/netty/channel/pool/DefaultChannelPool.java index 894211aeaa..4d67d33afe 100644 --- a/src/main/java/com/ning/http/client/providers/netty/channel/pool/DefaultChannelPool.java +++ b/src/main/java/com/ning/http/client/providers/netty/channel/pool/DefaultChannelPool.java @@ -15,14 +15,6 @@ import static com.ning.http.util.DateUtils.millisTime; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; - import org.jboss.netty.channel.Channel; import org.jboss.netty.util.Timeout; import org.jboss.netty.util.Timer; @@ -31,10 +23,17 @@ import org.slf4j.LoggerFactory; import com.ning.http.client.AsyncHttpClientConfig; -import com.ning.http.client.providers.netty.channel.ChannelManager; import com.ning.http.client.providers.netty.channel.Channels; import com.ning.http.client.providers.netty.future.NettyResponseFuture; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + /** * A simple implementation of {@link com.ning.http.client.providers.netty.channel.pool.ChannelPool} based on a {@link java.util.concurrent.ConcurrentHashMap} */ @@ -124,10 +123,6 @@ private boolean isTTLExpired(Channel channel, long now) { return creation == null || now - creation.creationTime >= maxConnectionTTL; } - private boolean isRemotelyClosed(Channel channel) { - return !channel.isConnected() || !channel.isOpen(); - } - private final class IdleChannelDetector implements TimerTask { private boolean isIdleTimeoutExpired(IdleChannel idleChannel, long now) { @@ -139,7 +134,7 @@ private List expiredChannels(ConcurrentLinkedQueue poo List idleTimeoutChannels = null; for (IdleChannel idleChannel : pool) { if (isTTLExpired(idleChannel.channel, now) || isIdleTimeoutExpired(idleChannel, now) - || isRemotelyClosed(idleChannel.channel)) { + || !Channels.isChannelValid(idleChannel.channel)) { LOGGER.debug("Adding Candidate expired Channel {}", idleChannel.channel); if (idleTimeoutChannels == null) idleTimeoutChannels = new ArrayList(); @@ -263,7 +258,7 @@ public Channel poll(String poolKey) { if (idleChannel == null) // pool is empty break; - else if (isRemotelyClosed(idleChannel.channel)) { + else if (!Channels.isChannelValid(idleChannel.channel)) { idleChannel = null; LOGGER.trace("Channel not connected or not opened, probably remotely closed!"); } diff --git a/src/main/java/com/ning/http/client/providers/netty/future/NettyResponseFuture.java b/src/main/java/com/ning/http/client/providers/netty/future/NettyResponseFuture.java index 49d27f4e41..818fd5d5d6 100755 --- a/src/main/java/com/ning/http/client/providers/netty/future/NettyResponseFuture.java +++ b/src/main/java/com/ning/http/client/providers/netty/future/NettyResponseFuture.java @@ -1,25 +1,22 @@ /* - * Copyright 2010 Ning, Inc. + * Copyright (c) 2014 AsyncHttpClient Project. All rights reserved. * - * 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: + * 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. * - * 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. + * 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.providers.netty.future; import static com.ning.http.util.DateUtils.millisTime; import org.jboss.netty.channel.Channel; -import org.jboss.netty.handler.codec.http.HttpRequest; -import org.jboss.netty.handler.codec.http.HttpResponse; +import org.jboss.netty.handler.codec.http.HttpHeaders; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -29,6 +26,7 @@ import com.ning.http.client.Request; import com.ning.http.client.listenable.AbstractListenableFuture; import com.ning.http.client.providers.netty.channel.Channels; +import com.ning.http.client.providers.netty.request.NettyRequest; import com.ning.http.client.providers.netty.request.timeout.TimeoutsHolder; import com.ning.http.client.uri.UriComponents; @@ -56,41 +54,49 @@ public final class NettyResponseFuture extends AbstractListenableFuture { public enum STATE { NEW, POOLED, RECONNECTED, CLOSED, } - + + private volatile boolean requestTimeoutReached; + private volatile boolean idleConnectionTimeoutReached; + private final long start = millisTime(); + private final ConnectionPoolKeyStrategy connectionPoolKeyStrategy; + private final ProxyServer proxyServer; + private final int maxRetry; private final CountDownLatch latch = new CountDownLatch(1); + + // state mutated from outside the event loop + // TODO check if they are indeed mutated outside the event loop private final AtomicBoolean isDone = new AtomicBoolean(false); private final AtomicBoolean isCancelled = new AtomicBoolean(false); - private AsyncHandler asyncHandler; - private Request request; - private HttpRequest nettyRequest; - private final AtomicReference content = new AtomicReference(); - private UriComponents uri; - private boolean keepAlive = true; - private HttpResponse httpResponse; - private final AtomicReference exEx = new AtomicReference(); private final AtomicInteger redirectCount = new AtomicInteger(); - private volatile TimeoutsHolder timeoutsHolder; private final AtomicBoolean inAuth = new AtomicBoolean(false); private final AtomicBoolean statusReceived = new AtomicBoolean(false); private final AtomicLong touch = new AtomicLong(millisTime()); - private final long start = millisTime(); private final AtomicReference state = new AtomicReference(STATE.NEW); private final AtomicBoolean contentProcessed = new AtomicBoolean(false); - private Channel channel; - private boolean reuseChannel = false; private final AtomicInteger currentRetry = new AtomicInteger(0); - private final int maxRetry; - private boolean writeHeaders; - private boolean writeBody; private final AtomicBoolean onThrowableCalled = new AtomicBoolean(false); - private boolean allowConnect = false; - private final ConnectionPoolKeyStrategy connectionPoolKeyStrategy; - private final ProxyServer proxyServer; + private final AtomicReference content = new AtomicReference(); + private final AtomicReference exEx = new AtomicReference(); + private volatile TimeoutsHolder timeoutsHolder; + + // state mutated only inside the event loop + private Channel channel; + private UriComponents uri; + private boolean keepAlive = true; + private Request request; + private NettyRequest nettyRequest; + private HttpHeaders httpHeaders; + private AsyncHandler asyncHandler; + private boolean streamWasAlreadyConsumed; + private boolean reuseChannel; + private boolean headersAlreadyWrittenOnContinue; + private boolean dontWriteBodyBecauseExpectContinue; + private boolean allowConnect; public NettyResponseFuture(UriComponents uri,// Request request,// AsyncHandler asyncHandler,// - HttpRequest nettyRequest,// + NettyRequest nettyRequest,// int maxRetry,// ConnectionPoolKeyStrategy connectionPoolKeyStrategy,// ProxyServer proxyServer) { @@ -102,8 +108,6 @@ public NettyResponseFuture(UriComponents uri,// this.connectionPoolKeyStrategy = connectionPoolKeyStrategy; this.proxyServer = proxyServer; this.maxRetry = maxRetry; - writeHeaders = true; - writeBody = true; } /*********************************************/ @@ -122,7 +126,6 @@ public boolean isCancelled() { @Override public boolean cancel(boolean force) { - cancelTimeouts(); if (isCancelled.getAndSet(true)) @@ -131,18 +134,16 @@ public boolean cancel(boolean force) { try { Channels.setDiscard(channel); channel.close(); - } catch (Exception t) { + } catch (Throwable t) { // Ignore } - - if (!onThrowableCalled.getAndSet(true)) + if (!onThrowableCalled.getAndSet(true)) { try { - // FIXME should we set the future exception once and for all asyncHandler.onThrowable(new CancellationException()); - } catch (Exception t) { - // Ignore + } catch (Throwable t) { + LOGGER.warn("cancel", t); } - + } latch.countDown(); runListeners(); return true; @@ -161,7 +162,7 @@ public V get(long l, TimeUnit tu) throws InterruptedException, TimeoutException, return getContent(); } - V getContent() throws ExecutionException { + private V getContent() throws ExecutionException { ExecutionException e = exEx.get(); if (e != null) @@ -193,9 +194,9 @@ V getContent() throws ExecutionException { } /*********************************************/ - /** com.ning.http.clientListenableFuture **/ + /** org.asynchttpclient.ListenableFuture **/ /*********************************************/ - @Override + public final void done() { cancelTimeouts(); @@ -219,7 +220,6 @@ public final void done() { runListeners(); } - @Override public final void abort(final Throwable t) { cancelTimeouts(); @@ -227,7 +227,6 @@ public final void abort(final Throwable t) { if (isDone.get() || isCancelled.getAndSet(true)) return; - isCancelled.set(true); exEx.compareAndSet(null, new ExecutionException(t)); if (onThrowableCalled.compareAndSet(false, true)) { try { @@ -240,38 +239,15 @@ public final void abort(final Throwable t) { runListeners(); } - @Override - public void content(V v) { - content.set(v); - } - @Override public void touch() { touch.set(millisTime()); } - public long getLastTouch() { - return touch.get(); - } - - @Override - public boolean getAndSetWriteHeaders(boolean writeHeaders) { - boolean b = this.writeHeaders; - this.writeHeaders = writeHeaders; - return b; - } - - @Override - public boolean getAndSetWriteBody(boolean writeBody) { - boolean b = this.writeBody; - this.writeBody = writeBody; - return b; - } - /*********************************************/ /** INTERNAL **/ /*********************************************/ - + public UriComponents getURI() { return uri; } @@ -292,8 +268,29 @@ public void setAsyncHandler(AsyncHandler asyncHandler) { this.asyncHandler = asyncHandler; } - public void setTimeoutsHolder(TimeoutsHolder timeoutsHolder) { - this.timeoutsHolder = timeoutsHolder; + /** + * Is the Future still valid + * + * @return true if response has expired and should be terminated. + */ + public boolean hasExpired() { + return requestTimeoutReached || idleConnectionTimeoutReached; + } + + public void setRequestTimeoutReached() { + this.requestTimeoutReached = true; + } + + public boolean isRequestTimeoutReached() { + return requestTimeoutReached; + } + + public void setIdleConnectionTimeoutReached() { + this.idleConnectionTimeoutReached = true; + } + + public boolean isIdleConnectionTimeoutReached() { + return idleConnectionTimeoutReached; } public void cancelTimeouts() { @@ -307,11 +304,11 @@ public final Request getRequest() { return request; } - public final HttpRequest getNettyRequest() { + public final NettyRequest getNettyRequest() { return nettyRequest; } - public final void setNettyRequest(HttpRequest nettyRequest) { + public final void setNettyRequest(NettyRequest nettyRequest) { this.nettyRequest = nettyRequest; } @@ -327,18 +324,22 @@ public final void setKeepAlive(final boolean keepAlive) { this.keepAlive = keepAlive; } - public final HttpResponse getHttpResponse() { - return httpResponse; + public final HttpHeaders getHttpHeaders() { + return httpHeaders; } - public final void setHttpResponse(final HttpResponse httpResponse) { - this.httpResponse = httpResponse; + public final void setHttpHeaders(HttpHeaders httpHeaders) { + this.httpHeaders = httpHeaders; } public int incrementAndGetCurrentRedirectCount() { return redirectCount.incrementAndGet(); } + public void setTimeoutsHolder(TimeoutsHolder timeoutsHolder) { + this.timeoutsHolder = timeoutsHolder; + } + public boolean isInAuth() { return inAuth.get(); } @@ -358,7 +359,35 @@ public void setState(STATE state) { public boolean getAndSetStatusReceived(boolean sr) { return statusReceived.getAndSet(sr); } - + + public boolean isStreamWasAlreadyConsumed() { + return streamWasAlreadyConsumed; + } + + public void setStreamWasAlreadyConsumed(boolean streamWasAlreadyConsumed) { + this.streamWasAlreadyConsumed = streamWasAlreadyConsumed; + } + + public long getLastTouch() { + return touch.get(); + } + + public void setHeadersAlreadyWrittenOnContinue(boolean headersAlreadyWrittenOnContinue) { + this.headersAlreadyWrittenOnContinue = headersAlreadyWrittenOnContinue; + } + + public boolean isHeadersAlreadyWrittenOnContinue() { + return headersAlreadyWrittenOnContinue; + } + + public void setDontWriteBodyBecauseExpectContinue(boolean dontWriteBodyBecauseExpectContinue) { + this.dontWriteBodyBecauseExpectContinue = dontWriteBodyBecauseExpectContinue; + } + + public boolean isDontWriteBodyBecauseExpectContinue() { + return dontWriteBodyBecauseExpectContinue; + } + public void attachChannel(Channel channel) { this.channel = channel; } @@ -404,13 +433,14 @@ 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} can 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 canBeReplay() { - return !isDone() && canRetry() && !(channel != null && channel.isOpen() && uri.getScheme().compareToIgnoreCase("https") != 0) - && !isInAuth(); + public boolean canBeReplayed() { + return !isDone() && canRetry() + && !(Channels.isChannelValid(channel) && !uri.getScheme().equalsIgnoreCase("https")) && !isInAuth(); } public long getStart() { @@ -428,7 +458,7 @@ public String toString() { ",\n\tcontent=" + content + // ",\n\turi=" + uri + // ",\n\tkeepAlive=" + keepAlive + // - ",\n\thttpResponse=" + httpResponse + // + ",\n\thttpHeaders=" + httpHeaders + // ",\n\texEx=" + exEx + // ",\n\tredirectCount=" + redirectCount + // ",\n\ttimeoutsHolder=" + timeoutsHolder + // diff --git a/src/main/java/com/ning/http/client/providers/netty/handler/HttpProtocol.java b/src/main/java/com/ning/http/client/providers/netty/handler/HttpProtocol.java index 160d007a21..7c8b5bcfe6 100644 --- a/src/main/java/com/ning/http/client/providers/netty/handler/HttpProtocol.java +++ b/src/main/java/com/ning/http/client/providers/netty/handler/HttpProtocol.java @@ -1,38 +1,46 @@ +/* + * Copyright (c) 2014 AsyncHttpClient Project. 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.providers.netty.handler; +import static com.ning.http.client.providers.netty.util.HttpUtils.isNTLM; +import static com.ning.http.util.AsyncHttpProviderUtils.getDefaultPort; import static com.ning.http.util.MiscUtils.isNonEmpty; +import static org.jboss.netty.handler.codec.http.HttpResponseStatus.CONTINUE; +import static org.jboss.netty.handler.codec.http.HttpResponseStatus.OK; +import static org.jboss.netty.handler.codec.http.HttpResponseStatus.PROXY_AUTHENTICATION_REQUIRED; +import static org.jboss.netty.handler.codec.http.HttpResponseStatus.UNAUTHORIZED; import org.jboss.netty.channel.Channel; -import org.jboss.netty.channel.ChannelStateEvent; -import org.jboss.netty.channel.ExceptionEvent; -import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.handler.codec.http.HttpChunk; import org.jboss.netty.handler.codec.http.HttpChunkTrailer; import org.jboss.netty.handler.codec.http.HttpHeaders; import org.jboss.netty.handler.codec.http.HttpMethod; 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.AsyncHandler.STATE; import com.ning.http.client.AsyncHttpClientConfig; 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.ProxyServer; import com.ning.http.client.Realm; import com.ning.http.client.Request; import com.ning.http.client.RequestBuilder; -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.ntlm.NTLMEngine; import com.ning.http.client.ntlm.NTLMEngineException; import com.ning.http.client.providers.netty.Callback; +import com.ning.http.client.providers.netty.NettyAsyncHttpProviderConfig; import com.ning.http.client.providers.netty.channel.ChannelManager; import com.ning.http.client.providers.netty.channel.Channels; import com.ning.http.client.providers.netty.future.NettyResponseFuture; @@ -41,42 +49,20 @@ import com.ning.http.client.providers.netty.response.ResponseHeaders; import com.ning.http.client.providers.netty.response.ResponseStatus; import com.ning.http.client.providers.netty.spnego.SpnegoEngine; -import com.ning.http.client.providers.netty.util.HttpUtil; import com.ning.http.client.uri.UriComponents; -import com.ning.http.util.AsyncHttpProviderUtils; import java.io.IOException; -import java.net.MalformedURLException; import java.util.List; -public class HttpProtocol extends Protocol { +public final class HttpProtocol extends Protocol { - private static final Logger LOGGER = LoggerFactory.getLogger(HttpProtocol.class); - - private final Processor webSocketProcessor; - - public HttpProtocol(ChannelManager channelManager, AsyncHttpClientConfig config, NettyRequestSender nettyRequestSender, Processor webSocketProcessor) { - super(channelManager, config, nettyRequestSender); - this.webSocketProcessor = webSocketProcessor; - } - - private void markAsDone(final NettyResponseFuture future, final Channel channel) throws MalformedURLException { - // We need to make sure everything is OK before adding the connection back to the pool. - try { - future.done(); - } catch (Throwable t) { - // Never propagate exception once we know we are done. - LOGGER.debug(t.getMessage(), t); - } - - if (!future.isKeepAlive() || !channel.isReadable()) { - channelManager.closeChannel(channel); - } + public HttpProtocol(ChannelManager channelManager, AsyncHttpClientConfig config, NettyAsyncHttpProviderConfig nettyConfig, + NettyRequestSender requestSender) { + super(channelManager, config, nettyConfig, requestSender); } - private final void configureKeepAlive(NettyResponseFuture future, HttpResponse response) { - String connectionHeader = response.headers().get(HttpHeaders.Names.CONNECTION); - future.setKeepAlive(connectionHeader == null || connectionHeader.equalsIgnoreCase(HttpHeaders.Values.KEEP_ALIVE)); + private Realm.RealmBuilder newRealmBuilder(Realm realm) { + return realm != null ? new Realm.RealmBuilder().clone(realm) : new Realm.RealmBuilder(); } private Realm kerberosChallenge(List proxyAuth, Request request, ProxyServer proxyServer, @@ -84,24 +70,24 @@ private Realm kerberosChallenge(List proxyAuth, Request request, ProxySe throws NTLMEngineException { UriComponents uri = request.getURI(); - String host = request.getVirtualHost() != null ? request.getVirtualHost() : uri.getHost(); + String host = request.getVirtualHost() == null ? uri.getHost() : request.getVirtualHost(); String server = proxyServer == null ? host : proxyServer.getHost(); try { String challengeHeader = SpnegoEngine.INSTANCE.generateToken(server); headers.remove(HttpHeaders.Names.AUTHORIZATION); headers.add(HttpHeaders.Names.AUTHORIZATION, "Negotiate " + challengeHeader); - Realm.RealmBuilder realmBuilder; - if (realm != null) { - realmBuilder = new Realm.RealmBuilder().clone(realm); - } else { - realmBuilder = new Realm.RealmBuilder(); - } - return realmBuilder.setUri(uri).setMethodName(request.getMethod()).setScheme(Realm.AuthScheme.KERBEROS).build(); + return newRealmBuilder(realm)// + .setUri(uri)// + .setMethodName(request.getMethod())// + .setScheme(Realm.AuthScheme.KERBEROS)// + .build(); + } catch (Throwable throwable) { - if (HttpUtil.isNTLM(proxyAuth)) + if (isNTLM(proxyAuth)) { return ntlmChallenge(proxyAuth, request, proxyServer, headers, realm, future, proxyInd); - nettyRequestSender.abort(future, throwable); + } + requestSender.abort(future, throwable); return null; } } @@ -110,26 +96,14 @@ private String authorizationHeaderName(boolean proxyInd) { return proxyInd ? HttpHeaders.Names.PROXY_AUTHORIZATION : HttpHeaders.Names.AUTHORIZATION; } - private void addNTLMAuthorization(FluentCaseInsensitiveStringsMap headers, String challengeHeader, boolean proxyInd) { + private void addNTLMAuthorizationHeader(FluentCaseInsensitiveStringsMap headers, String challengeHeader, boolean proxyInd) { headers.add(authorizationHeaderName(proxyInd), "NTLM " + challengeHeader); } - private void addType3NTLMAuthorizationHeader(List auth, FluentCaseInsensitiveStringsMap headers, String username, - String password, String domain, String workstation, boolean proxyInd) throws NTLMEngineException { - headers.remove(authorizationHeaderName(proxyInd)); - - // Beware of space!, see #462 - if (isNonEmpty(auth) && auth.get(0).startsWith("NTLM ")) { - String serverChallenge = auth.get(0).trim().substring("NTLM ".length()); - String challengeHeader = NTLMEngine.INSTANCE.generateType3Msg(username, password, domain, workstation, serverChallenge); - addNTLMAuthorization(headers, challengeHeader, proxyInd); - } - } - private Realm ntlmChallenge(List wwwAuth, Request request, ProxyServer proxyServer, FluentCaseInsensitiveStringsMap headers, Realm realm, NettyResponseFuture future, boolean proxyInd) throws NTLMEngineException { - boolean useRealm = (proxyServer == null && realm != null); + boolean useRealm = proxyServer == null && realm != null; String ntlmDomain = useRealm ? realm.getNtlmDomain() : proxyServer.getNtlmDomain(); String ntlmHost = useRealm ? realm.getNtlmHost() : proxyServer.getHost(); @@ -137,359 +111,336 @@ private Realm ntlmChallenge(List wwwAuth, Request request, ProxyServer p String password = useRealm ? realm.getPassword() : proxyServer.getPassword(); UriComponents uri = request.getURI(); - Realm.RealmBuilder realmBuilder; if (realm != null && !realm.isNtlmMessageType2Received()) { String challengeHeader = NTLMEngine.INSTANCE.generateType1Msg(ntlmDomain, ntlmHost); - addNTLMAuthorization(headers, challengeHeader, proxyInd); - realmBuilder = new Realm.RealmBuilder().clone(realm).setScheme(realm.getAuthScheme()).setNtlmMessageType2Received(true); + + addNTLMAuthorizationHeader(headers, challengeHeader, proxyInd); future.getAndSetAuth(false); + return newRealmBuilder(realm)// + .setScheme(realm.getAuthScheme())// + .setUri(uri)// + .setMethodName(request.getMethod())// + .setNtlmMessageType2Received(true)// + .build(); + } else { addType3NTLMAuthorizationHeader(wwwAuth, headers, principal, password, ntlmDomain, ntlmHost, proxyInd); - - if (realm != null) { - realmBuilder = new Realm.RealmBuilder().clone(realm).setScheme(realm.getAuthScheme()); - } else { - realmBuilder = new Realm.RealmBuilder().setScheme(Realm.AuthScheme.NTLM); - } + Realm.AuthScheme authScheme = realm != null ? realm.getAuthScheme() : Realm.AuthScheme.NTLM; + return newRealmBuilder(realm)// + .setScheme(authScheme)// + .setUri(uri)// + .setMethodName(request.getMethod())// + .build(); } - - return realmBuilder.setUri(uri).setMethodName(request.getMethod()).build(); } private Realm ntlmProxyChallenge(List wwwAuth, Request request, ProxyServer proxyServer, - FluentCaseInsensitiveStringsMap headers, Realm realm, NettyResponseFuture future) throws NTLMEngineException { + FluentCaseInsensitiveStringsMap headers, Realm realm, NettyResponseFuture future, boolean proxyInd) + throws NTLMEngineException { future.getAndSetAuth(false); + headers.remove(HttpHeaders.Names.PROXY_AUTHORIZATION); addType3NTLMAuthorizationHeader(wwwAuth, headers, proxyServer.getPrincipal(), proxyServer.getPassword(), - proxyServer.getNtlmDomain(), proxyServer.getHost(), true); + proxyServer.getNtlmDomain(), proxyServer.getHost(), proxyInd); - Realm.RealmBuilder realmBuilder = new Realm.RealmBuilder(); - if (realm != null) { - realmBuilder = realmBuilder.clone(realm); + return newRealmBuilder(realm)// + // .setScheme(realm.getAuthScheme()) + .setUri(request.getURI())// + .setMethodName(request.getMethod()).build(); + } + + private void addType3NTLMAuthorizationHeader(List auth, FluentCaseInsensitiveStringsMap headers, String username, + String password, String domain, String workstation, boolean proxyInd) throws NTLMEngineException { + headers.remove(authorizationHeaderName(proxyInd)); + + if (isNonEmpty(auth) && auth.get(0).startsWith("NTLM ")) { + String serverChallenge = auth.get(0).trim().substring("NTLM ".length()); + String challengeHeader = NTLMEngine.INSTANCE.generateType3Msg(username, password, domain, workstation, serverChallenge); + addNTLMAuthorizationHeader(headers, challengeHeader, proxyInd); } - return realmBuilder.setUri(request.getURI()).setMethodName(request.getMethod()).build(); } - private final boolean exitAfterProcessingFilters(Channel channel, NettyResponseFuture future, HttpResponse response, - AsyncHandler handler, Request request, HttpResponseStatus status, HttpResponseHeaders responseHeaders) throws IOException { - if (!config.getResponseFilters().isEmpty()) { - FilterContext fc = new FilterContext.FilterContextBuilder().asyncHandler(handler).request(request).responseStatus(status) - .responseHeaders(responseHeaders).build(); - - for (ResponseFilter asyncFilter : config.getResponseFilters()) { - try { - fc = asyncFilter.filter(fc); - if (fc == null) { - throw new NullPointerException("FilterContext is null"); - } - } catch (FilterException efe) { - nettyRequestSender.abort(future, efe); - } - } + private void finishUpdate(final NettyResponseFuture future, Channel channel, boolean expectOtherChunks) throws IOException { - // The handler may have been wrapped. - future.setAsyncHandler(fc.getAsyncHandler()); + boolean keepAlive = future.isKeepAlive(); + if (expectOtherChunks && keepAlive) + channelManager.drainChannel(channel, future); + else + channelManager.tryToOfferChannelToPool(channel, keepAlive, channelManager.getPoolKey(future)); + markAsDone(future, channel); + } - // The request has changed - if (fc.replayRequest()) { - replayRequest(future, fc, channel); - return true; - } + private boolean updateBodyAndInterrupt(NettyResponseFuture future, AsyncHandler handler, ResponseBodyPart bodyPart) + throws Exception { + boolean interrupt = handler.onBodyPartReceived(bodyPart) != STATE.CONTINUE; + if (bodyPart.isUnderlyingConnectionToBeClosed()) + future.setKeepAlive(false); + return interrupt; + } + + private void markAsDone(NettyResponseFuture future, final Channel channel) { + // We need to make sure everything is OK before adding the + // connection back to the pool. + try { + future.done(); + } catch (Throwable t) { + // Never propagate exception once we know we are done. + logger.debug(t.getMessage(), t); + } + + if (!future.isKeepAlive() || !channel.isConnected()) { + channelManager.closeChannel(channel); } - return false; } - private final boolean exitAfterHandling401(// + private boolean exitAfterHandling401(// final Channel channel,// final NettyResponseFuture future,// HttpResponse response,// - Request request,// + final Request request,// int statusCode,// Realm realm,// - ProxyServer proxyServer,// - final RequestBuilder requestBuilder) throws Exception { + ProxyServer proxyServer) throws Exception { - if (statusCode == 401 && realm != null && !future.getAndSetAuth(true)) { + if (statusCode == UNAUTHORIZED.getCode() && realm != null && !future.getAndSetAuth(true)) { - List wwwAuthHeaders = HttpUtil.getNettyHeaderValuesByCaseInsensitiveName(response.headers(), - HttpHeaders.Names.WWW_AUTHENTICATE); + List wwwAuthHeaders = response.headers().getAll(HttpHeaders.Names.WWW_AUTHENTICATE); if (!wwwAuthHeaders.isEmpty()) { future.setState(NettyResponseFuture.STATE.NEW); Realm newRealm = null; - FluentCaseInsensitiveStringsMap requestHeaders = request.getHeaders(); - if (!wwwAuthHeaders.contains("Kerberos") && (HttpUtil.isNTLM(wwwAuthHeaders) || (wwwAuthHeaders.contains("Negotiate")))) { + boolean negociate = wwwAuthHeaders.contains("Negotiate"); + if (!wwwAuthHeaders.contains("Kerberos") && (isNTLM(wwwAuthHeaders) || negociate)) { // NTLM newRealm = ntlmChallenge(wwwAuthHeaders, request, proxyServer, requestHeaders, realm, future, false); - } else if (wwwAuthHeaders.contains("Negotiate")) { + } else if (negociate) { // SPNEGO KERBEROS newRealm = kerberosChallenge(wwwAuthHeaders, request, proxyServer, requestHeaders, realm, future, false); if (newRealm == null) return true; + } else { - newRealm = new Realm.RealmBuilder().clone(realm) // - .setScheme(realm.getAuthScheme()) // - .setUri(request.getURI()) // - .setMethodName(request.getMethod()) // - .setUsePreemptiveAuth(true) // + newRealm = new Realm.RealmBuilder()// + .clone(realm)// + .setScheme(realm.getAuthScheme())// + .setUri(request.getURI())// + .setMethodName(request.getMethod())// + .setUsePreemptiveAuth(true)// .parseWWWAuthenticateHeader(wwwAuthHeaders.get(0))// .build(); } - final Realm nr = newRealm; + Realm nr = newRealm; + final Request nextRequest = new RequestBuilder(future.getRequest()).setHeaders(requestHeaders).setRealm(nr).build(); - LOGGER.debug("Sending authentication to {}", request.getURI()); - final Request nextRequest = requestBuilder.setHeaders(requestHeaders).setRealm(nr).build(); - Callback ac = new Callback(future) { + logger.debug("Sending authentication to {}", request.getURI()); + Callback callback = new Callback(future) { public void call() throws Exception { - // not waiting for the channel to be drained, so we might ended up pooling the initial channel and creating a new one - nettyRequestSender.drainChannel(channel, future); - nettyRequestSender.nextRequest(nextRequest, future); + channelManager.drainChannel(channel, future); + requestSender.sendNextRequest(nextRequest, future); } }; - if (future.isKeepAlive() && response.isChunked()) - // we must make sure there is no chunk left before executing the next request - Channels.setAttachment(channel, ac); + if (future.isKeepAlive() && HttpHeaders.isTransferEncodingChunked(response)) + // We must make sure there is no bytes left + // before executing the next request. + Channels.setAttachment(channel, callback); else - // FIXME couldn't we reuse the channel right now? - ac.call(); + callback.call(); + return true; } } + + return false; + } + + private boolean exitAfterHandling100(final Channel channel, final NettyResponseFuture future, int statusCode) { + if (statusCode == CONTINUE.getCode()) { + future.setHeadersAlreadyWrittenOnContinue(true); + future.setDontWriteBodyBecauseExpectContinue(false); + // FIXME why not reuse the channel? + requestSender.writeRequest(future, channel); + return true; + + } return false; } - private final boolean exitAfterHandling407(// + private boolean exitAfterHandling407(// NettyResponseFuture future,// HttpResponse response,// Request request,// int statusCode,// Realm realm,// - ProxyServer proxyServer,// - final RequestBuilder requestBuilder) throws Exception { + ProxyServer proxyServer) throws Exception { + + if (statusCode == PROXY_AUTHENTICATION_REQUIRED.getCode() && realm != null && !future.getAndSetAuth(true)) { + + List proxyAuthHeaders = response.headers().getAll(HttpHeaders.Names.PROXY_AUTHENTICATE); - if (statusCode == 407 && realm != null && !future.getAndSetAuth(true)) { - List proxyAuth = HttpUtil.getNettyHeaderValuesByCaseInsensitiveName(response.headers(), - HttpHeaders.Names.PROXY_AUTHENTICATE); - if (!proxyAuth.isEmpty()) { - LOGGER.debug("Sending proxy authentication to {}", request.getURI()); + if (!proxyAuthHeaders.isEmpty()) { + logger.debug("Sending proxy authentication to {}", request.getURI()); future.setState(NettyResponseFuture.STATE.NEW); Realm newRealm = null; FluentCaseInsensitiveStringsMap requestHeaders = request.getHeaders(); - if (!proxyAuth.contains("Kerberos") && (HttpUtil.isNTLM(proxyAuth) || (proxyAuth.contains("Negotiate")))) { - newRealm = ntlmProxyChallenge(proxyAuth, request, proxyServer, requestHeaders, realm, future); + boolean negociate = proxyAuthHeaders.contains("Negotiate"); + if (!proxyAuthHeaders.contains("Kerberos") && (isNTLM(proxyAuthHeaders) || negociate)) { + newRealm = ntlmProxyChallenge(proxyAuthHeaders, request, proxyServer, requestHeaders, realm, future, true); // SPNEGO KERBEROS - } else if (proxyAuth.contains("Negotiate")) { - newRealm = kerberosChallenge(proxyAuth, request, proxyServer, requestHeaders, realm, future, true); + } else if (negociate) { + newRealm = kerberosChallenge(proxyAuthHeaders, request, proxyServer, requestHeaders, realm, future, true); if (newRealm == null) return true; } else { newRealm = new Realm.RealmBuilder().clone(realm)// .setScheme(realm.getAuthScheme())// .setUri(request.getURI())// - .setMethodName("CONNECT")// - .setTargetProxy(true)// + .setOmitQuery(true)// + .setMethodName(HttpMethod.CONNECT.getName())// .setUsePreemptiveAuth(true)// - .parseProxyAuthenticateHeader(proxyAuth.get(0))// + .parseProxyAuthenticateHeader(proxyAuthHeaders.get(0))// .build(); } - Request req = requestBuilder.setHeaders(requestHeaders).setRealm(newRealm).build(); future.setReuseChannel(true); future.setConnectAllowed(true); - nettyRequestSender.nextRequest(req, future); + Request nextRequest = new RequestBuilder(future.getRequest()).setHeaders(requestHeaders).setRealm(newRealm).build(); + requestSender.sendNextRequest(nextRequest, future); return true; } } return false; } - private boolean exitAfterHandling100(Channel channel, NettyResponseFuture future, int statusCode) { - if (statusCode == 100) { - future.getAndSetWriteHeaders(false); - future.getAndSetWriteBody(true); - nettyRequestSender.writeRequest(channel, config, future); - return true; - } - return false; - } - - private boolean exitAfterHandlingConnect(Channel channel,// - NettyResponseFuture future,// - Request request,// + private boolean exitAfterHandlingConnect(// + final Channel channel,// + final NettyResponseFuture future,// + final Request request,// ProxyServer proxyServer,// int statusCode,// - RequestBuilder requestBuilder,// - HttpRequest nettyRequest) throws IOException { + HttpRequest httpRequest) throws IOException { - if (nettyRequest.getMethod().equals(HttpMethod.CONNECT) && statusCode == 200) { + if (statusCode == OK.getCode() && httpRequest.getMethod() == HttpMethod.CONNECT) { - LOGGER.debug("Connected to {}:{}", proxyServer.getHost(), proxyServer.getPort()); - - if (future.isKeepAlive()) { + if (future.isKeepAlive()) future.attachChannel(channel, true); - } try { UriComponents requestURI = request.getURI(); String scheme = requestURI.getScheme(); String host = requestURI.getHost(); - int port = AsyncHttpProviderUtils.getDefaultPort(requestURI); + int port = getDefaultPort(requestURI); - LOGGER.debug("Connecting to proxy {} for scheme {}", proxyServer, scheme); - channelManager.upgradeProtocol(channel.getPipeline(), scheme, host, port, webSocketProcessor); + logger.debug("Connecting to proxy {} for scheme {}", proxyServer, scheme); + channelManager.upgradeProtocol(channel.getPipeline(), scheme, host, port); } catch (Throwable ex) { - nettyRequestSender.abort(future, ex); + requestSender.abort(future, ex); } - Request req = requestBuilder.build(); + future.setReuseChannel(true); future.setConnectAllowed(false); - nettyRequestSender.nextRequest(req, future); + requestSender.sendNextRequest(new RequestBuilder(future.getRequest()).build(), future); return true; } - return false; - } - private final boolean updateStatusAndInterrupt(AsyncHandler handler, HttpResponseStatus c) throws Exception { - return handler.onStatusReceived(c) != STATE.CONTINUE; - } - - private final boolean updateHeadersAndInterrupt(AsyncHandler handler, HttpResponseHeaders c) throws Exception { - return handler.onHeadersReceived(c) != STATE.CONTINUE; - } - - private final boolean updateBodyAndInterrupt(final NettyResponseFuture future, AsyncHandler handler, HttpResponseBodyPart c) - throws Exception { - boolean state = handler.onBodyPartReceived(c) != STATE.CONTINUE; - if (c.isUnderlyingConnectionToBeClosed()) - future.setKeepAlive(false); - return state; + return false; } - private final boolean exitAfterHandlingStatus(Channel channel, NettyResponseFuture future, HttpResponse response, - AsyncHandler handler, HttpResponseStatus status) throws IOException, Exception { - if (!future.getAndSetStatusReceived(true) && updateStatusAndInterrupt(handler, status)) { - finishUpdate(future, channel, response.isChunked()); + private boolean exitAfterHandlingStatus(Channel channel, NettyResponseFuture future, HttpResponse response, + AsyncHandler handler, ResponseStatus status) throws IOException, Exception { + if (!future.getAndSetStatusReceived(true) && handler.onStatusReceived(status) != STATE.CONTINUE) { + finishUpdate(future, channel, HttpHeaders.isTransferEncodingChunked(response)); return true; } return false; } - private final boolean exitAfterHandlingHeaders(Channel channel, NettyResponseFuture future, HttpResponse response, - AsyncHandler handler, HttpResponseHeaders responseHeaders) throws IOException, Exception { - if (!response.headers().isEmpty() && updateHeadersAndInterrupt(handler, responseHeaders)) { - finishUpdate(future, channel, response.isChunked()); + private boolean exitAfterHandlingHeaders(Channel channel, NettyResponseFuture future, HttpResponse response, + AsyncHandler handler, ResponseHeaders responseHeaders) throws IOException, Exception { + if (!response.headers().isEmpty() && handler.onHeadersReceived(responseHeaders) != STATE.CONTINUE) { + finishUpdate(future, channel, HttpHeaders.isTransferEncodingChunked(response)); return true; } return false; } - private final boolean exitAfterHandlingBody(Channel channel, NettyResponseFuture future, HttpResponse response, + // Netty 3: if the response is not chunked, the full body comes with the response + private boolean exitAfterHandlingBody(Channel channel, NettyResponseFuture future, HttpResponse response, AsyncHandler handler) throws Exception { if (!response.isChunked()) { - updateBodyAndInterrupt(future, handler, new ResponseBodyPart(response, null, true)); + // no chunks expected, exiting + if (response.getContent().readableBytes() > 0) + // FIXME no need to notify an empty bodypart? + updateBodyAndInterrupt(future, handler, new ResponseBodyPart(response, null, true)); finishUpdate(future, channel, false); return true; } return false; } - private final boolean exitAfterHandlingHead(Channel channel, NettyResponseFuture future, HttpResponse response, - AsyncHandler handler, HttpRequest nettyRequest) throws Exception { - if (nettyRequest.getMethod().equals(HttpMethod.HEAD)) { - updateBodyAndInterrupt(future, handler, new ResponseBodyPart(response, null, true)); - markAsDone(future, channel); - nettyRequestSender.drainChannel(channel, future); - } - return false; - } - - private final void handleHttpResponse(final HttpResponse response, final Channel channel, final NettyResponseFuture future, + private boolean handleHttpResponse(final HttpResponse response,// + final Channel channel,// + final NettyResponseFuture future,// AsyncHandler handler) throws Exception { - HttpRequest nettyRequest = future.getNettyRequest(); - Request request = future.getRequest(); + HttpRequest httpRequest = future.getNettyRequest().getHttpRequest(); ProxyServer proxyServer = future.getProxyServer(); - LOGGER.debug("\n\nRequest {}\n\nResponse {}\n", nettyRequest, response); - - // Required if there is some trailing headers. - future.setHttpResponse(response); - - configureKeepAlive(future, response); - - HttpResponseStatus status = new ResponseStatus(future.getURI(), config, response); - HttpResponseHeaders responseHeaders = new ResponseHeaders(response); - - if (exitAfterProcessingFilters(channel, future, response, handler, request, status, responseHeaders)) - return; + logger.debug("\n\nRequest {}\n\nResponse {}\n", httpRequest, response); - final RequestBuilder requestBuilder = new RequestBuilder(future.getRequest()); + // store the original headers so we can re-send all them to + // the handler in case of trailing headers + future.setHttpHeaders(response.headers()); - Realm realm = request.getRealm() != null ? request.getRealm() : config.getRealm(); + future.setKeepAlive(!HttpHeaders.Values.CLOSE.equalsIgnoreCase(response.headers().get(HttpHeaders.Names.CONNECTION))); + ResponseStatus status = new ResponseStatus(future.getURI(), config, response); int statusCode = response.getStatus().getCode(); + Request request = future.getRequest(); + Realm realm = request.getRealm() != null ? request.getRealm() : config.getRealm(); + ResponseHeaders responseHeaders = new ResponseHeaders(response.headers()); - // FIXME - if (exitAfterHandling401(channel, future, response, request, statusCode, realm, proxyServer, requestBuilder) || // - exitAfterHandling407(future, response, request, statusCode, realm, proxyServer, requestBuilder) || // + return exitAfterProcessingFilters(channel, future, handler, status, responseHeaders) + || exitAfterHandling401(channel, future, response, request, statusCode, realm, proxyServer) || // + exitAfterHandling407(future, response, request, statusCode, realm, proxyServer) || // exitAfterHandling100(channel, future, statusCode) || // - exitAfterHandlingRedirect(channel, future, request, response, statusCode) || // - exitAfterHandlingConnect(channel, future, request, proxyServer, statusCode, requestBuilder, nettyRequest) || // + exitAfterHandlingRedirect(channel, future, response, request, statusCode) || // + exitAfterHandlingConnect(channel, future, request, proxyServer, statusCode, httpRequest) || // exitAfterHandlingStatus(channel, future, response, handler, status) || // exitAfterHandlingHeaders(channel, future, response, handler, responseHeaders) || // - exitAfterHandlingBody(channel, future, response, handler) || // - exitAfterHandlingHead(channel, future, response, handler, nettyRequest)) { - return; - } + exitAfterHandlingBody(channel, future, response, handler); } - private final void handleChunk(final HttpChunk chunk, final Channel channel, final NettyResponseFuture future, - final AsyncHandler handler) throws Exception { + private void handleChunk(HttpChunk chunk,// + final Channel channel,// + final NettyResponseFuture future,// + AsyncHandler handler) throws IOException, Exception { + boolean last = chunk.isLast(); // we don't notify updateBodyAndInterrupt with the last chunk as it's empty if (last || updateBodyAndInterrupt(future, handler, new ResponseBodyPart(null, chunk, last))) { + // only possible if last is true if (chunk instanceof HttpChunkTrailer) { HttpChunkTrailer chunkTrailer = (HttpChunkTrailer) chunk; if (!chunkTrailer.trailingHeaders().isEmpty()) { - ResponseHeaders responseHeaders = new ResponseHeaders(future.getHttpResponse(), chunkTrailer); - updateHeadersAndInterrupt(handler, responseHeaders); + ResponseHeaders responseHeaders = new ResponseHeaders(future.getHttpHeaders(), chunkTrailer.trailingHeaders()); + handler.onHeadersReceived(responseHeaders); } } finishUpdate(future, channel, !chunk.isLast()); } } - private FilterContext handleIoException(FilterContext fc, NettyResponseFuture future) { - for (IOExceptionFilter asyncFilter : config.getIOExceptionFilters()) { - try { - fc = asyncFilter.filter(fc); - if (fc == null) { - throw new NullPointerException("FilterContext is null"); - } - } catch (FilterException efe) { - nettyRequestSender.abort(future, efe); - } - } - return fc; - } + @Override + public void handle(final Channel channel, final NettyResponseFuture future, final Object e) throws Exception { - private void finishUpdate(final NettyResponseFuture future, Channel channel, boolean expectOtherChunks) throws IOException { - boolean keepAlive = future.isKeepAlive(); - if (expectOtherChunks && keepAlive) - nettyRequestSender.drainChannel(channel, future); - else - channelManager.tryToOfferChannelToPool(channel, keepAlive, channelManager.getPoolKey(future)); - markAsDone(future, channel); - } - - public void handle(final Channel channel, final MessageEvent e, final NettyResponseFuture future) throws Exception { + future.touch(); // The connect timeout occurred. if (future.isDone()) { @@ -497,41 +448,35 @@ public void handle(final Channel channel, final MessageEvent e, final NettyRespo return; } - future.touch(); - AsyncHandler handler = future.getAsyncHandler(); - Object message = e.getMessage(); try { - if (message instanceof HttpResponse) - handleHttpResponse((HttpResponse) message, channel, future, handler); + if (e instanceof HttpResponse && handleHttpResponse((HttpResponse) e, channel, future, handler)) + return; - else if (message instanceof HttpChunk) - handleChunk((HttpChunk) message, channel, future, handler); + if (e instanceof HttpChunk) + handleChunk((HttpChunk) e, channel, future, handler); } catch (Exception t) { - if (t instanceof IOException && !config.getIOExceptionFilters().isEmpty()) { - FilterContext fc = new FilterContext.FilterContextBuilder().asyncHandler(handler).request(future.getRequest()) - .ioException(IOException.class.cast(t)).build(); - fc = handleIoException(fc, future); - - if (fc.replayRequest()) { - replayRequest(future, fc, channel); - return; - } + if (hasIOExceptionFilters// + && t instanceof IOException// + && requestSender.applyIoExceptionFiltersAndReplayRequest(future, IOException.class.cast(t), channel)) { + return; } try { - nettyRequestSender.abort(future, t); + requestSender.abort(future, t); + } catch (Exception abortException) { + logger.debug("Abort failed", abortException); } finally { finishUpdate(future, channel, false); - throw t; } + throw t; } } - public void onError(Channel channel, ExceptionEvent e) { + public void onError(Channel channel, Throwable e) { } - public void onClose(Channel channel, ChannelStateEvent e) { + public void onClose(Channel channel) { } } diff --git a/src/main/java/com/ning/http/client/providers/netty/handler/Processor.java b/src/main/java/com/ning/http/client/providers/netty/handler/Processor.java index 985d12a7bc..6d44b49393 100644 --- a/src/main/java/com/ning/http/client/providers/netty/handler/Processor.java +++ b/src/main/java/com/ning/http/client/providers/netty/handler/Processor.java @@ -1,17 +1,15 @@ /* - * Copyright 2010-2013 Ning, Inc. + * Copyright (c) 2014 AsyncHttpClient Project. All rights reserved. * - * 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: + * 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. * - * 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. + * 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.providers.netty.handler; @@ -27,9 +25,6 @@ import org.slf4j.LoggerFactory; import com.ning.http.client.AsyncHttpClientConfig; -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.providers.netty.Callback; import com.ning.http.client.providers.netty.DiscardEvent; import com.ning.http.client.providers.netty.channel.ChannelManager; @@ -54,13 +49,16 @@ public class Processor extends SimpleChannelUpstreamHandler { private final AsyncHttpClientConfig config; private final ChannelManager channelManager; - private final NettyRequestSender nettyRequestSender; + private final NettyRequestSender requestSender; private final Protocol protocol; - public Processor(AsyncHttpClientConfig config, ChannelManager channelManager, NettyRequestSender nettyRequestSender, Protocol protocol) { + public Processor(AsyncHttpClientConfig config,// + ChannelManager channelManager,// + NettyRequestSender requestSender,// + Protocol protocol) { this.config = config; this.channelManager = channelManager; - this.nettyRequestSender = nettyRequestSender; + this.requestSender = requestSender; this.protocol = protocol; } @@ -76,10 +74,7 @@ public void messageReceived(final ChannelHandlerContext ctx, MessageEvent e) thr if (attachment == null) LOGGER.debug("ChannelHandlerContext doesn't have any attachment"); - if (attachment == DiscardEvent.INSTANCE) { - // discard - - } else if (attachment instanceof Callback) { + if (attachment instanceof Callback) { Object message = e.getMessage(); Callback ac = (Callback) attachment; if (message instanceof HttpChunk) { @@ -88,14 +83,16 @@ public void messageReceived(final ChannelHandlerContext ctx, MessageEvent e) thr // process the AsyncCallable before passing the message to the protocol ac.call(); } else { + LOGGER.info("Received unexpected message while expecting a chunk: " + message); ac.call(); Channels.setDiscard(channel); } } else if (attachment instanceof NettyResponseFuture) { - protocol.handle(channel, e, NettyResponseFuture.class.cast(attachment)); + NettyResponseFuture future = (NettyResponseFuture) attachment; + protocol.handle(channel, future, e.getMessage()); - } else { + } else if (attachment != DiscardEvent.INSTANCE) { // unhandled message try { ctx.getChannel().close(); @@ -105,24 +102,10 @@ public void messageReceived(final ChannelHandlerContext ctx, MessageEvent e) thr } } - private FilterContext handleIoException(FilterContext fc, NettyResponseFuture future) { - for (IOExceptionFilter asyncFilter : config.getIOExceptionFilters()) { - try { - fc = asyncFilter.filter(fc); - if (fc == null) { - throw new NullPointerException("FilterContext is null"); - } - } catch (FilterException efe) { - nettyRequestSender.abort(future, efe); - } - } - return fc; - } - @Override public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { - if (nettyRequestSender.isClosed()) + if (requestSender.isClosed()) return; Channel channel = ctx.getChannel(); @@ -138,32 +121,25 @@ public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws LOGGER.debug("Channel Closed: {} with attachment {}", channel, attachment); if (attachment instanceof Callback) { - Callback ac = (Callback) attachment; - Channels.setAttachment(channel, ac.future()); - ac.call(); + Callback callback = (Callback) attachment; + Channels.setAttachment(channel, callback.future()); + callback.call(); } else if (attachment instanceof NettyResponseFuture) { NettyResponseFuture future = (NettyResponseFuture) attachment; future.touch(); - if (!config.getIOExceptionFilters().isEmpty()) { - FilterContext fc = new FilterContext.FilterContextBuilder().asyncHandler(future.getAsyncHandler()) - .request(future.getRequest()).ioException(CHANNEL_CLOSED_EXCEPTION).build(); - fc = handleIoException(fc, future); - - if (fc.replayRequest() && future.canBeReplay()) { - nettyRequestSender.replayRequest(future, fc, channel); - return; - } - } + if (!config.getIOExceptionFilters().isEmpty() + && requestSender.applyIoExceptionFiltersAndReplayRequest(future, CHANNEL_CLOSED_EXCEPTION, channel)) + return; - protocol.onClose(channel, e); + protocol.onClose(channel); if (future == null || future.isDone()) channelManager.closeChannel(channel); - else if (!nettyRequestSender.retry(ctx.getChannel(), future)) - nettyRequestSender.abort(future, REMOTELY_CLOSED_EXCEPTION); + else if (!requestSender.retry(future, ctx.getChannel())) + requestSender.abort(future, REMOTELY_CLOSED_EXCEPTION); } } @@ -173,16 +149,12 @@ public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Throwable cause = e.getCause(); NettyResponseFuture future = null; - if (e.getCause() instanceof PrematureChannelClosureException) + if (e.getCause() instanceof PrematureChannelClosureException || cause instanceof ClosedChannelException) return; LOGGER.debug("Unexpected I/O exception on channel {}", channel, cause); try { - if (cause instanceof ClosedChannelException) { - return; - } - Object attachment = Channels.getAttachment(channel); if (attachment instanceof NettyResponseFuture) { future = (NettyResponseFuture) attachment; @@ -191,24 +163,19 @@ public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws 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(); - fc = handleIoException(fc, future); - - if (fc.replayRequest()) { - nettyRequestSender.replayRequest(future, fc, channel); + // FIXME why drop the original exception and throw a new one? + if (!config.getIOExceptionFilters().isEmpty()) + if (requestSender.applyIoExceptionFiltersAndReplayRequest(future, CHANNEL_CLOSED_EXCEPTION, channel)) + return; + else { + // Close the channel so the recovering can occurs. + try { + channel.close(); + } catch (Throwable t) { + // Swallow. + } return; } - } else { - // Close the channel so the recovering can occurs. - try { - channel.close(); - } catch (Throwable t) { - // Swallow. - } - return; - } } if (StackTraceInspector.abortOnReadOrWriteException(cause)) { @@ -222,16 +189,15 @@ public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws cause = t; } - if (future != null) { + if (future != null) try { LOGGER.debug("Was unable to recover Future: {}", future); - nettyRequestSender.abort(future, cause); + requestSender.abort(future, cause); } catch (Throwable t) { LOGGER.error(t.getMessage(), t); } - } - protocol.onError(channel, e); + protocol.onError(channel, e.getCause()); channelManager.closeChannel(channel); ctx.sendUpstream(e); diff --git a/src/main/java/com/ning/http/client/providers/netty/handler/Protocol.java b/src/main/java/com/ning/http/client/providers/netty/handler/Protocol.java index 1c5a3193b4..c9bfe7c634 100644 --- a/src/main/java/com/ning/http/client/providers/netty/handler/Protocol.java +++ b/src/main/java/com/ning/http/client/providers/netty/handler/Protocol.java @@ -1,9 +1,10 @@ /* - * Copyright (c) 2010-2012 Sonatype, Inc. All rights reserved. + * Copyright (c) 2014 AsyncHttpClient Project. 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. + * 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 @@ -12,133 +13,188 @@ */ package com.ning.http.client.providers.netty.handler; -import static com.ning.http.util.MiscUtils.isNonEmpty; +import static com.ning.http.client.providers.netty.util.HttpUtils.HTTP; +import static com.ning.http.client.providers.netty.util.HttpUtils.WEBSOCKET; +import static com.ning.http.util.AsyncHttpProviderUtils.followRedirect; +import static org.jboss.netty.handler.codec.http.HttpResponseStatus.FOUND; +import static org.jboss.netty.handler.codec.http.HttpResponseStatus.MOVED_PERMANENTLY; +import static org.jboss.netty.handler.codec.http.HttpResponseStatus.SEE_OTHER; +import static org.jboss.netty.handler.codec.http.HttpResponseStatus.TEMPORARY_REDIRECT; import org.jboss.netty.channel.Channel; -import org.jboss.netty.channel.ChannelStateEvent; -import org.jboss.netty.channel.ExceptionEvent; -import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.handler.codec.http.HttpHeaders; import org.jboss.netty.handler.codec.http.HttpResponse; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.ning.http.client.AsyncHandlerExtensions; +import com.ning.http.client.AsyncHandler; import com.ning.http.client.AsyncHttpClientConfig; +import com.ning.http.client.HttpResponseHeaders; +import com.ning.http.client.HttpResponseStatus; import com.ning.http.client.MaxRedirectException; import com.ning.http.client.Request; import com.ning.http.client.RequestBuilder; +import com.ning.http.client.cookie.Cookie; import com.ning.http.client.cookie.CookieDecoder; +import com.ning.http.client.date.TimeConverter; import com.ning.http.client.filter.FilterContext; +import com.ning.http.client.filter.FilterException; +import com.ning.http.client.filter.ResponseFilter; import com.ning.http.client.providers.netty.Callback; +import com.ning.http.client.providers.netty.NettyAsyncHttpProviderConfig; import com.ning.http.client.providers.netty.channel.ChannelManager; import com.ning.http.client.providers.netty.channel.Channels; import com.ning.http.client.providers.netty.future.NettyResponseFuture; import com.ning.http.client.providers.netty.request.NettyRequestSender; -import com.ning.http.client.providers.netty.util.HttpUtil; import com.ning.http.client.uri.UriComponents; -import com.ning.http.util.AsyncHttpProviderUtils; import java.io.IOException; -import java.util.List; +import java.util.HashSet; +import java.util.Set; public abstract class Protocol { - private static final Logger LOGGER = LoggerFactory.getLogger(Protocol.class); + protected final Logger logger = LoggerFactory.getLogger(getClass()); protected final ChannelManager channelManager; protected final AsyncHttpClientConfig config; - protected final NettyRequestSender nettyRequestSender; + protected final NettyAsyncHttpProviderConfig nettyConfig; + protected final NettyRequestSender requestSender; + + private final boolean hasResponseFilters; + protected final boolean hasIOExceptionFilters; + private final TimeConverter timeConverter; + + public static final Set REDIRECT_STATUSES = new HashSet(); + static { + REDIRECT_STATUSES.add(MOVED_PERMANENTLY.getCode()); + REDIRECT_STATUSES.add(FOUND.getCode()); + REDIRECT_STATUSES.add(SEE_OTHER.getCode()); + REDIRECT_STATUSES.add(TEMPORARY_REDIRECT.getCode()); + } - public Protocol(ChannelManager channelManager, AsyncHttpClientConfig config, NettyRequestSender nettyRequestSender) { + public Protocol(ChannelManager channelManager, AsyncHttpClientConfig config, NettyAsyncHttpProviderConfig nettyConfig, + NettyRequestSender requestSender) { this.channelManager = channelManager; this.config = config; - this.nettyRequestSender = nettyRequestSender; + this.nettyConfig = nettyConfig; + this.requestSender = requestSender; + + hasResponseFilters = !config.getResponseFilters().isEmpty(); + hasIOExceptionFilters = !config.getIOExceptionFilters().isEmpty(); + timeConverter = config.getTimeConverter(); } - protected void replayRequest(final NettyResponseFuture future, FilterContext fc, Channel channel) throws IOException { - if (future.getAsyncHandler() instanceof AsyncHandlerExtensions) - AsyncHandlerExtensions.class.cast(future.getAsyncHandler()).onRetry(); + public abstract void handle(Channel channel, NettyResponseFuture future, Object message) throws Exception; - final Request newRequest = fc.getRequest(); - future.setAsyncHandler(fc.getAsyncHandler()); - future.setState(NettyResponseFuture.STATE.NEW); - future.touch(); + public abstract void onError(Channel channel, Throwable e); - LOGGER.debug("\n\nReplaying Request {}\n for Future {}\n", newRequest, future); - nettyRequestSender.drainChannel(channel, future); - nettyRequestSender.nextRequest(newRequest, future); - return; - } + public abstract void onClose(Channel channel); - protected boolean exitAfterHandlingRedirect(Channel channel, NettyResponseFuture future, Request request, HttpResponse response, + protected boolean exitAfterHandlingRedirect(// + Channel channel,// + NettyResponseFuture future,// + HttpResponse response,// + Request request,// int statusCode) throws Exception { - if (AsyncHttpProviderUtils.followRedirect(config, request) - && (statusCode == 302 || statusCode == 301 || statusCode == 303 || statusCode == 307)) { + if (followRedirect(config, request) && REDIRECT_STATUSES.contains(statusCode)) { + if (future.incrementAndGetCurrentRedirectCount() >= config.getMaxRedirects()) { + throw new MaxRedirectException("Maximum redirect reached: " + config.getMaxRedirects()); - if (future.incrementAndGetCurrentRedirectCount() < config.getMaxRedirects()) { - // allow 401 handling again + } else { + // We must allow 401 handling again. future.getAndSetAuth(false); HttpHeaders responseHeaders = response.headers(); - String location = responseHeaders.get(HttpHeaders.Names.LOCATION); UriComponents uri = UriComponents.create(future.getURI(), location); + if (!uri.equals(future.getURI())) { - final RequestBuilder nBuilder = new RequestBuilder(future.getRequest()); + final RequestBuilder requestBuilder = new RequestBuilder(future.getRequest()); - if (config.isRemoveQueryParamOnRedirect()) - nBuilder.resetQuery(); - else - nBuilder.addQueryParams(future.getRequest().getQueryParams()); + if (!config.isRemoveQueryParamOnRedirect()) + requestBuilder.addQueryParams(future.getRequest().getQueryParams()); - if (!(statusCode < 302 || statusCode > 303) && !(statusCode == 302 && config.isStrict302Handling())) { - nBuilder.setMethod("GET"); - } + // if we are to strictly handle 302, we should keep the original method (which browsers don't) + // 303 must force GET + if ((statusCode == FOUND.getCode() && !config.isStrict302Handling()) || statusCode == SEE_OTHER.getCode()) + requestBuilder.setMethod("GET"); + + // in case of a redirect from HTTP to HTTPS, future attributes might change final boolean initialConnectionKeepAlive = future.isKeepAlive(); final String initialPoolKey = channelManager.getPoolKey(future); + future.setURI(uri); - UriComponents newURI = uri; - String targetScheme = request.getURI().getScheme(); - if (targetScheme.equals(HttpUtil.WEBSOCKET)) { - newURI = newURI.withNewScheme(HttpUtil.WEBSOCKET); - } - if (targetScheme.equals(HttpUtil.WEBSOCKET_SSL)) { - newURI = newURI.withNewScheme(HttpUtil.WEBSOCKET_SSL); + String newUrl = uri.toString(); + if (request.getURI().getScheme().startsWith(WEBSOCKET)) { + newUrl = newUrl.replaceFirst(HTTP, WEBSOCKET); } - LOGGER.debug("Redirecting to {}", newURI); - List setCookieHeaders = responseHeaders.getAll(HttpHeaders.Names.SET_COOKIE2); - if (!isNonEmpty(setCookieHeaders)) { - setCookieHeaders = responseHeaders.getAll(HttpHeaders.Names.SET_COOKIE); - } + logger.debug("Redirecting to {}", newUrl); - for (String cookieStr : setCookieHeaders) { - nBuilder.addOrReplaceCookie(CookieDecoder.decode(cookieStr)); + for (String cookieStr : responseHeaders.getAll(HttpHeaders.Names.SET_COOKIE)) { + Cookie c = CookieDecoder.decode(cookieStr, timeConverter); + if (c != null) + requestBuilder.addOrReplaceCookie(c); } - Callback ac = nettyRequestSender.newDrainCallable(future, channel, initialConnectionKeepAlive, initialPoolKey); + Callback callback = channelManager.newDrainCallback(future, channel, initialConnectionKeepAlive, initialPoolKey); - if (response.isChunked()) { - // We must make sure there is no bytes left before executing the next request. - Channels.setAttachment(channel, ac); + if (HttpHeaders.isTransferEncodingChunked(response)) { + // We must make sure there is no bytes left before + // executing the next request. + // FIXME investigate this + Channels.setAttachment(channel, callback); } else { - ac.call(); + // FIXME don't understand: this offers the connection to the pool, or even closes it, while the + // request has not been sent, right? + callback.call(); } - nettyRequestSender.nextRequest(nBuilder.setURI(newURI).build(), future); + + Request redirectRequest = requestBuilder.setUrl(newUrl).build(); + // FIXME why not reuse the channel is same host? + requestSender.sendNextRequest(redirectRequest, future); return true; } - } else { - throw new MaxRedirectException("Maximum redirect reached: " + config.getMaxRedirects()); } } return false; } - public abstract void handle(Channel channel, MessageEvent e, NettyResponseFuture future) throws Exception; + @SuppressWarnings({ "rawtypes", "unchecked" }) + protected boolean exitAfterProcessingFilters(// + Channel channel,// + NettyResponseFuture future,// + AsyncHandler handler, // + HttpResponseStatus status,// + HttpResponseHeaders responseHeaders) throws IOException { + + if (hasResponseFilters) { + FilterContext fc = new FilterContext.FilterContextBuilder().asyncHandler(handler).request(future.getRequest()) + .responseStatus(status).responseHeaders(responseHeaders).build(); + + for (ResponseFilter asyncFilter : config.getResponseFilters()) { + try { + fc = asyncFilter.filter(fc); + // FIXME Is it worth protecting against this? + if (fc == null) { + throw new NullPointerException("FilterContext is null"); + } + } catch (FilterException efe) { + requestSender.abort(future, efe); + } + } - public abstract void onError(Channel channel, ExceptionEvent e); + // The handler may have been wrapped. + future.setAsyncHandler(fc.getAsyncHandler()); - public abstract void onClose(Channel channel, ChannelStateEvent e); + // The request has changed + if (fc.replayRequest()) { + requestSender.replayRequest(future, fc, channel); + return true; + } + } + return false; + } } diff --git a/src/main/java/com/ning/http/client/providers/netty/handler/WebSocketProtocol.java b/src/main/java/com/ning/http/client/providers/netty/handler/WebSocketProtocol.java index d5367a95ee..fe70261cd8 100644 --- a/src/main/java/com/ning/http/client/providers/netty/handler/WebSocketProtocol.java +++ b/src/main/java/com/ning/http/client/providers/netty/handler/WebSocketProtocol.java @@ -1,31 +1,37 @@ +/* + * Copyright (c) 2014 AsyncHttpClient Project. 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.providers.netty.handler; +import static com.ning.http.client.providers.netty.ws.WebSocketUtils.getAcceptKey; +import static org.jboss.netty.handler.codec.http.HttpResponseStatus.SWITCHING_PROTOCOLS; + import org.jboss.netty.buffer.ChannelBuffer; -import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.Channel; -import org.jboss.netty.channel.ChannelStateEvent; -import org.jboss.netty.channel.ExceptionEvent; -import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.handler.codec.http.HttpChunk; import org.jboss.netty.handler.codec.http.HttpHeaders; import org.jboss.netty.handler.codec.http.HttpResponse; 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; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import com.ning.http.client.AsyncHandler.STATE; import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.HttpResponseHeaders; import com.ning.http.client.HttpResponseStatus; import com.ning.http.client.Request; -import com.ning.http.client.filter.FilterContext; -import com.ning.http.client.filter.FilterException; -import com.ning.http.client.filter.ResponseFilter; +import com.ning.http.client.providers.netty.DiscardEvent; +import com.ning.http.client.providers.netty.NettyAsyncHttpProviderConfig; import com.ning.http.client.providers.netty.channel.ChannelManager; import com.ning.http.client.providers.netty.channel.Channels; import com.ning.http.client.providers.netty.future.NettyResponseFuture; @@ -34,191 +40,150 @@ import com.ning.http.client.providers.netty.response.ResponseHeaders; import com.ning.http.client.providers.netty.response.ResponseStatus; import com.ning.http.client.providers.netty.ws.NettyWebSocket; -import com.ning.http.client.providers.netty.ws.WebSocketUtil; import com.ning.http.client.websocket.WebSocketUpgradeHandler; import com.ning.http.util.StandardCharsets; import java.io.IOException; +import java.util.Locale; + +public final class WebSocketProtocol extends Protocol { -public class WebSocketProtocol extends Protocol { - - private static final Logger LOGGER = LoggerFactory.getLogger(WebSocketProtocol.class); - - 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; - - public WebSocketProtocol(ChannelManager channelManager, AsyncHttpClientConfig config, NettyRequestSender nettyRequestSender) { - super(channelManager, config, nettyRequestSender); + public WebSocketProtocol(ChannelManager channelManager,// + AsyncHttpClientConfig config,// + NettyAsyncHttpProviderConfig nettyConfig,// + NettyRequestSender requestSender) { + super(channelManager, config, nettyConfig, requestSender); } - - // We don't need to synchronize as replacing the "ws-decoder" will process using the same thread. + + // We don't need to synchronize as replacing the "ws-decoder" will + // process using the same thread. private void invokeOnSucces(Channel channel, WebSocketUpgradeHandler h) { if (!h.touchSuccess()) { try { h.onSuccess(new NettyWebSocket(channel)); } catch (Exception ex) { - LOGGER.warn("onSuccess unexexpected exception", ex); + logger.warn("onSuccess unexpected exception", ex); } } } @Override - public void handle(Channel channel, MessageEvent e, final NettyResponseFuture future) throws Exception { - - WebSocketUpgradeHandler wsUpgradeHandler = (WebSocketUpgradeHandler) future.getAsyncHandler(); + public void handle(Channel channel, NettyResponseFuture future, Object e) throws Exception { + WebSocketUpgradeHandler handler = WebSocketUpgradeHandler.class.cast(future.getAsyncHandler()); Request request = future.getRequest(); - if (e.getMessage() instanceof HttpResponse) { - HttpResponse response = (HttpResponse) e.getMessage(); - HttpHeaders nettyResponseHeaders = response.headers(); + if (e instanceof HttpResponse) { + HttpResponse response = (HttpResponse) e; + HttpResponseStatus status = new ResponseStatus(future.getURI(), config, response); + HttpResponseHeaders responseHeaders = new ResponseHeaders(response.headers()); - HttpResponseStatus s = new ResponseStatus(future.getURI(), config, response); - HttpResponseHeaders responseHeaders = new ResponseHeaders(response); - FilterContext fc = new FilterContext.FilterContextBuilder().asyncHandler(wsUpgradeHandler).request(request) - .responseStatus(s).responseHeaders(responseHeaders).build(); - for (ResponseFilter asyncFilter : config.getResponseFilters()) { - try { - fc = asyncFilter.filter(fc); - if (fc == null) { - throw new NullPointerException("FilterContext is null"); - } - } catch (FilterException efe) { - nettyRequestSender.abort(future, efe); - } - } - - // The handler may have been wrapped. - future.setAsyncHandler(fc.getAsyncHandler()); - - // The request has changed - if (fc.replayRequest()) { - replayRequest(future, fc, channel); + if (exitAfterProcessingFilters(channel, future, handler, status, responseHeaders)) { return; } - future.setHttpResponse(response); - if (exitAfterHandlingRedirect(channel, future, request, response, response.getStatus().getCode())) + future.setHttpHeaders(response.headers()); + if (exitAfterHandlingRedirect(channel, future, response, request, response.getStatus().getCode())) return; - 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 = nettyResponseHeaders.contains(HttpHeaders.Names.UPGRADE); - String c = nettyResponseHeaders.get(HttpHeaders.Names.CONNECTION); + boolean validStatus = response.getStatus().equals(SWITCHING_PROTOCOLS); + boolean validUpgrade = response.headers().get(HttpHeaders.Names.UPGRADE) != null; + String c = response.headers().get(HttpHeaders.Names.CONNECTION); if (c == null) { - c = nettyResponseHeaders.get("connection"); + c = response.headers().get(HttpHeaders.Names.CONNECTION.toLowerCase(Locale.ENGLISH)); } - final boolean validConnection = c == null ? false : c.equalsIgnoreCase(HttpHeaders.Values.UPGRADE); + boolean validConnection = c != null && c.equalsIgnoreCase(HttpHeaders.Values.UPGRADE); - s = new ResponseStatus(future.getURI(), config, response); - final boolean statusReceived = wsUpgradeHandler.onStatusReceived(s) == STATE.UPGRADE; + status = new ResponseStatus(future.getURI(), config, response); + final boolean statusReceived = handler.onStatusReceived(status) == STATE.UPGRADE; if (!statusReceived) { try { - wsUpgradeHandler.onCompleted(); + handler.onCompleted(); } finally { future.done(); } return; } - final boolean headerOK = wsUpgradeHandler.onHeadersReceived(responseHeaders) == STATE.CONTINUE; + final boolean headerOK = handler.onHeadersReceived(responseHeaders) == STATE.CONTINUE; if (!headerOK || !validStatus || !validUpgrade || !validConnection) { - nettyRequestSender.abort(future, new IOException("Invalid handshake response")); + requestSender.abort(future, new IOException("Invalid handshake response")); return; } - String accept = nettyResponseHeaders.get(HttpHeaders.Names.SEC_WEBSOCKET_ACCEPT); - String key = WebSocketUtil.getAcceptKey(future.getNettyRequest().headers().get(HttpHeaders.Names.SEC_WEBSOCKET_KEY)); + String accept = response.headers().get(HttpHeaders.Names.SEC_WEBSOCKET_ACCEPT); + String key = getAcceptKey(future.getNettyRequest().getHttpRequest().headers().get(HttpHeaders.Names.SEC_WEBSOCKET_KEY)); if (accept == null || !accept.equals(key)) { - nettyRequestSender.abort(future, new IOException(String.format("Invalid challenge. Actual: %s. Expected: %s", accept, key))); - return; + requestSender.abort(future, new IOException(String.format("Invalid challenge. Actual: %s. Expected: %s", accept, key))); } - // FIXME - channel.getPipeline().replace(ChannelManager.HTTP_HANDLER, "ws-encoder", new WebSocket08FrameEncoder(true)); - channel.getPipeline().addBefore(ChannelManager.WS_PROCESSOR, "ws-decoder", new WebSocket08FrameDecoder(false, false)); + channelManager.upgradePipelineForWebSockets(channel.getPipeline()); - invokeOnSucces(channel, wsUpgradeHandler); + invokeOnSucces(channel, handler); future.done(); - } else if (e.getMessage() instanceof WebSocketFrame) { - - invokeOnSucces(channel, wsUpgradeHandler); - - final WebSocketFrame frame = (WebSocketFrame) e.getMessage(); - - byte pendingOpcode = OPCODE_UNKNOWN; - if (frame instanceof TextWebSocketFrame) { - pendingOpcode = OPCODE_TEXT; - } else if (frame instanceof BinaryWebSocketFrame) { - pendingOpcode = OPCODE_BINARY; - } - - if (frame.getBinaryData() != null) { - - HttpChunk webSocketChunk = new HttpChunk() { - private ChannelBuffer content = ChannelBuffers.wrappedBuffer(frame.getBinaryData()); - @Override - public boolean isLast() { - return false; - } + } else if (e instanceof WebSocketFrame) { - @Override - public ChannelBuffer getContent() { - return content; - } + final WebSocketFrame frame = (WebSocketFrame) e; + NettyWebSocket webSocket = NettyWebSocket.class.cast(handler.onCompleted()); + invokeOnSucces(channel, handler); - @Override - public void setContent(ChannelBuffer content) { - throw new UnsupportedOperationException(); - } - }; - - ResponseBodyPart rp = new ResponseBodyPart(null, webSocketChunk, true); - wsUpgradeHandler.onBodyPartReceived(rp); - - NettyWebSocket webSocket = NettyWebSocket.class.cast(wsUpgradeHandler.onCompleted()); - - if (webSocket != null) { - if (pendingOpcode == OPCODE_BINARY) { - webSocket.onBinaryFragment(rp.getBodyPartBytes(), frame.isFinalFragment()); - } else if (pendingOpcode == OPCODE_TEXT) { - webSocket.onTextFragment(frame.getBinaryData().toString(StandardCharsets.UTF_8), frame.isFinalFragment()); - } + if (webSocket != null) { + if (frame instanceof CloseWebSocketFrame) { + Channels.setDiscard(channel); + CloseWebSocketFrame closeFrame = CloseWebSocketFrame.class.cast(frame); + webSocket.onClose(closeFrame.getStatusCode(), closeFrame.getReasonText()); + } else { - if (frame instanceof CloseWebSocketFrame) { - try { - Channels.setDiscard(channel); - webSocket.onClose(CloseWebSocketFrame.class.cast(frame).getStatusCode(), - CloseWebSocketFrame.class.cast(frame).getReasonText()); - } finally { - wsUpgradeHandler.resetSuccess(); + if (frame.getBinaryData() != null) { + HttpChunk webSocketChunk = new HttpChunk() { + private ChannelBuffer content = frame.getBinaryData(); + + @Override + public boolean isLast() { + return false; + } + + @Override + public ChannelBuffer getContent() { + return content; + } + + @Override + public void setContent(ChannelBuffer content) { + throw new UnsupportedOperationException(); + } + }; + + ResponseBodyPart rp = new ResponseBodyPart(null, webSocketChunk, true); + handler.onBodyPartReceived(rp); + + if (frame instanceof BinaryWebSocketFrame) { + webSocket.onBinaryFragment(rp.getBodyPartBytes(), frame.isFinalFragment()); + } else { + webSocket.onTextFragment(frame.getBinaryData().toString(StandardCharsets.UTF_8), frame.isFinalFragment()); } } - } else { - LOGGER.debug("UpgradeHandler returned a null NettyWebSocket "); } + } else { + logger.debug("UpgradeHandler returned a null NettyWebSocket "); } } else { - LOGGER.error("Invalid message {}", e.getMessage()); + logger.error("Invalid message {}", e); } } @Override - public void onError(Channel channel, ExceptionEvent e) { + public void onError(Channel channel, Throwable e) { try { - Object attachment = Channels.getAttachment(channel); - LOGGER.warn("onError {}", e); - if (!(attachment instanceof NettyResponseFuture)) { + Object attribute = Channels.getAttachment(channel); + logger.warn("onError {}", e); + if (!(attribute instanceof NettyResponseFuture)) { return; } - NettyResponseFuture nettyResponse = (NettyResponseFuture) attachment; + NettyResponseFuture nettyResponse = (NettyResponseFuture) attribute; WebSocketUpgradeHandler h = WebSocketUpgradeHandler.class.cast(nettyResponse.getAsyncHandler()); NettyWebSocket webSocket = NettyWebSocket.class.cast(h.onCompleted()); @@ -227,24 +192,28 @@ public void onError(Channel channel, ExceptionEvent e) { webSocket.close(); } } catch (Throwable t) { - LOGGER.error("onError", t); + logger.error("onError", t); } } @Override - public void onClose(Channel channel, ChannelStateEvent e) { - LOGGER.trace("onClose {}", e); + public void onClose(Channel channel) { + logger.trace("onClose {}"); + Object attribute = Channels.getAttachment(channel); + if (!(attribute instanceof NettyResponseFuture)) + return; - Object attachment = Channels.getAttachment(channel); - if (attachment instanceof NettyResponseFuture) { - try { - NettyResponseFuture nettyResponse = (NettyResponseFuture) attachment; - WebSocketUpgradeHandler h = WebSocketUpgradeHandler.class.cast(nettyResponse.getAsyncHandler()); - h.resetSuccess(); + try { + NettyResponseFuture nettyResponse = NettyResponseFuture.class.cast(attribute); + WebSocketUpgradeHandler h = WebSocketUpgradeHandler.class.cast(nettyResponse.getAsyncHandler()); + NettyWebSocket webSocket = NettyWebSocket.class.cast(h.onCompleted()); - } catch (Throwable t) { - LOGGER.error("onError", t); - } + // FIXME How could this test not succeed, we just checked above that attribute is a NettyResponseFuture???? + logger.trace("Connection was closed abnormally (that is, with no close frame being sent)."); + if (attribute != DiscardEvent.INSTANCE && webSocket != null) + webSocket.close(1006, "Connection was closed abnormally (that is, with no close frame being sent)."); + } catch (Throwable t) { + logger.error("onError", t); } } } diff --git a/src/main/java/com/ning/http/client/providers/netty/request/FeedableBodyGenerator.java b/src/main/java/com/ning/http/client/providers/netty/request/FeedableBodyGenerator.java new file mode 100644 index 0000000000..31d6425b90 --- /dev/null +++ b/src/main/java/com/ning/http/client/providers/netty/request/FeedableBodyGenerator.java @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2014 AsyncHttpClient Project. 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.providers.netty.request; + +import com.ning.http.client.Body; +import com.ning.http.client.BodyGenerator; +import com.ning.http.util.StandardCharsets; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.Queue; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * {@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. + */ +public class FeedableBodyGenerator implements BodyGenerator { + private final static byte[] END_PADDING = "\r\n".getBytes(StandardCharsets.US_ASCII); + private final static byte[] ZERO = "0".getBytes(StandardCharsets.US_ASCII); + private final Queue queue = new ConcurrentLinkedQueue(); + private final AtomicInteger queueSize = new AtomicInteger(); + private FeedListener listener; + + @Override + public Body createBody() throws IOException { + return new PushBody(); + } + + public void feed(final ByteBuffer buffer, final boolean isLast) throws IOException { + queue.offer(new BodyPart(buffer, isLast)); + queueSize.incrementAndGet(); + if (listener != null) { + listener.onContentAdded(); + } + } + + public static interface FeedListener { + void onContentAdded(); + } + + public void setListener(FeedListener listener) { + this.listener = listener; + } + + private final class PushBody implements Body { + private final int ONGOING = 0; + private final int CLOSING = 1; + private final int FINISHED = 2; + + private int finishState = 0; + + @Override + public long getContentLength() { + return -1; + } + + @Override + public long read(final ByteBuffer buffer) throws IOException { + BodyPart nextPart = queue.peek(); + if (nextPart == null) { + // Nothing in the queue + switch (finishState) { + case ONGOING: + return 0; + case CLOSING: + buffer.put(ZERO); + buffer.put(END_PADDING); + finishState = FINISHED; + return buffer.position(); + case FINISHED: + buffer.put(END_PADDING); + return -1; + } + } + int capacity = buffer.remaining() - 10; // be safe (we'll have to add size, ending, etc.) + int size = Math.min(nextPart.buffer.remaining(), capacity); + buffer.put(Integer.toHexString(size).getBytes(StandardCharsets.US_ASCII)); + buffer.put(END_PADDING); + for (int i = 0; i < size; i++) { + buffer.put(nextPart.buffer.get()); + } + buffer.put(END_PADDING); + if (!nextPart.buffer.hasRemaining()) { + if (nextPart.isLast) { + finishState = CLOSING; + } + queue.remove(); + } + return size; + } + + @Override + public void close() throws IOException { + } + + } + + private final static class BodyPart { + private final boolean isLast; + private final ByteBuffer buffer; + + public BodyPart(final ByteBuffer buffer, final boolean isLast) { + this.buffer = buffer; + this.isLast = isLast; + } + } +} diff --git a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequest.java b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequest.java new file mode 100644 index 0000000000..6c114f8794 --- /dev/null +++ b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequest.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2014 AsyncHttpClient Project. 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.providers.netty.request; + +import org.jboss.netty.handler.codec.http.HttpRequest; + +import com.ning.http.client.providers.netty.request.body.NettyBody; + +public final class NettyRequest { + + private final HttpRequest httpRequest; + private final NettyBody body; + + public NettyRequest(HttpRequest httpRequest, NettyBody body) { + this.httpRequest = httpRequest; + this.body = body; + } + + public HttpRequest getHttpRequest() { + return httpRequest; + } + + public NettyBody getBody() { + return body; + } +} diff --git a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestFactory.java b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestFactory.java new file mode 100644 index 0000000000..145e6bf929 --- /dev/null +++ b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestFactory.java @@ -0,0 +1,324 @@ +/* + * Copyright (c) 2014 AsyncHttpClient Project. 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.providers.netty.request; + +import org.jboss.netty.buffer.ChannelBuffers; +import org.jboss.netty.handler.codec.http.DefaultHttpRequest; +import org.jboss.netty.handler.codec.http.HttpHeaders; +import org.jboss.netty.handler.codec.http.HttpMethod; +import org.jboss.netty.handler.codec.http.HttpRequest; +import org.jboss.netty.handler.codec.http.HttpVersion; + +import com.ning.http.client.AsyncHttpClientConfig; +import com.ning.http.client.Param; +import com.ning.http.client.ProxyServer; +import com.ning.http.client.Realm; +import com.ning.http.client.Request; +import com.ning.http.client.cookie.CookieEncoder; +import com.ning.http.client.generators.FileBodyGenerator; +import com.ning.http.client.generators.InputStreamBodyGenerator; +import com.ning.http.client.ntlm.NTLMEngine; +import com.ning.http.client.ntlm.NTLMEngineException; +import com.ning.http.client.providers.netty.NettyAsyncHttpProvider; +import com.ning.http.client.providers.netty.NettyAsyncHttpProviderConfig; +import com.ning.http.client.providers.netty.request.body.NettyBody; +import com.ning.http.client.providers.netty.request.body.NettyBodyBody; +import com.ning.http.client.providers.netty.request.body.NettyByteArrayBody; +import com.ning.http.client.providers.netty.request.body.NettyFileBody; +import com.ning.http.client.providers.netty.request.body.NettyInputStreamBody; +import com.ning.http.client.providers.netty.request.body.NettyMultipartBody; +import com.ning.http.client.providers.netty.spnego.SpnegoEngine; +import static com.ning.http.client.providers.netty.util.HttpUtils.*; +import static com.ning.http.client.providers.netty.ws.WebSocketUtils.*; +import com.ning.http.client.uri.UriComponents; +import static com.ning.http.util.AsyncHttpProviderUtils.*; +import static com.ning.http.util.AuthenticatorUtils.*; +import static com.ning.http.util.MiscUtils.*; +import com.ning.http.util.UTF8UrlEncoder; + +import java.io.IOException; +import java.nio.charset.Charset; +import java.security.NoSuchAlgorithmException; +import java.util.List; +import java.util.Map.Entry; + +public final class NettyRequestFactory { + + public static final String GZIP_DEFLATE = HttpHeaders.Values.GZIP + "," + HttpHeaders.Values.DEFLATE; + + private final AsyncHttpClientConfig config; + private final NettyAsyncHttpProviderConfig nettyConfig; + + public NettyRequestFactory(AsyncHttpClientConfig config, NettyAsyncHttpProviderConfig nettyConfig) { + this.config = config; + this.nettyConfig = nettyConfig; + } + + private String requestUri(UriComponents uri, ProxyServer proxyServer, HttpMethod method) { + if (method == HttpMethod.CONNECT) + return getAuthority(uri); + + else if (proxyServer != null && !(isSecure(uri) && config.isUseRelativeURIsWithSSLProxies())) + return uri.toString(); + + else { + String path = getNonEmptyPath(uri); + if (isNonEmpty(uri.getQuery())) + return path + "?" + uri.getQuery(); + else + return path; + } + } + + private String hostHeader(Request request, UriComponents uri) { + String host = request.getVirtualHost() != null ? request.getVirtualHost() : uri.getHost(); + return request.getVirtualHost() != null || uri.getPort() == -1 ? host : host + ":" + uri.getPort(); + } + + private String authorizationHeader(Request request, UriComponents uri, ProxyServer proxyServer, Realm realm) throws IOException { + + String authorizationHeader = null; + + if (realm != null && realm.getUsePreemptiveAuth()) { + + switch (realm.getAuthScheme()) { + case BASIC: + authorizationHeader = computeBasicAuthentication(realm); + break; + case DIGEST: + if (isNonEmpty(realm.getNonce())) { + try { + authorizationHeader = computeDigestAuthentication(realm); + } catch (NoSuchAlgorithmException e) { + throw new SecurityException(e); + } + } + break; + case NTLM: + String domain; + if (proxyServer != null && proxyServer.getNtlmDomain() != null) { + domain = proxyServer.getNtlmDomain(); + } else { + domain = realm.getNtlmDomain(); + } + try { + String msg = NTLMEngine.INSTANCE.generateType1Msg("NTLM " + domain, realm.getNtlmHost()); + authorizationHeader = "NTLM " + msg; + } catch (NTLMEngineException e) { + throw new IOException(e); + } + break; + case KERBEROS: + case SPNEGO: + + String host; + if (proxyServer != null) + host = proxyServer.getHost(); + else if (request.getVirtualHost() != null) + host = request.getVirtualHost(); + else + host = uri.getHost(); + + try { + authorizationHeader = "Negotiate " + SpnegoEngine.INSTANCE.generateToken(host); + } catch (Throwable e) { + throw new IOException(e); + } + break; + case NONE: + break; + default: + throw new IllegalStateException("Invalid Authentication " + realm); + } + } + + return authorizationHeader; + } + + private String proxyAuthorizationHeader(Request request, ProxyServer proxyServer, HttpMethod method) throws IOException { + + String proxyAuthorization = null; + + if (method == HttpMethod.CONNECT) { + List auth = request.getHeaders().get(HttpHeaders.Names.PROXY_AUTHORIZATION); + if (isNTLM(auth)) { + proxyAuthorization = auth.get(0); + } + + } else if (proxyServer != null && proxyServer.getPrincipal() != null) { + if (isNonEmpty(proxyServer.getNtlmDomain())) { + List auth = request.getHeaders().get(HttpHeaders.Names.PROXY_AUTHORIZATION); + if (!isNTLM(auth)) { + try { + String msg = NTLMEngine.INSTANCE.generateType1Msg(proxyServer.getNtlmDomain(), proxyServer.getHost()); + proxyAuthorization = "NTLM " + msg; + } catch (NTLMEngineException e) { + IOException ie = new IOException(); + ie.initCause(e); + throw ie; + } + } + } else { + proxyAuthorization = computeBasicAuthentication(proxyServer); + } + } + + return proxyAuthorization; + } + + private byte[] computeBodyFromParams(List params, Charset bodyCharset) { + + StringBuilder sb = new StringBuilder(); + for (Param param : params) { + UTF8UrlEncoder.appendEncoded(sb, param.getName()); + sb.append("="); + UTF8UrlEncoder.appendEncoded(sb, param.getValue()); + sb.append("&"); + } + sb.setLength(sb.length() - 1); + return sb.toString().getBytes(bodyCharset); + } + + private NettyBody body(Request request, HttpMethod method) throws IOException { + NettyBody nettyBody = null; + if (method != HttpMethod.CONNECT) { + + Charset bodyCharset = request.getBodyEncoding() == null ? DEFAULT_CHARSET : Charset.forName(request.getBodyEncoding()); + + if (request.getByteData() != null) + nettyBody = new NettyByteArrayBody(request.getByteData()); + + else if (request.getStringData() != null) + nettyBody = new NettyByteArrayBody(request.getStringData().getBytes(bodyCharset)); + + else if (request.getStreamData() != null) + nettyBody = new NettyInputStreamBody(request.getStreamData()); + + else if (isNonEmpty(request.getFormParams())) { + + String contentType = null; + if (!request.getHeaders().containsKey(HttpHeaders.Names.CONTENT_TYPE)) + contentType = HttpHeaders.Values.APPLICATION_X_WWW_FORM_URLENCODED; + + nettyBody = new NettyByteArrayBody(computeBodyFromParams(request.getFormParams(), bodyCharset), contentType); + + } else if (isNonEmpty(request.getParts())) + nettyBody = new NettyMultipartBody(request.getParts(), request.getHeaders(), nettyConfig); + + else if (request.getFile() != null) + nettyBody = new NettyFileBody(request.getFile(), nettyConfig); + + else if (request.getBodyGenerator() instanceof FileBodyGenerator) { + FileBodyGenerator fileBodyGenerator = (FileBodyGenerator) request.getBodyGenerator(); + nettyBody = new NettyFileBody(fileBodyGenerator.getFile(), fileBodyGenerator.getRegionSeek(), + fileBodyGenerator.getRegionLength(), nettyConfig); + + } else if (request.getBodyGenerator() instanceof InputStreamBodyGenerator) + nettyBody = new NettyInputStreamBody(InputStreamBodyGenerator.class.cast(request.getBodyGenerator()).getInputStream()); + + else if (request.getBodyGenerator() != null) + nettyBody = new NettyBodyBody(request.getBodyGenerator().createBody(), nettyConfig); + } + + return nettyBody; + } + + public NettyRequest newNettyRequest(Request request, UriComponents uri, boolean forceConnect, ProxyServer proxyServer) + throws IOException { + + HttpMethod method = forceConnect ? HttpMethod.CONNECT : HttpMethod.valueOf(request.getMethod()); + HttpVersion httpVersion = method == HttpMethod.CONNECT ? HttpVersion.HTTP_1_0 : HttpVersion.HTTP_1_1; + String requestUri = requestUri(uri, proxyServer, method); + + NettyBody body = body(request, method); + + HttpRequest httpRequest; + NettyRequest nettyRequest; + if (body instanceof NettyByteArrayBody) { + byte[] bytes = NettyByteArrayBody.class.cast(body).getBytes(); + httpRequest = new DefaultHttpRequest(httpVersion, method, requestUri); + // body is passed as null as it's written directly with the request + httpRequest.setContent(ChannelBuffers.wrappedBuffer(bytes)); + nettyRequest = new NettyRequest(httpRequest, null); + + } else { + httpRequest = new DefaultHttpRequest(httpVersion, method, requestUri); + nettyRequest = new NettyRequest(httpRequest, body); + } + + if (method != HttpMethod.CONNECT) { + // assign headers as configured on request + for (Entry> header : request.getHeaders()) { + httpRequest.headers().set(header.getKey(), header.getValue()); + } + + if (isNonEmpty(request.getCookies())) + httpRequest.headers().set(HttpHeaders.Names.COOKIE, CookieEncoder.encode(request.getCookies())); + + if (config.isCompressionEnabled()) + httpRequest.headers().set(HttpHeaders.Names.ACCEPT_ENCODING, GZIP_DEFLATE); + } + + if (body != null) { + if (body.getContentLength() >= 0) + httpRequest.headers().set(HttpHeaders.Names.CONTENT_LENGTH, body.getContentLength()); + else + httpRequest.headers().set(HttpHeaders.Names.TRANSFER_ENCODING, HttpHeaders.Values.CHUNKED); + + if (body.getContentType() != null) + httpRequest.headers().set(HttpHeaders.Names.CONTENT_TYPE, body.getContentType()); + } + + // connection header and friends + boolean webSocket = isWebSocket(uri.getScheme()); + if (method != HttpMethod.CONNECT && webSocket) { + String origin = "http://" + uri.getHost() + ":" + (uri.getPort() == -1 ? isSecure(uri.getScheme()) ? 443 : 80 : uri.getPort()); + httpRequest.headers().set(HttpHeaders.Names.UPGRADE, HttpHeaders.Values.WEBSOCKET)// + .set(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.UPGRADE)// + .set(HttpHeaders.Names.ORIGIN, origin)// + .set(HttpHeaders.Names.SEC_WEBSOCKET_KEY, getKey())// + .set(HttpHeaders.Names.SEC_WEBSOCKET_VERSION, "13"); + + } else if (!httpRequest.headers().contains(HttpHeaders.Names.CONNECTION)) { + httpRequest.headers().set(HttpHeaders.Names.CONNECTION, keepAliveHeaderValue(config)); + } + + String hostHeader = hostHeader(request, uri); + if (hostHeader != null) + httpRequest.headers().set(HttpHeaders.Names.HOST, hostHeader); + + Realm realm = request.getRealm() != null ? request.getRealm() : config.getRealm(); + String authorizationHeader = authorizationHeader(request, uri, proxyServer, realm); + if (authorizationHeader != null) + // don't override authorization but append + httpRequest.headers().add(HttpHeaders.Names.AUTHORIZATION, authorizationHeader); + + String proxyAuthorizationHeader = proxyAuthorizationHeader(request, proxyServer, method); + if (proxyAuthorizationHeader != null) + httpRequest.headers().set(HttpHeaders.Names.PROXY_AUTHORIZATION, proxyAuthorizationHeader); + + // Add default accept headers + if (!httpRequest.headers().contains(HttpHeaders.Names.ACCEPT)) + httpRequest.headers().set(HttpHeaders.Names.ACCEPT, "*/*"); + + // Add default user agent + if (!httpRequest.headers().contains(HttpHeaders.Names.USER_AGENT)) { + String userAgent = config.getUserAgent() != null ? config.getUserAgent() : constructUserAgent(NettyAsyncHttpProvider.class, + config); + httpRequest.headers().set(HttpHeaders.Names.USER_AGENT, userAgent); + } + + return nettyRequest; + } +} diff --git a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java index 750ccac448..5accbe8e5d 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java @@ -12,23 +12,19 @@ */ package com.ning.http.client.providers.netty.request; -import static com.ning.http.util.AsyncHttpProviderUtils.DEFAULT_CHARSET; -import static com.ning.http.util.AsyncHttpProviderUtils.getNonEmptyPath; -import static com.ning.http.util.MiscUtils.isNonEmpty; +import static com.ning.http.client.providers.netty.util.HttpUtils.WEBSOCKET; +import static com.ning.http.client.providers.netty.util.HttpUtils.isSecure; +import static com.ning.http.util.AsyncHttpProviderUtils.getDefaultPort; +import static com.ning.http.util.AsyncHttpProviderUtils.requestTimeout; +import static com.ning.http.util.ProxyUtils.avoidProxy; +import static com.ning.http.util.ProxyUtils.getProxyServer; import org.jboss.netty.bootstrap.ClientBootstrap; -import org.jboss.netty.buffer.ChannelBuffer; -import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFuture; -import org.jboss.netty.channel.FileRegion; -import org.jboss.netty.handler.codec.http.DefaultHttpRequest; import org.jboss.netty.handler.codec.http.HttpHeaders; import org.jboss.netty.handler.codec.http.HttpMethod; import org.jboss.netty.handler.codec.http.HttpRequest; -import org.jboss.netty.handler.codec.http.HttpVersion; -import org.jboss.netty.handler.ssl.SslHandler; -import org.jboss.netty.handler.stream.ChunkedFile; import org.jboss.netty.util.Timeout; import org.jboss.netty.util.Timer; import org.jboss.netty.util.TimerTask; @@ -38,304 +34,246 @@ import com.ning.http.client.AsyncHandler; import com.ning.http.client.AsyncHandlerExtensions; import com.ning.http.client.AsyncHttpClientConfig; -import com.ning.http.client.Body; -import com.ning.http.client.BodyGenerator; import com.ning.http.client.ConnectionPoolKeyStrategy; import com.ning.http.client.FluentCaseInsensitiveStringsMap; import com.ning.http.client.ListenableFuture; 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.cookie.CookieEncoder; import com.ning.http.client.filter.FilterContext; -import com.ning.http.client.generators.InputStreamBodyGenerator; +import com.ning.http.client.filter.FilterException; +import com.ning.http.client.filter.IOExceptionFilter; 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.Callback; -import com.ning.http.client.providers.netty.NettyAsyncHttpProvider; import com.ning.http.client.providers.netty.NettyAsyncHttpProviderConfig; import com.ning.http.client.providers.netty.channel.ChannelManager; import com.ning.http.client.providers.netty.channel.Channels; import com.ning.http.client.providers.netty.future.NettyResponseFuture; -import com.ning.http.client.providers.netty.request.body.BodyChunkedInput; -import com.ning.http.client.providers.netty.request.body.BodyFileRegion; -import com.ning.http.client.providers.netty.request.body.OptimizedFileRegion; +import com.ning.http.client.providers.netty.request.body.NettyConnectListener; import com.ning.http.client.providers.netty.request.timeout.ReadTimeoutTimerTask; import com.ning.http.client.providers.netty.request.timeout.RequestTimeoutTimerTask; import com.ning.http.client.providers.netty.request.timeout.TimeoutsHolder; -import com.ning.http.client.providers.netty.spnego.SpnegoEngine; -import com.ning.http.client.providers.netty.util.HttpUtil; -import com.ning.http.client.providers.netty.ws.WebSocketUtil; import com.ning.http.client.uri.UriComponents; -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.ProxyUtils; - -import java.io.File; -import java.io.FileInputStream; +import com.ning.http.client.websocket.WebSocketUpgradeHandler; + import java.io.IOException; -import java.io.RandomAccessFile; import java.net.InetSocketAddress; -import java.nio.charset.Charset; -import java.security.NoSuchAlgorithmException; -import java.util.List; -import java.util.Map.Entry; +import java.util.Map; import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; -public class NettyRequestSender { +public final class NettyRequestSender { private static final Logger LOGGER = LoggerFactory.getLogger(NettyRequestSender.class); public static final String GZIP_DEFLATE = HttpHeaders.Values.GZIP + "," + HttpHeaders.Values.DEFLATE; private final AsyncHttpClientConfig config; - private final NettyAsyncHttpProviderConfig nettyConfig; private final ChannelManager channelManager; private final Timer nettyTimer; private final AtomicBoolean closed; - private final boolean disableZeroCopy; + private final NettyRequestFactory requestFactory; - public NettyRequestSender(AsyncHttpClientConfig config, NettyAsyncHttpProviderConfig nettyConfig, ChannelManager channelManager, - Timer nettyTimer, AtomicBoolean closed) { + public NettyRequestSender(AsyncHttpClientConfig config,// + NettyAsyncHttpProviderConfig nettyConfig,// + ChannelManager channelManager,// + Timer nettyTimer,// + AtomicBoolean closed) { this.config = config; - this.nettyConfig = nettyConfig; this.channelManager = channelManager; this.nettyTimer = nettyTimer; this.closed = closed; - disableZeroCopy = nettyConfig.isDisableZeroCopy(); + requestFactory = new NettyRequestFactory(config, nettyConfig); } - public void abort(NettyResponseFuture future, Throwable t) { - Channel channel = future.channel(); - if (channel != null) - channelManager.closeChannel(channel); - - if (!future.isDone()) { - LOGGER.debug("Aborting Future {}\n", future); - LOGGER.debug(t.getMessage(), t); - } + public ListenableFuture sendRequest(final Request request,// + final AsyncHandler asyncHandler,// + NettyResponseFuture future,// + boolean reclaimCache) throws IOException { - future.abort(t); - } + if (closed.get()) + throw new IOException("Closed"); - public Timeout newTimeout(TimerTask task, long delay) { - return nettyTimer.newTimeout(task, delay, TimeUnit.MILLISECONDS); - } + UriComponents uri = request.getURI(); - public final void writeRequest(final Channel channel, final AsyncHttpClientConfig config, final NettyResponseFuture future) { + // FIXME really useful? Why not do this check when building the request? + if (uri.getScheme().startsWith(WEBSOCKET) && !validateWebSocketRequest(request, asyncHandler)) + throw new IOException("WebSocket method must be a GET"); - HttpRequest nettyRequest = future.getNettyRequest(); - HttpHeaders nettyRequestHeaders = nettyRequest.headers(); - boolean ssl = channel.getPipeline().get(SslHandler.class) != null; + ProxyServer proxyServer = getProxyServer(config, request); + boolean resultOfAConnect = future != null && future.getNettyRequest() != null + && future.getNettyRequest().getHttpRequest().getMethod() == HttpMethod.CONNECT; + boolean useProxy = proxyServer != null && !resultOfAConnect; - 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 channelClosed do it's work. - */ - if (!channel.isOpen() || !channel.isConnected()) { - return; - } + if (useProxy && isSecure(uri)) + // SSL proxy, have to handle CONNECT + if (future != null && future.isConnectAllowed()) + // CONNECT forced + return sendRequestWithCertainForceConnect(request, asyncHandler, future, reclaimCache, uri, proxyServer, true, true); + else + return sendRequestThroughSslProxy(request, asyncHandler, future, reclaimCache, uri, proxyServer); + else + return sendRequestWithCertainForceConnect(request, asyncHandler, future, reclaimCache, uri, proxyServer, useProxy, false); + } - Body body = null; - if (!nettyRequest.getMethod().equals(HttpMethod.CONNECT)) { - BodyGenerator bg = future.getRequest().getBodyGenerator(); + /** + * We know for sure if we have to force to connect or not, so we can + * build the HttpRequest right away + * This reduces the probability of having a pooled channel closed by the + * server by the time we build the request + */ + private ListenableFuture sendRequestWithCertainForceConnect(// + Request request,// + AsyncHandler asyncHandler,// + NettyResponseFuture future,// + boolean reclaimCache,// + UriComponents uri,// + ProxyServer proxyServer,// + boolean useProxy,// + boolean forceConnect) throws IOException { + NettyResponseFuture newFuture = newNettyRequestAndResponseFuture(request, asyncHandler, future, uri, proxyServer, forceConnect); + + Channel channel = getCachedChannel(future, uri, request.getConnectionPoolKeyStrategy(), proxyServer); + + if (Channels.isChannelValid(channel)) + return sendRequestWithCachedChannel(request, uri, proxyServer, newFuture, asyncHandler, channel); + else + return sendRequestWithNewChannel(request, uri, proxyServer, useProxy, newFuture, asyncHandler, reclaimCache); + } - if (bg == null && future.getRequest().getStreamData() != null) { - bg = new InputStreamBodyGenerator(future.getRequest().getStreamData()); - } + /** + * Using CONNECT depends on wither we can fetch a valid channel or not + * Loop until we get a valid channel from the pool and it's still valid + * once the request is built + */ + private ListenableFuture sendRequestThroughSslProxy(// + Request request,// + AsyncHandler asyncHandler,// + NettyResponseFuture future,// + boolean reclaimCache,// + UriComponents uri,// + ProxyServer proxyServer) throws IOException { - if (bg != null) { - // Netty issue with chunking. - if (bg instanceof InputStreamBodyGenerator) { - InputStreamBodyGenerator.class.cast(bg).patchNettyChunkingIssue(true); - } + NettyResponseFuture newFuture = null; + for (int i = 0; i < 3; i++) { + Channel channel = getCachedChannel(future, uri, request.getConnectionPoolKeyStrategy(), proxyServer); + if (Channels.isChannelValid(channel)) + if (newFuture == null) + newFuture = newNettyRequestAndResponseFuture(request, asyncHandler, future, uri, proxyServer, false); + + if (Channels.isChannelValid(channel)) + // if the channel is still active, we can use it, otherwise try + // gain + return sendRequestWithCachedChannel(request, uri, proxyServer, newFuture, asyncHandler, channel); + else + // pool is empty + break; + } - try { - body = bg.createBody(); - } catch (IOException ex) { - throw new IllegalStateException(ex); - } - long length = body.getContentLength(); - if (length >= 0) { - nettyRequestHeaders.set(HttpHeaders.Names.CONTENT_LENGTH, length); - } else { - nettyRequestHeaders.set(HttpHeaders.Names.TRANSFER_ENCODING, HttpHeaders.Values.CHUNKED); - } + newFuture = newNettyRequestAndResponseFuture(request, asyncHandler, future, uri, proxyServer, true); + return sendRequestWithNewChannel(request, uri, proxyServer, true, newFuture, asyncHandler, reclaimCache); + } - } else if (isNonEmpty(future.getRequest().getParts())) { - String contentType = nettyRequestHeaders.get(HttpHeaders.Names.CONTENT_TYPE); - String contentLength = nettyRequestHeaders.get(HttpHeaders.Names.CONTENT_LENGTH); + private NettyResponseFuture newNettyRequestAndResponseFuture(final Request request, final AsyncHandler asyncHandler, + NettyResponseFuture originalFuture, UriComponents uri, ProxyServer proxy, boolean forceConnect) throws IOException { - long length = -1; - if (contentLength != null) { - length = Long.parseLong(contentLength); - } else { - nettyRequestHeaders.add(HttpHeaders.Names.TRANSFER_ENCODING, HttpHeaders.Values.CHUNKED); - } + NettyRequest nettyRequest = requestFactory.newNettyRequest(request, uri, forceConnect, proxy); - body = new MultipartBody(future.getRequest().getParts(), contentType, length); - } - } + if (originalFuture == null) { + return newNettyResponseFuture(uri, request, asyncHandler, nettyRequest, proxy); + } else { + originalFuture.setNettyRequest(nettyRequest); + originalFuture.setRequest(request); + return originalFuture; + } + } - if (future.getAsyncHandler() instanceof TransferCompletionHandler) { + private Channel getCachedChannel(NettyResponseFuture future, UriComponents uri, ConnectionPoolKeyStrategy poolKeyGen, + ProxyServer proxyServer) { - FluentCaseInsensitiveStringsMap h = new FluentCaseInsensitiveStringsMap(); - for (String s : nettyRequestHeaders.names()) { - for (String header : nettyRequestHeaders.getAll(s)) { - h.add(s, header); - } - } + if (future != null && future.reuseChannel() && Channels.isChannelValid(future.channel())) + return future.channel(); + else + return pollAndVerifyCachedChannel(uri, proxyServer, poolKeyGen); + } - TransferCompletionHandler.class.cast(future.getAsyncHandler()).transferAdapter( - new NettyTransferAdapter(h, nettyRequest.getContent(), future.getRequest().getFile())); - } + private ListenableFuture sendRequestWithCachedChannel(Request request, UriComponents uri, ProxyServer proxy, + NettyResponseFuture future, AsyncHandler asyncHandler, Channel channel) throws IOException { - // Leave it to true. - if (future.getAndSetWriteHeaders(true)) { - try { - if (future.getAsyncHandler() instanceof AsyncHandlerExtensions) - AsyncHandlerExtensions.class.cast(future.getAsyncHandler()).onRequestSent(); + future.setState(NettyResponseFuture.STATE.POOLED); + future.attachChannel(channel, false); - channel.write(nettyRequest).addListener(new ProgressListener(config, true, future.getAsyncHandler(), future)); - } catch (Throwable cause) { - LOGGER.debug(cause.getMessage(), cause); - try { - channel.close(); - } catch (RuntimeException ex) { - LOGGER.debug(ex.getMessage(), ex); - } - return; - } - } + LOGGER.debug("\nUsing cached Channel {}\n for request \n{}\n", channel, future.getNettyRequest().getHttpRequest()); + Channels.setAttachment(channel, future); - if (future.getAndSetWriteBody(true)) { - if (!nettyRequest.getMethod().equals(HttpMethod.CONNECT)) { - - if (future.getRequest().getFile() != null) { - final File file = future.getRequest().getFile(); - final RandomAccessFile raf = new RandomAccessFile(file, "r"); - - try { - ChannelFuture writeFuture; - if (disableZeroCopy || ssl) { - writeFuture = channel.write(new ChunkedFile(raf, 0, raf.length(), nettyConfig.getChunkedFileChunkSize())); - } else { - final FileRegion region = new OptimizedFileRegion(raf, 0, raf.length()); - writeFuture = channel.write(region); - } - writeFuture.addListener(new ProgressListener(config, false, future.getAsyncHandler(), future) { - public void operationComplete(ChannelFuture cf) { - try { - raf.close(); - } catch (IOException e) { - LOGGER.warn("Failed to close request body: {}", e.getMessage(), e); - } - super.operationComplete(cf); - } - }); - } catch (IOException ex) { - if (raf != null) { - try { - raf.close(); - } catch (IOException e) { - } - } - throw ex; - } - } else if (body != null) { - final Body b = body; - - ChannelFuture writeFuture; - if (disableZeroCopy || ssl || !(body instanceof RandomAccessBody)) { - BodyChunkedInput bodyChunkedInput = new BodyChunkedInput(body); - writeFuture = channel.write(bodyChunkedInput); - } else { - BodyFileRegion bodyFileRegion = new BodyFileRegion((RandomAccessBody) body); - writeFuture = channel.write(bodyFileRegion); - } - writeFuture.addListener(new ProgressListener(config, false, future.getAsyncHandler(), future) { - public void operationComplete(ChannelFuture cf) { - try { - b.close(); - } catch (IOException e) { - LOGGER.warn("Failed to close request body: {}", e.getMessage(), e); - } - super.operationComplete(cf); - } - }); - } + try { + writeRequest(future, channel); + } catch (Exception ex) { + LOGGER.debug("writeRequest failure", ex); + if (ex.getMessage() != null && ex.getMessage().contains("SSLEngine")) { + LOGGER.debug("SSLEngine failure", ex); + future = null; + } else { + try { + asyncHandler.onThrowable(ex); + } catch (Throwable t) { + LOGGER.warn("doConnect.writeRequest()", t); } - } - } catch (Throwable ioe) { - try { - channel.close(); - } catch (RuntimeException ex) { - LOGGER.debug(ex.getMessage(), ex); + IOException ioe = new IOException(ex.getMessage()); + ioe.initCause(ex); + throw ioe; } } + return future; + } - try { - future.touch(); - int requestTimeout = AsyncHttpProviderUtils.requestTimeout(config, future.getRequest()); - TimeoutsHolder timeoutsHolder = new TimeoutsHolder(); - if (requestTimeout != -1) { - timeoutsHolder.requestTimeout = newTimeout(new RequestTimeoutTimerTask(future, this, timeoutsHolder, requestTimeout), - requestTimeout); - } + private ListenableFuture sendRequestWithNewChannel(// + Request request,// + UriComponents uri,// + ProxyServer proxy,// + boolean useProxy,// + NettyResponseFuture future,// + AsyncHandler asyncHandler,// + boolean reclaimCache) throws IOException { - int readTimeout = config.getReadTimeout(); - if (readTimeout != -1 && readTimeout <= requestTimeout) { - // no need for a idleConnectionTimeout that's less than the requestTimeout - timeoutsHolder.readTimeout = newTimeout( - new ReadTimeoutTimerTask(future, this, timeoutsHolder, requestTimeout, readTimeout), readTimeout); - } - future.setTimeoutsHolder(timeoutsHolder); + boolean useSSl = isSecure(uri) && !useProxy; - } catch (RejectedExecutionException ex) { - abort(future, ex); - } - } + // Do not throw an exception when we need an extra connection for a + // redirect + // FIXME why? This violate the max connection per host handling, right? + ClientBootstrap bootstrap = channelManager.getBootstrap(request.getURI().getScheme(), useProxy, useSSl); - public void nextRequest(final Request request, final NettyResponseFuture future) throws IOException { - nextRequest(request, future, true); - } + boolean channelPreempted = false; + String poolKey = null; - private void nextRequest(final Request request, final NettyResponseFuture future, final boolean useCache) throws IOException { - execute(request, future, useCache, true); - } + // Do not throw an exception when we need an extra connection for a redirect. + if (!reclaimCache) { - private void execute(final Request request, final NettyResponseFuture f, boolean useCache, boolean reclaimCache) - throws IOException { - doConnect(request, f.getAsyncHandler(), f, useCache, reclaimCache); - } + // only compute when maxConnectionPerHost is enabled + // FIXME clean up + if (config.getMaxConnectionsPerHost() > 0) + poolKey = channelManager.getPoolKey(future); - private Channel lookupInCache(UriComponents uri, ProxyServer proxy, ConnectionPoolKeyStrategy strategy) { - final Channel channel = channelManager.poll(channelManager.getPoolKey(uri, proxy, strategy)); + channelPreempted = preemptChannel(asyncHandler, poolKey); + } - if (channel != null) { - LOGGER.debug("Using cached Channel {}\n for uri {}\n", channel, uri); + try { + ChannelFuture channelFuture = connect(request, uri, proxy, useProxy, bootstrap); + channelFuture.addListener(new NettyConnectListener(config, future, this, channelManager, channelPreempted, poolKey)); - try { - // Always make sure the channel who got cached support the proper protocol. It could - // only occurs when a HttpMethod.CONNECT is used against a proxy that requires upgrading from http to - // https. - return channelManager.verifyChannelPipeline(channel, uri.getScheme()); - } catch (Exception ex) { - LOGGER.debug(ex.getMessage(), ex); - } + } catch (Throwable t) { + if (channelPreempted) + channelManager.abortChannelPreemption(poolKey); + + abort(future, t.getCause() == null ? t : t.getCause()); } - return null; + + return future; } - private NettyResponseFuture newFuture(UriComponents uri, Request request, AsyncHandler asyncHandler, - HttpRequest nettyRequest, AsyncHttpClientConfig config, ProxyServer proxyServer) { + private NettyResponseFuture newNettyResponseFuture(UriComponents uri, Request request, AsyncHandler asyncHandler, + NettyRequest nettyRequest, ProxyServer proxyServer) { - NettyResponseFuture f = new NettyResponseFuture(uri,// + NettyResponseFuture future = new NettyResponseFuture(// + uri,// request,// asyncHandler,// nettyRequest,// @@ -344,443 +282,146 @@ private NettyResponseFuture newFuture(UriComponents uri, Request request, proxyServer); String expectHeader = request.getHeaders().getFirstValue(HttpHeaders.Names.EXPECT); - if (expectHeader != null && expectHeader.equalsIgnoreCase(HttpHeaders.Values.CONTINUE)) { - f.getAndSetWriteBody(false); - } - return f; + if (expectHeader != null && expectHeader.equalsIgnoreCase(HttpHeaders.Values.CONTINUE)) + future.setDontWriteBodyBecauseExpectContinue(true); + return future; } - private NettyResponseFuture buildNettyResponseFutureWithCachedChannel(Request request, AsyncHandler asyncHandler, - NettyResponseFuture f, ProxyServer proxyServer, UriComponents uri, ChannelBuffer bufferedBytes, int maxTry) - throws IOException { - - for (int i = 0; i < maxTry; i++) { - if (maxTry == 0) - return null; - - Channel channel = null; - if (f != null && f.reuseChannel() && f.channel() != null) { - channel = f.channel(); - } else { - channel = lookupInCache(uri, proxyServer, request.getConnectionPoolKeyStrategy()); - } - - if (channel == null) - return null; - else { - HttpRequest nettyRequest = null; - - if (f == null) { - nettyRequest = buildRequest(config, request, uri, false, bufferedBytes, proxyServer); - f = newFuture(uri, request, asyncHandler, nettyRequest, config, proxyServer); - } else if (i == 0) { - // only build request on first try - nettyRequest = buildRequest(config, request, uri, f.isConnectAllowed(), bufferedBytes, proxyServer); - f.setNettyRequest(nettyRequest); - } - f.setState(NettyResponseFuture.STATE.POOLED); - f.attachChannel(channel, false); - - if (channel.isOpen() && channel.isConnected()) { - Channels.setAttachment(channel, f); - return f; - } else - // else, channel was closed by the server since we fetched it from the pool, starting over - f.attachChannel(null); - } - } - return null; - } - - private String computeNonConnectRequestPath(AsyncHttpClientConfig config, UriComponents uri, ProxyServer proxyServer) { - if (proxyServer != null && !(HttpUtil.isSecure(uri) && config.isUseRelativeURIsWithSSLProxies())) - return uri.toString(); - else { - String path = getNonEmptyPath(uri); - return uri.getQuery() != null ? path + "?" + uri.getQuery() : path; - } - } - - private HttpRequest construct(AsyncHttpClientConfig config, Request request, HttpMethod m, UriComponents uri, ChannelBuffer buffer, - ProxyServer proxyServer) throws IOException { - - HttpRequest nettyRequest; - - if (m.equals(HttpMethod.CONNECT)) { - nettyRequest = new DefaultHttpRequest(HttpVersion.HTTP_1_0, m, AsyncHttpProviderUtils.getAuthority(uri)); - } else { - String path = computeNonConnectRequestPath(config, uri, proxyServer); - nettyRequest = new DefaultHttpRequest(HttpVersion.HTTP_1_1, m, path); - } - - HttpHeaders nettyRequestHeaders = nettyRequest.headers(); + public void writeRequest(NettyResponseFuture future, Channel channel) { + 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 channelInactive do its work + if (!Channels.isChannelValid(channel)) + return; - boolean webSocket = HttpUtil.isWebSocket(uri.getScheme()); - if (webSocket && !m.equals(HttpMethod.CONNECT)) { - nettyRequestHeaders.add(HttpHeaders.Names.UPGRADE, HttpHeaders.Values.WEBSOCKET); - nettyRequestHeaders.add(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.UPGRADE); - nettyRequestHeaders.add(HttpHeaders.Names.ORIGIN, "http://" + uri.getHost() + ":" + uri.getPort()); - nettyRequestHeaders.add(HttpHeaders.Names.SEC_WEBSOCKET_KEY, WebSocketUtil.getKey()); - nettyRequestHeaders.add(HttpHeaders.Names.SEC_WEBSOCKET_VERSION, "13"); - } + NettyRequest nettyRequest = future.getNettyRequest(); + HttpRequest httpRequest = nettyRequest.getHttpRequest(); + AsyncHandler handler = future.getAsyncHandler(); - String host = request.getVirtualHost() != null ? request.getVirtualHost() : uri.getHost(); - String hostHeader = request.getVirtualHost() != null || uri.getPort() == -1 ? host : host + ":" + uri.getPort(); - nettyRequestHeaders.set(HttpHeaders.Names.HOST, hostHeader); + if (handler instanceof TransferCompletionHandler) + configureTransferAdapter(handler, httpRequest); - if (!m.equals(HttpMethod.CONNECT)) { - for (Entry> header : request.getHeaders()) { - String name = header.getKey(); - if (!HttpHeaders.Names.HOST.equalsIgnoreCase(name)) { - for (String value : header.getValue()) { - nettyRequestHeaders.add(name, value); + if (!future.isHeadersAlreadyWrittenOnContinue()) { + try { + if (future.getAsyncHandler() instanceof AsyncHandlerExtensions) { + AsyncHandlerExtensions.class.cast(future.getAsyncHandler()).onRequestSent(); } - } - } - - if (config.isCompressionEnabled()) { - nettyRequestHeaders.set(HttpHeaders.Names.ACCEPT_ENCODING, GZIP_DEFLATE); - } - } else { - List auth = request.getHeaders().get(HttpHeaders.Names.PROXY_AUTHORIZATION); - if (HttpUtil.isNTLM(auth)) { - nettyRequestHeaders.add(HttpHeaders.Names.PROXY_AUTHORIZATION, auth.get(0)); - } - } - Realm realm = request.getRealm() != null ? request.getRealm() : config.getRealm(); - - if (realm != null && realm.getUsePreemptiveAuth()) { - - String domain = realm.getNtlmDomain(); - if (proxyServer != null && proxyServer.getNtlmDomain() != null) { - domain = proxyServer.getNtlmDomain(); - } - - String authHost = realm.getNtlmHost(); - if (proxyServer != null && proxyServer.getHost() != null) { - host = proxyServer.getHost(); - } - - switch (realm.getAuthScheme()) { - case BASIC: - nettyRequestHeaders.add(HttpHeaders.Names.AUTHORIZATION, AuthenticatorUtils.computeBasicAuthentication(realm)); - break; - case DIGEST: - if (isNonEmpty(realm.getNonce())) { + channel.write(httpRequest).addListener(new ProgressListener(config, future.getAsyncHandler(), future, true)); + } catch (Throwable cause) { + // FIXME why not notify? + LOGGER.debug(cause.getMessage(), cause); try { - nettyRequestHeaders.add(HttpHeaders.Names.AUTHORIZATION, AuthenticatorUtils.computeDigestAuthentication(realm)); - } catch (NoSuchAlgorithmException e) { - throw new SecurityException(e); + channel.close(); + } catch (RuntimeException ex) { + LOGGER.debug(ex.getMessage(), ex); } + return; } - break; - case NTLM: - try { - nettyRequestHeaders.add(HttpHeaders.Names.AUTHORIZATION, NTLMEngine.INSTANCE.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 = SpnegoEngine.INSTANCE.generateToken(server); - } catch (Throwable e) { - IOException ie = new IOException(); - ie.initCause(e); - throw ie; - } - nettyRequestHeaders.add(HttpHeaders.Names.AUTHORIZATION, "Negotiate " + challengeHeader); - break; - case NONE: - break; - default: - throw new IllegalStateException(String.format("Invalid Authentication %s", realm.toString())); } - } - - if (!webSocket && !request.getHeaders().containsKey(HttpHeaders.Names.CONNECTION)) { - nettyRequestHeaders.set(HttpHeaders.Names.CONNECTION, AsyncHttpProviderUtils.keepAliveHeaderValue(config)); - } - if (proxyServer != null) { - if (!request.getHeaders().containsKey("Proxy-Connection")) { - nettyRequestHeaders.set("Proxy-Connection", AsyncHttpProviderUtils.keepAliveHeaderValue(config)); - } + if (!future.isDontWriteBodyBecauseExpectContinue() && !httpRequest.getMethod().equals(HttpMethod.CONNECT) + && nettyRequest.getBody() != null) + nettyRequest.getBody().write(channel, future, config); - if (proxyServer.getPrincipal() != null) { - if (isNonEmpty(proxyServer.getNtlmDomain())) { - - List auth = request.getHeaders().get(HttpHeaders.Names.PROXY_AUTHORIZATION); - if (!HttpUtil.isNTLM(auth)) { - try { - String msg = NTLMEngine.INSTANCE.generateType1Msg(proxyServer.getNtlmDomain(), proxyServer.getHost()); - nettyRequestHeaders.set(HttpHeaders.Names.PROXY_AUTHORIZATION, "NTLM " + msg); - } catch (NTLMEngineException e) { - IOException ie = new IOException(); - ie.initCause(e); - throw ie; - } - } - } else { - nettyRequestHeaders.set(HttpHeaders.Names.PROXY_AUTHORIZATION, - AuthenticatorUtils.computeBasicAuthentication(proxyServer)); - } + } catch (Throwable ioe) { + try { + channel.close(); + } catch (RuntimeException ex) { + LOGGER.debug(ex.getMessage(), ex); } } - // Add default accept headers. - if (!request.getHeaders().containsKey(HttpHeaders.Names.ACCEPT)) { - nettyRequestHeaders.set(HttpHeaders.Names.ACCEPT, "*/*"); - } - - String userAgentHeader = request.getHeaders().getFirstValue(HttpHeaders.Names.USER_AGENT); - if (userAgentHeader != null) { - nettyRequestHeaders.set(HttpHeaders.Names.USER_AGENT, userAgentHeader); - } else if (config.getUserAgent() != null) { - nettyRequestHeaders.set(HttpHeaders.Names.USER_AGENT, config.getUserAgent()); - } else { - nettyRequestHeaders.set(HttpHeaders.Names.USER_AGENT, AsyncHttpProviderUtils.constructUserAgent(NettyAsyncHttpProvider.class)); - } - - if (!m.equals(HttpMethod.CONNECT)) { - if (isNonEmpty(request.getCookies())) { - nettyRequestHeaders.set(HttpHeaders.Names.COOKIE, CookieEncoder.encode(request.getCookies())); - } - - Charset bodyCharset = request.getBodyEncoding() == null ? DEFAULT_CHARSET : Charset.forName(request.getBodyEncoding()); - - // We already have processed the body. - if (buffer != null && buffer.writerIndex() != 0) { - nettyRequestHeaders.set(HttpHeaders.Names.CONTENT_LENGTH, buffer.writerIndex()); - nettyRequest.setContent(buffer); - - } else if (request.getByteData() != null) { - nettyRequestHeaders.set(HttpHeaders.Names.CONTENT_LENGTH, String.valueOf(request.getByteData().length)); - nettyRequest.setContent(ChannelBuffers.wrappedBuffer(request.getByteData())); - - } else if (request.getStringData() != null) { - byte[] bytes = request.getStringData().getBytes(bodyCharset); - nettyRequestHeaders.set(HttpHeaders.Names.CONTENT_LENGTH, String.valueOf(bytes.length)); - nettyRequest.setContent(ChannelBuffers.wrappedBuffer(bytes)); - - } else if (isNonEmpty(request.getFormParams())) { - String formBody = AsyncHttpProviderUtils.formParams2UTF8String(request.getFormParams()); - nettyRequestHeaders.set(HttpHeaders.Names.CONTENT_LENGTH, String.valueOf(formBody.length())); - nettyRequest.setContent(ChannelBuffers.wrappedBuffer(formBody.getBytes(bodyCharset))); - - if (!request.getHeaders().containsKey(HttpHeaders.Names.CONTENT_TYPE)) { - nettyRequestHeaders.set(HttpHeaders.Names.CONTENT_TYPE, HttpHeaders.Values.APPLICATION_X_WWW_FORM_URLENCODED); - } - - } else if (isNonEmpty(request.getParts())) { - MultipartRequestEntity mre = AsyncHttpProviderUtils.createMultipartRequestEntity(request.getParts(), request.getHeaders()); - - nettyRequestHeaders.set(HttpHeaders.Names.CONTENT_TYPE, mre.getContentType()); - long contentLength = mre.getContentLength(); - if (contentLength >= 0) { - nettyRequestHeaders.set(HttpHeaders.Names.CONTENT_LENGTH, String.valueOf(contentLength)); - } - - } else if (request.getFile() != null) { - File file = request.getFile(); - if (!file.isFile()) { - throw new IOException(String.format("File %s is not a file or doesn't exist", file.getAbsolutePath())); - } - nettyRequestHeaders.set(HttpHeaders.Names.CONTENT_LENGTH, file.length()); - } - } - return nettyRequest; + scheduleTimeouts(future); } - private final HttpRequest buildRequest(AsyncHttpClientConfig config, Request request, UriComponents uri, boolean allowConnect, - ChannelBuffer buffer, ProxyServer proxyServer) throws IOException { + private InetSocketAddress remoteAddress(Request request, UriComponents uri, ProxyServer proxy, boolean useProxy) { + if (request.getInetAddress() != null) + return new InetSocketAddress(request.getInetAddress(), getDefaultPort(uri)); - String method = request.getMethod(); - if (allowConnect && proxyServer != null && HttpUtil.isSecure(uri)) { - method = HttpMethod.CONNECT.toString(); - } - return construct(config, request, new HttpMethod(method), uri, buffer, proxyServer); - } + else if (!useProxy || avoidProxy(proxy, uri.getHost())) + return new InetSocketAddress(uri.getHost(), getDefaultPort(uri)); - private NettyResponseFuture buildConnectListenerFuture(AsyncHttpClientConfig config,// - Request request,// - AsyncHandler asyncHandler,// - NettyResponseFuture future,// - ChannelBuffer buffer,// - UriComponents uri) throws IOException { - ProxyServer proxyServer = ProxyUtils.getProxyServer(config, request); - HttpRequest nettyRequest = buildRequest(config, request, uri, true, buffer, proxyServer); - if (future == null) { - return newFuture(uri, request, asyncHandler, nettyRequest, config, proxyServer); - } else { - future.setNettyRequest(nettyRequest); - future.setRequest(request); - return future; - } + else + return new InetSocketAddress(proxy.getHost(), proxy.getPort()); } - public ListenableFuture doConnect(final Request request, final AsyncHandler asyncHandler, NettyResponseFuture f, - boolean useCache, boolean reclaimCache) throws IOException { - - if (isClosed()) { - throw new IOException("Closed"); - } - - UriComponents uri = request.getURI(); - - if (uri.getScheme().startsWith(HttpUtil.WEBSOCKET) && !channelManager.validateWebSocketRequest(request, asyncHandler)) - throw new IOException("WebSocket method must be a GET"); - - ProxyServer proxyServer = ProxyUtils.getProxyServer(config, request); - - boolean resultOfAConnect = f != null && f.getNettyRequest() != null && f.getNettyRequest().getMethod().equals(HttpMethod.CONNECT); - boolean useProxy = proxyServer != null && !resultOfAConnect; - - ChannelBuffer bufferedBytes = null; - if (f != null && f.getRequest().getFile() == null - && !f.getNettyRequest().getMethod().getName().equals(HttpMethod.CONNECT.getName())) { - bufferedBytes = f.getNettyRequest().getContent(); - } - - boolean useSSl = HttpUtil.isSecure(uri) && !useProxy; - - if (useCache) { - // 3 tentatives - NettyResponseFuture connectedFuture = buildNettyResponseFutureWithCachedChannel(request, asyncHandler, f, proxyServer, uri, - bufferedBytes, 3); - - if (connectedFuture != null) { - LOGGER.debug("\nUsing cached Channel {}\n for request \n{}\n", connectedFuture.channel(), connectedFuture.getNettyRequest()); - - try { - writeRequest(connectedFuture.channel(), config, connectedFuture); - } catch (Exception ex) { - LOGGER.debug("writeRequest failure", ex); - if (useSSl && ex.getMessage() != null && ex.getMessage().contains("SSLEngine")) { - LOGGER.debug("SSLEngine failure", ex); - connectedFuture = null; - } else { - try { - asyncHandler.onThrowable(ex); - } catch (Throwable t) { - LOGGER.warn("doConnect.writeRequest()", t); - } - IOException ioe = new IOException(ex.getMessage()); - ioe.initCause(ex); - throw ioe; - } - } - return connectedFuture; - } - } - - NettyResponseFuture connectListenerFuture = buildConnectListenerFuture(config, request, asyncHandler, f, bufferedBytes, uri); - - boolean channelPreempted = false; - String poolKey = null; - - // Do not throw an exception when we need an extra connection for a redirect. - if (!reclaimCache) { + private ChannelFuture connect(Request request, UriComponents uri, ProxyServer proxy, boolean useProxy, ClientBootstrap bootstrap) { + InetSocketAddress remoteAddress = remoteAddress(request, uri, proxy, useProxy); - // only compute when maxConnectionPerHost is enabled - // FIXME clean up - if (config.getMaxConnectionsPerHost() > 0) - poolKey = channelManager.getPoolKey(connectListenerFuture); + if (request.getLocalAddress() != null) + return bootstrap.connect(remoteAddress, new InetSocketAddress(request.getLocalAddress(), 0)); + else + return bootstrap.connect(remoteAddress); + } - if (channelManager.preemptChannel(poolKey)) { - channelPreempted = true; - } else { - IOException ex = new IOException(String.format("Too many connections %s", config.getMaxConnections())); - try { - asyncHandler.onThrowable(ex); - } catch (Exception e) { - LOGGER.warn("asyncHandler.onThrowable crashed", e); - } - throw ex; - } + private void configureTransferAdapter(AsyncHandler handler, HttpRequest httpRequest) { + FluentCaseInsensitiveStringsMap h = new FluentCaseInsensitiveStringsMap(); + for (Map.Entry entries : httpRequest.headers()) { + h.add(entries.getKey(), entries.getValue()); } - NettyConnectListener connectListener = new NettyConnectListener(config, connectListenerFuture, this, channelManager, - channelPreempted, poolKey); + TransferCompletionHandler.class.cast(handler).headers(h); + } - ChannelFuture channelFuture; - ClientBootstrap bootstrap = channelManager.getBootstrap(request.getURI().getScheme(), useProxy, useSSl); + private void scheduleTimeouts(NettyResponseFuture nettyResponseFuture) { try { - InetSocketAddress remoteAddress; - if (request.getInetAddress() != null) { - remoteAddress = new InetSocketAddress(request.getInetAddress(), AsyncHttpProviderUtils.getDefaultPort(uri)); - } else if (!useProxy) { - remoteAddress = new InetSocketAddress(uri.getHost(), AsyncHttpProviderUtils.getDefaultPort(uri)); - } else { - remoteAddress = new InetSocketAddress(proxyServer.getHost(), proxyServer.getPort()); + nettyResponseFuture.touch(); + int requestTimeoutInMs = requestTimeout(config, nettyResponseFuture.getRequest()); + TimeoutsHolder timeoutsHolder = new TimeoutsHolder(); + if (requestTimeoutInMs != -1) { + Timeout requestTimeout = newTimeout(new RequestTimeoutTimerTask(nettyResponseFuture, this, timeoutsHolder, + requestTimeoutInMs), requestTimeoutInMs); + timeoutsHolder.requestTimeout = requestTimeout; } - if (request.getLocalAddress() != null) { - channelFuture = bootstrap.connect(remoteAddress, new InetSocketAddress(request.getLocalAddress(), 0)); - } else { - channelFuture = bootstrap.connect(remoteAddress); + int readTimeout = config.getReadTimeout(); + if (readTimeout != -1 && readTimeout < requestTimeoutInMs) { + // no need for a idleConnectionTimeout that's less than the + // requestTimeoutInMs + Timeout idleConnectionTimeout = newTimeout(new ReadTimeoutTimerTask(nettyResponseFuture, this, timeoutsHolder, + requestTimeoutInMs, readTimeout), readTimeout); + timeoutsHolder.readTimeout = idleConnectionTimeout; } - - channelFuture.addListener(connectListener); - - } catch (Throwable t) { - if (channelPreempted) - channelManager.abortChannelPreemption(poolKey); - abort(connectListener.future(), t.getCause() == null ? t : t.getCause()); + nettyResponseFuture.setTimeoutsHolder(timeoutsHolder); + } catch (RejectedExecutionException ex) { + abort(nettyResponseFuture, ex); } - - return connectListener.future(); } - private static class NettyTransferAdapter extends TransferCompletionHandler.TransferAdapter { + public Timeout newTimeout(TimerTask task, long delay) { + return nettyTimer.newTimeout(task, delay, TimeUnit.MILLISECONDS); + } - private final ChannelBuffer content; - private final FileInputStream file; - private int byteRead = 0; + public void abort(NettyResponseFuture future, Throwable t) { + Channel channel = future.channel(); + if (channel != null) + channelManager.closeChannel(channel); - public NettyTransferAdapter(FluentCaseInsensitiveStringsMap headers, ChannelBuffer content, File file) throws IOException { - super(headers); - this.content = content; - if (file != null) { - this.file = new FileInputStream(file); - } else { - this.file = null; - } + if (!future.isDone()) { + LOGGER.debug("Aborting Future {}\n", future); + LOGGER.debug(t.getMessage(), t); } - @Override - public void getBytes(byte[] bytes) { - if (content.writableBytes() != 0) { - content.getBytes(byteRead, bytes); - byteRead += bytes.length; - } else if (file != null) { - try { - byteRead += file.read(bytes); - } catch (IOException e) { - LOGGER.error(e.getMessage(), e); - } - } - } + future.abort(t); } - public boolean retry(Channel channel, NettyResponseFuture future) { + public boolean retry(NettyResponseFuture future, Channel channel) { if (isClosed()) return false; + // FIXME this was done in AHC2, is this a bug? + // channelManager.removeAll(channel); + if (future == null) { Object attachment = Channels.getAttachment(channel); if (attachment instanceof NettyResponseFuture) future = (NettyResponseFuture) attachment; } - if (future != null && future.canBeReplay()) { + if (future != null && future.canBeReplayed()) { future.setState(NettyResponseFuture.STATE.RECONNECTED); LOGGER.debug("Trying to recover request {}\n", future.getNettyRequest()); @@ -788,7 +429,7 @@ public boolean retry(Channel channel, NettyResponseFuture future) { AsyncHandlerExtensions.class.cast(future.getAsyncHandler()).onRetry(); try { - nextRequest(future.getRequest(), future); + sendNextRequest(future.getRequest(), future); return true; } catch (IOException iox) { @@ -804,33 +445,88 @@ public boolean retry(Channel channel, NettyResponseFuture future) { } } - public final Callback newDrainCallable(final NettyResponseFuture future, final Channel channel, final boolean keepAlive, - final String poolKey) { + public boolean applyIoExceptionFiltersAndReplayRequest(NettyResponseFuture future, IOException e, Channel channel) + throws IOException { + + boolean replayed = false; + + FilterContext fc = new FilterContext.FilterContextBuilder().asyncHandler(future.getAsyncHandler()).request(future.getRequest()) + .ioException(e).build(); + for (IOExceptionFilter asyncFilter : config.getIOExceptionFilters()) { + try { + fc = asyncFilter.filter(fc); + if (fc == null) { + throw new NullPointerException("FilterContext is null"); + } + } catch (FilterException efe) { + abort(future, efe); + } + } + + if (fc.replayRequest() && future.canBeReplayed()) { + replayRequest(future, fc, channel); + replayed = true; + } + return replayed; + } + + public void sendNextRequest(final Request request, final NettyResponseFuture future) throws IOException { + sendRequest(request, future.getAsyncHandler(), future, true); + } + + private boolean validateWebSocketRequest(Request request, AsyncHandler asyncHandler) { + return request.getMethod().equals(HttpMethod.GET.getName()) && asyncHandler instanceof WebSocketUpgradeHandler; + } + + public Channel pollAndVerifyCachedChannel(UriComponents uri, ProxyServer proxy, ConnectionPoolKeyStrategy connectionPoolKeyStrategy) { + final Channel channel = channelManager.poll(connectionPoolKeyStrategy.getKey(uri, proxy)); + + if (channel != null) { + LOGGER.debug("Using cached Channel {}\n for uri {}\n", channel, uri); - return new Callback(future) { - public void call() throws Exception { - channelManager.tryToOfferChannelToPool(channel, keepAlive, poolKey); + try { + // Always make sure the channel who got cached support the proper protocol. It could + // only occurs when a HttpMethod.CONNECT is used against a proxy that requires upgrading from http to + // https. + channelManager.verifyChannelPipeline(channel.getPipeline(), uri.getScheme()); + } catch (Exception ex) { + LOGGER.debug(ex.getMessage(), ex); } - }; + } + return channel; } - public void drainChannel(final Channel channel, final NettyResponseFuture future) { - Channels.setAttachment(channel, newDrainCallable(future, channel, future.isKeepAlive(), channelManager.getPoolKey(future))); + public boolean preemptChannel(AsyncHandler asyncHandler, String poolKey) throws IOException { + + boolean channelPreempted = false; + if (channelManager.preemptChannel(poolKey)) { + channelPreempted = true; + } else { + IOException ex = new IOException(String.format("Too many connections %s", config.getMaxConnections())); + try { + asyncHandler.onThrowable(ex); + } catch (Exception e) { + LOGGER.warn("asyncHandler.onThrowable crashed", e); + } + throw ex; + } + return channelPreempted; } @SuppressWarnings({ "rawtypes", "unchecked" }) public void replayRequest(final NettyResponseFuture future, FilterContext fc, Channel channel) throws IOException { - if (future.getAsyncHandler() instanceof AsyncHandlerExtensions) { - AsyncHandlerExtensions.class.cast(future.getAsyncHandler()).onRetry(); - } + final Request newRequest = fc.getRequest(); future.setAsyncHandler(fc.getAsyncHandler()); future.setState(NettyResponseFuture.STATE.NEW); future.touch(); LOGGER.debug("\n\nReplaying Request {}\n for Future {}\n", newRequest, future); - drainChannel(channel, future); - nextRequest(newRequest, future); + if (future.getAsyncHandler() instanceof AsyncHandlerExtensions) + AsyncHandlerExtensions.class.cast(future.getAsyncHandler()).onRetry(); + + channelManager.drainChannel(channel, future); + sendNextRequest(newRequest, future); return; } diff --git a/src/main/java/com/ning/http/client/providers/netty/request/ProgressListener.java b/src/main/java/com/ning/http/client/providers/netty/request/ProgressListener.java index 189d8b5ffd..32d3c1c61d 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/ProgressListener.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/ProgressListener.java @@ -30,17 +30,20 @@ public class ProgressListener implements ChannelFutureProgressListener { private static final Logger LOGGER = LoggerFactory.getLogger(ProgressListener.class); - + private final AsyncHttpClientConfig config; private final boolean notifyHeaders; private final AsyncHandler asyncHandler; private final NettyResponseFuture future; - public ProgressListener(AsyncHttpClientConfig config, boolean notifyHeaders, AsyncHandler asyncHandler, NettyResponseFuture future) { + public ProgressListener(AsyncHttpClientConfig config,// + AsyncHandler asyncHandler,// + NettyResponseFuture future,// + boolean notifyHeaders) { this.config = config; - this.notifyHeaders = notifyHeaders; this.asyncHandler = asyncHandler; this.future = future; + this.notifyHeaders = notifyHeaders; } public void operationComplete(ChannelFuture cf) { diff --git a/src/main/java/com/ning/http/client/providers/netty/request/body/BodyChunkedInput.java b/src/main/java/com/ning/http/client/providers/netty/request/body/BodyChunkedInput.java index 22c32bf198..3dd1c1b5b4 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/body/BodyChunkedInput.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/body/BodyChunkedInput.java @@ -1,9 +1,10 @@ /* - * Copyright (c) 2010-2012 Sonatype, Inc. All rights reserved. + * Copyright (c) 2014 AsyncHttpClient Project. 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. + * 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 diff --git a/src/main/java/com/ning/http/client/providers/netty/request/body/BodyFileRegion.java b/src/main/java/com/ning/http/client/providers/netty/request/body/BodyFileRegion.java index 546e82692e..d32131fca9 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/body/BodyFileRegion.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/body/BodyFileRegion.java @@ -1,9 +1,10 @@ /* - * Copyright (c) 2010-2012 Sonatype, Inc. All rights reserved. + * Copyright (c) 2014 AsyncHttpClient Project. 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. + * 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 diff --git a/src/main/java/com/ning/http/client/providers/netty/request/body/NettyBody.java b/src/main/java/com/ning/http/client/providers/netty/request/body/NettyBody.java new file mode 100644 index 0000000000..7b0a5bd6fb --- /dev/null +++ b/src/main/java/com/ning/http/client/providers/netty/request/body/NettyBody.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2014 AsyncHttpClient Project. 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.providers.netty.request.body; + +import org.jboss.netty.channel.Channel; + +import com.ning.http.client.AsyncHttpClientConfig; +import com.ning.http.client.providers.netty.future.NettyResponseFuture; + +import java.io.IOException; + +public interface NettyBody { + + long getContentLength(); + + String getContentType(); + + void write(Channel channel, NettyResponseFuture future, AsyncHttpClientConfig config) throws IOException; +} diff --git a/src/main/java/com/ning/http/client/providers/netty/request/body/NettyBodyBody.java b/src/main/java/com/ning/http/client/providers/netty/request/body/NettyBodyBody.java new file mode 100644 index 0000000000..523cf6e858 --- /dev/null +++ b/src/main/java/com/ning/http/client/providers/netty/request/body/NettyBodyBody.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2014 AsyncHttpClient Project. 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.providers.netty.request.body; + +import org.jboss.netty.channel.Channel; +import org.jboss.netty.channel.ChannelFuture; +import org.jboss.netty.handler.ssl.SslHandler; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.ning.http.client.AsyncHttpClientConfig; +import com.ning.http.client.Body; +import com.ning.http.client.RandomAccessBody; +import com.ning.http.client.providers.netty.NettyAsyncHttpProviderConfig; +import com.ning.http.client.providers.netty.future.NettyResponseFuture; +import com.ning.http.client.providers.netty.request.ProgressListener; + +import java.io.IOException; + +public class NettyBodyBody implements NettyBody { + + private static final Logger LOGGER = LoggerFactory.getLogger(NettyBodyBody.class); + + private final Body body; + private final NettyAsyncHttpProviderConfig nettyConfig; + + public NettyBodyBody(Body body, NettyAsyncHttpProviderConfig nettyConfig) { + this.body = body; + this.nettyConfig = nettyConfig; + } + + public Body getBody() { + return body; + } + + @Override + public long getContentLength() { + return body.getContentLength(); + } + + @Override + public String getContentType() { + return null; + } + + @Override + public void write(final Channel channel, NettyResponseFuture future, AsyncHttpClientConfig config) throws IOException { + + ChannelFuture writeFuture; + boolean ssl = channel.getPipeline().get(SslHandler.class) != null; + if (ssl || !(body instanceof RandomAccessBody) || nettyConfig.isDisableZeroCopy()) { + BodyChunkedInput bodyChunkedInput = new BodyChunkedInput(body); + writeFuture = channel.write(bodyChunkedInput); + } else { + BodyFileRegion bodyFileRegion = new BodyFileRegion((RandomAccessBody) body); + writeFuture = channel.write(bodyFileRegion); + } + writeFuture.addListener(new ProgressListener(config, future.getAsyncHandler(), future, false) { + public void operationComplete(ChannelFuture cf) { + try { + body.close(); + } catch (IOException e) { + LOGGER.warn("Failed to close request body: {}", e.getMessage(), e); + } + super.operationComplete(cf); + } + }); + } +} diff --git a/src/main/java/com/ning/http/client/providers/netty/request/body/NettyByteArrayBody.java b/src/main/java/com/ning/http/client/providers/netty/request/body/NettyByteArrayBody.java new file mode 100644 index 0000000000..78127d94f6 --- /dev/null +++ b/src/main/java/com/ning/http/client/providers/netty/request/body/NettyByteArrayBody.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2014 AsyncHttpClient Project. 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.providers.netty.request.body; + +import org.jboss.netty.channel.Channel; + +import com.ning.http.client.AsyncHttpClientConfig; +import com.ning.http.client.providers.netty.future.NettyResponseFuture; + +import java.io.IOException; + +public class NettyByteArrayBody implements NettyBody { + + private final byte[] bytes; + private final String contentType; + + public NettyByteArrayBody(byte[] bytes) { + this(bytes, null); + } + + public NettyByteArrayBody(byte[] bytes, String contentType) { + this.bytes = bytes; + this.contentType = contentType; + } + + public byte[] getBytes() { + return bytes; + } + + @Override + public long getContentLength() { + return bytes.length; + } + + @Override + public String getContentType() { + return contentType; + } + + @Override + public void write(Channel channel, NettyResponseFuture future, AsyncHttpClientConfig config) throws IOException { + throw new UnsupportedOperationException("This kind of body is supposed to be writen directly"); + } +} diff --git a/src/main/java/com/ning/http/client/providers/netty/request/NettyConnectListener.java b/src/main/java/com/ning/http/client/providers/netty/request/body/NettyConnectListener.java similarity index 80% rename from src/main/java/com/ning/http/client/providers/netty/request/NettyConnectListener.java rename to src/main/java/com/ning/http/client/providers/netty/request/body/NettyConnectListener.java index 7774638a6c..d94c415995 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/NettyConnectListener.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/body/NettyConnectListener.java @@ -1,25 +1,21 @@ /* - * Copyright 2010 Ning, Inc. + * Copyright (c) 2014 AsyncHttpClient Project. All rights reserved. * - * 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. + * 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.providers.netty.request; +package com.ning.http.client.providers.netty.request.body; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelFutureListener; -import org.jboss.netty.handler.codec.http.HttpRequest; import org.jboss.netty.handler.ssl.SslHandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -29,6 +25,8 @@ import com.ning.http.client.providers.netty.channel.Channels; import com.ning.http.client.providers.netty.future.NettyResponseFuture; import com.ning.http.client.providers.netty.future.StackTraceInspector; +import com.ning.http.client.providers.netty.request.NettyRequest; +import com.ning.http.client.providers.netty.request.NettyRequestSender; import com.ning.http.util.Base64; import javax.net.ssl.HostnameVerifier; @@ -45,22 +43,22 @@ public final class NettyConnectListener implements ChannelFutureListener { private static final Logger LOGGER = LoggerFactory.getLogger(NettyConnectListener.class); private final AsyncHttpClientConfig config; private final NettyResponseFuture future; - private final HttpRequest nettyRequest; - private final NettyRequestSender nettyRequestSender; + private final NettyRequest nettyRequest; + private final NettyRequestSender requestSender; private final ChannelManager channelManager; private final boolean channelPreempted; private final String poolKey; public NettyConnectListener(AsyncHttpClientConfig config,// NettyResponseFuture future,// - NettyRequestSender nettyRequestSender,// + NettyRequestSender requestSender,// ChannelManager channelManager,// boolean channelPreempted,// String poolKey) { this.config = config; this.future = future; this.nettyRequest = future.getNettyRequest(); - this.nettyRequestSender = nettyRequestSender; + this.requestSender = requestSender; this.channelManager = channelManager; this.channelPreempted = channelPreempted; this.poolKey = poolKey; @@ -86,7 +84,7 @@ private void writeRequest(Channel channel, String poolKey) { channelManager.registerOpenChannel(channel); future.attachChannel(channel, false); - nettyRequestSender.writeRequest(channel, config, future); + requestSender.writeRequest(future, channel); } public final void operationComplete(ChannelFuture f) throws Exception { @@ -134,8 +132,8 @@ public void operationComplete(ChannelFuture handshakeFuture) throws Exception { && cause != null && (cause instanceof ClosedChannelException || future.getState() != NettyResponseFuture.STATE.NEW || StackTraceInspector.abortOnDisconnectException(cause))) { - LOGGER.debug("Retrying {} ", nettyRequest); - if (!nettyRequestSender.retry(channel, future)) + LOGGER.debug("Retrying {} ", nettyRequest.getHttpRequest()); + if (!requestSender.retry(future, channel)) return; } diff --git a/src/main/java/com/ning/http/client/providers/netty/request/body/NettyFileBody.java b/src/main/java/com/ning/http/client/providers/netty/request/body/NettyFileBody.java new file mode 100644 index 0000000000..45d16ddb12 --- /dev/null +++ b/src/main/java/com/ning/http/client/providers/netty/request/body/NettyFileBody.java @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2014 AsyncHttpClient Project. 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.providers.netty.request.body; + +import org.jboss.netty.channel.Channel; +import org.jboss.netty.channel.ChannelFuture; +import org.jboss.netty.channel.FileRegion; +import org.jboss.netty.handler.ssl.SslHandler; +import org.jboss.netty.handler.stream.ChunkedFile; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.ning.http.client.AsyncHttpClientConfig; +import com.ning.http.client.providers.netty.NettyAsyncHttpProviderConfig; +import com.ning.http.client.providers.netty.future.NettyResponseFuture; +import com.ning.http.client.providers.netty.request.ProgressListener; + +import java.io.File; +import java.io.IOException; +import java.io.RandomAccessFile; + +public class NettyFileBody implements NettyBody { + + private static final Logger LOGGER = LoggerFactory.getLogger(NettyFileBody.class); + + public final static int MAX_BUFFERED_BYTES = 8192; + + private final File file; + private final long offset; + private final long length; + private final NettyAsyncHttpProviderConfig nettyConfig; + + public NettyFileBody(File file, NettyAsyncHttpProviderConfig nettyConfig) throws IOException { + this(file, 0, file.length(), nettyConfig); + } + + public NettyFileBody(File file, long offset, long length, NettyAsyncHttpProviderConfig nettyConfig) throws IOException { + if (!file.isFile()) { + throw new IOException(String.format("File %s is not a file or doesn't exist", file.getAbsolutePath())); + } + this.file = file; + this.offset = offset; + this.length = length; + this.nettyConfig = nettyConfig; + } + + public File getFile() { + return file; + } + + public long getOffset() { + return offset; + } + + @Override + public long getContentLength() { + return length; + } + + @Override + public String getContentType() { + return null; + } + + @Override + public void write(Channel channel, NettyResponseFuture future, AsyncHttpClientConfig config) throws IOException { + final RandomAccessFile raf = new RandomAccessFile(file, "r"); + + boolean ssl = channel.getPipeline().get(SslHandler.class) != null; + try { + ChannelFuture writeFuture; + if (ssl || nettyConfig.isDisableZeroCopy()) { + writeFuture = channel.write(new ChunkedFile(raf, 0, raf.length(), nettyConfig.getChunkedFileChunkSize())); + } else { + final FileRegion region = new OptimizedFileRegion(raf, 0, raf.length()); + writeFuture = channel.write(region); + } + writeFuture.addListener(new ProgressListener(config, future.getAsyncHandler(), future, false) { + public void operationComplete(ChannelFuture cf) { + try { + raf.close(); + } catch (IOException e) { + LOGGER.warn("Failed to close request body: {}", e.getMessage(), e); + } + super.operationComplete(cf); + } + }); + } catch (IOException ex) { + if (raf != null) { + try { + raf.close(); + } catch (IOException e) { + } + } + throw ex; + } + } +} diff --git a/src/main/java/com/ning/http/client/providers/netty/request/body/NettyInputStreamBody.java b/src/main/java/com/ning/http/client/providers/netty/request/body/NettyInputStreamBody.java new file mode 100644 index 0000000000..eb00525a17 --- /dev/null +++ b/src/main/java/com/ning/http/client/providers/netty/request/body/NettyInputStreamBody.java @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2014 AsyncHttpClient Project. 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.providers.netty.request.body; + +import org.jboss.netty.channel.Channel; +import org.jboss.netty.channel.ChannelFuture; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.ning.http.client.AsyncHttpClientConfig; +import com.ning.http.client.Body; +import com.ning.http.client.generators.InputStreamBodyGenerator; +import com.ning.http.client.providers.netty.future.NettyResponseFuture; +import com.ning.http.client.providers.netty.request.ProgressListener; + +import java.io.IOException; +import java.io.InputStream; + +public class NettyInputStreamBody implements NettyBody { + + private static final Logger LOGGER = LoggerFactory.getLogger(NettyInputStreamBody.class); + + private final InputStream inputStream; + + public NettyInputStreamBody(InputStream inputStream) { + this.inputStream = inputStream; + } + + public InputStream getInputStream() { + return inputStream; + } + + @Override + public long getContentLength() { + return -1L; + } + + @Override + public String getContentType() { + return null; + } + + @Override + public void write(Channel channel, NettyResponseFuture future, AsyncHttpClientConfig config) throws IOException { + final InputStream is = inputStream; + + if (future.isStreamWasAlreadyConsumed()) { + if (is.markSupported()) + is.reset(); + else { + LOGGER.warn("Stream has already been consumed and cannot be reset"); + return; + } + } else { + future.setStreamWasAlreadyConsumed(true); + } + + InputStreamBodyGenerator generator = new InputStreamBodyGenerator(is); + // FIXME is this still usefull? + generator.patchNettyChunkingIssue(true); + final Body body = generator.createBody(); + channel.write(new BodyChunkedInput(body)).addListener(new ProgressListener(config, future.getAsyncHandler(), future, false) { + public void operationComplete(ChannelFuture cf) { + try { + body.close(); + } catch (IOException e) { + LOGGER.warn("Failed to close request body: {}", e.getMessage(), e); + } + super.operationComplete(cf); + } + }); + + // FIXME ChunkedStream is broken in Netty 3 but fixed in Netty 4 +// channel.write(new ChunkedStream(is)).addListener( +// new ProgressListener(config, future.getAsyncHandler(), future, false) { +// public void operationComplete(ChannelFuture cf) { +// try { +// is.close(); +// } catch (IOException e) { +// LOGGER.warn("Failed to close request body: {}", e.getMessage(), e); +// } +// super.operationComplete(cf); +// } +// }); + } +} diff --git a/src/main/java/com/ning/http/client/providers/netty/request/body/NettyMultipartBody.java b/src/main/java/com/ning/http/client/providers/netty/request/body/NettyMultipartBody.java new file mode 100644 index 0000000000..b319e165dd --- /dev/null +++ b/src/main/java/com/ning/http/client/providers/netty/request/body/NettyMultipartBody.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2014 AsyncHttpClient Project. 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.providers.netty.request.body; + +import com.ning.http.client.FluentCaseInsensitiveStringsMap; +import com.ning.http.client.multipart.MultipartBody; +import com.ning.http.client.multipart.MultipartUtils; +import com.ning.http.client.multipart.Part; +import com.ning.http.client.providers.netty.NettyAsyncHttpProviderConfig; + +import java.util.List; + +public class NettyMultipartBody extends NettyBodyBody { + + private final String contentType; + + public NettyMultipartBody(List parts, FluentCaseInsensitiveStringsMap headers, NettyAsyncHttpProviderConfig nettyConfig) { + this(MultipartUtils.newMultipartBody(parts, headers), nettyConfig); + } + + private NettyMultipartBody(MultipartBody body, NettyAsyncHttpProviderConfig nettyConfig) { + super(body, nettyConfig); + contentType = body.getContentType(); + } + + @Override + public String getContentType() { + return contentType; + } +} diff --git a/src/main/java/com/ning/http/client/providers/netty/request/timeout/ReadTimeoutTimerTask.java b/src/main/java/com/ning/http/client/providers/netty/request/timeout/ReadTimeoutTimerTask.java index 4f6d56d5c9..bdfa842b23 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/timeout/ReadTimeoutTimerTask.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/timeout/ReadTimeoutTimerTask.java @@ -24,16 +24,20 @@ public class ReadTimeoutTimerTask extends TimeoutTimerTask { private final long readTimeout; private final long requestTimeoutInstant; - public ReadTimeoutTimerTask(NettyResponseFuture nettyResponseFuture, NettyRequestSender nettyRequestSender, TimeoutsHolder timeoutsHolder, - long requestTimeout, long readTimeout) { - super(nettyResponseFuture, nettyRequestSender, timeoutsHolder); + public ReadTimeoutTimerTask(// + NettyResponseFuture nettyResponseFuture,// + NettyRequestSender requestSender,// + TimeoutsHolder timeoutsHolder,// + long requestTimeout,// + long readTimeout) { + super(nettyResponseFuture, requestSender, timeoutsHolder); this.readTimeout = readTimeout; requestTimeoutInstant = requestTimeout >= 0 ? nettyResponseFuture.getStart() + requestTimeout : Long.MAX_VALUE; } public void run(Timeout timeout) throws Exception { - if (nettyRequestSender.isClosed() || nettyResponseFuture.isDone()) { + if (requestSender.isClosed() || nettyResponseFuture.isDone()) { timeoutsHolder.cancel(); return; } @@ -51,7 +55,7 @@ public void run(Timeout timeout) throws Exception { } else if (currentReadTimeoutInstant < requestTimeoutInstant) { // reschedule - timeoutsHolder.readTimeout = nettyRequestSender.newTimeout(this, durationBeforeCurrentReadTimeout); + timeoutsHolder.readTimeout = requestSender.newTimeout(this, durationBeforeCurrentReadTimeout); } else { // otherwise, no need to reschedule: requestTimeout will happen sooner diff --git a/src/main/java/com/ning/http/client/providers/netty/request/timeout/RequestTimeoutTimerTask.java b/src/main/java/com/ning/http/client/providers/netty/request/timeout/RequestTimeoutTimerTask.java index 6a4822f555..8129dce9b6 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/timeout/RequestTimeoutTimerTask.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/timeout/RequestTimeoutTimerTask.java @@ -22,9 +22,13 @@ public class RequestTimeoutTimerTask extends TimeoutTimerTask { private final long requestTimeout; - - public RequestTimeoutTimerTask(NettyResponseFuture nettyResponseFuture, NettyRequestSender nettyRequestSender, TimeoutsHolder timeoutsHolder, long requestTimeout) { - super(nettyResponseFuture, nettyRequestSender, timeoutsHolder); + + public RequestTimeoutTimerTask(// + NettyResponseFuture nettyResponseFuture,// + NettyRequestSender requestSender,// + TimeoutsHolder timeoutsHolder,// + long requestTimeout) { + super(nettyResponseFuture, requestSender, timeoutsHolder); this.requestTimeout = requestTimeout; } @@ -33,7 +37,7 @@ public void run(Timeout timeout) throws Exception { // in any case, cancel possible idleConnectionTimeout timeoutsHolder.cancel(); - if (nettyRequestSender.isClosed() || nettyResponseFuture.isDone()) + if (requestSender.isClosed() || nettyResponseFuture.isDone()) return; String message = "Request timed out to " + nettyResponseFuture.getChannelRemoteAddress() + " of " + requestTimeout + " ms"; diff --git a/src/main/java/com/ning/http/client/providers/netty/request/timeout/TimeoutTimerTask.java b/src/main/java/com/ning/http/client/providers/netty/request/timeout/TimeoutTimerTask.java index 3ccfd3e918..bebd559616 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/timeout/TimeoutTimerTask.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/timeout/TimeoutTimerTask.java @@ -26,17 +26,17 @@ public abstract class TimeoutTimerTask implements TimerTask { private static final Logger LOGGER = LoggerFactory.getLogger(TimeoutTimerTask.class); protected final NettyResponseFuture nettyResponseFuture; - protected final NettyRequestSender nettyRequestSender; + protected final NettyRequestSender requestSender; protected final TimeoutsHolder timeoutsHolder; - public TimeoutTimerTask(NettyResponseFuture nettyResponseFuture, NettyRequestSender nettyRequestSender, TimeoutsHolder timeoutsHolder) { + public TimeoutTimerTask(NettyResponseFuture nettyResponseFuture, NettyRequestSender requestSender, TimeoutsHolder timeoutsHolder) { this.nettyResponseFuture = nettyResponseFuture; - this.nettyRequestSender = nettyRequestSender; + this.requestSender = requestSender; this.timeoutsHolder = timeoutsHolder; } protected void expire(String message, long time) { LOGGER.debug("{} for {} after {} ms", message, nettyResponseFuture, time); - nettyRequestSender.abort(nettyResponseFuture, new TimeoutException(message)); + requestSender.abort(nettyResponseFuture, new TimeoutException(message)); } } diff --git a/src/main/java/com/ning/http/client/providers/netty/response/NettyResponse.java b/src/main/java/com/ning/http/client/providers/netty/response/NettyResponse.java index bff1cdf2e4..70d813b677 100644 --- a/src/main/java/com/ning/http/client/providers/netty/response/NettyResponse.java +++ b/src/main/java/com/ning/http/client/providers/netty/response/NettyResponse.java @@ -1,20 +1,19 @@ /* - * Copyright 2010 Ning, Inc. + * Copyright (c) 2014 AsyncHttpClient Project. All rights reserved. * - * 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: + * 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. * - * 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. + * 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.providers.netty.response; +import static com.ning.http.client.providers.netty.util.ChannelBufferUtils.channelBuffer2bytes; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBufferInputStream; @@ -27,13 +26,10 @@ import com.ning.http.client.ResponseBase; import com.ning.http.client.cookie.Cookie; import com.ning.http.client.cookie.CookieDecoder; -import com.ning.http.client.providers.netty.util.ChannelBufferUtil; -import com.ning.http.util.AsyncHttpProviderUtils; import java.io.IOException; import java.io.InputStream; import java.nio.ByteBuffer; -import java.nio.charset.Charset; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -43,16 +39,13 @@ */ public class NettyResponse extends ResponseBase { - public NettyResponse(HttpResponseStatus status, - HttpResponseHeaders headers, - List bodyParts) { - + public NettyResponse(HttpResponseStatus status, HttpResponseHeaders headers, List bodyParts) { super(status, headers, bodyParts); } @Override public byte[] getResponseBodyAsBytes() throws IOException { - return ChannelBufferUtil.channelBuffer2bytes(getResponseBodyAsChannelBuffer()); + return channelBuffer2bytes(getResponseBodyAsChannelBuffer()); } @Override diff --git a/src/main/java/com/ning/http/client/providers/netty/response/ResponseBodyPart.java b/src/main/java/com/ning/http/client/providers/netty/response/ResponseBodyPart.java index ecbb1ea327..f2566d4673 100644 --- a/src/main/java/com/ning/http/client/providers/netty/response/ResponseBodyPart.java +++ b/src/main/java/com/ning/http/client/providers/netty/response/ResponseBodyPart.java @@ -1,27 +1,26 @@ /* - * Copyright 2010 Ning, Inc. + * Copyright (c) 2014 AsyncHttpClient Project. All rights reserved. * - * 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: + * 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. * - * 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. + * 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.providers.netty.response; -import com.ning.http.client.HttpResponseBodyPart; -import com.ning.http.client.providers.netty.util.ChannelBufferUtil; +import static com.ning.http.client.providers.netty.util.ChannelBufferUtils.channelBuffer2bytes; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.handler.codec.http.HttpChunk; import org.jboss.netty.handler.codec.http.HttpResponse; +import com.ning.http.client.HttpResponseBodyPart; + import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; @@ -54,7 +53,7 @@ public ResponseBodyPart(HttpResponse response, HttpChunk chunk, boolean last) { */ public byte[] getBodyPartBytes() { if (bytes == null) - bytes = ChannelBufferUtil.channelBuffer2bytes(content); + bytes = channelBuffer2bytes(content); return bytes; } diff --git a/src/main/java/com/ning/http/client/providers/netty/response/ResponseHeaders.java b/src/main/java/com/ning/http/client/providers/netty/response/ResponseHeaders.java index 597e72c018..8f8cfea1bf 100644 --- a/src/main/java/com/ning/http/client/providers/netty/response/ResponseHeaders.java +++ b/src/main/java/com/ning/http/client/providers/netty/response/ResponseHeaders.java @@ -1,22 +1,19 @@ /* - * Copyright 2010 Ning, Inc. + * Copyright (c) 2014 AsyncHttpClient Project. All rights reserved. * - * 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: + * 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. * - * 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. + * 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.providers.netty.response; -import org.jboss.netty.handler.codec.http.HttpChunkTrailer; -import org.jboss.netty.handler.codec.http.HttpResponse; +import org.jboss.netty.handler.codec.http.HttpHeaders; import com.ning.http.client.FluentCaseInsensitiveStringsMap; import com.ning.http.client.HttpResponseHeaders; @@ -28,32 +25,30 @@ */ public class ResponseHeaders extends HttpResponseHeaders { - private final HttpChunkTrailer trailingHeaders; - private final HttpResponse response; + private final HttpHeaders responseHeaders; + private final HttpHeaders trailingHeaders; private final FluentCaseInsensitiveStringsMap headers; - public ResponseHeaders(HttpResponse response) { - super(false); - this.trailingHeaders = null; - this.response = response; - headers = computerHeaders(); + // FIXME unused AsyncHttpProvider provider + public ResponseHeaders(HttpHeaders responseHeaders) { + this(responseHeaders, null); } - public ResponseHeaders(HttpResponse response, HttpChunkTrailer traillingHeaders) { - super(true); + public ResponseHeaders(HttpHeaders responseHeaders, HttpHeaders traillingHeaders) { + super(traillingHeaders != null); + this.responseHeaders = responseHeaders; this.trailingHeaders = traillingHeaders; - this.response = response; headers = computerHeaders(); } private FluentCaseInsensitiveStringsMap computerHeaders() { FluentCaseInsensitiveStringsMap h = new FluentCaseInsensitiveStringsMap(); - for (Map.Entry header : response.headers()) { + for (Map.Entry header : responseHeaders) { h.add(header.getKey(), header.getValue()); } if (trailingHeaders != null) { - for (Map.Entry header : trailingHeaders.trailingHeaders()) { + for (Map.Entry header : trailingHeaders) { h.add(header.getKey(), header.getValue()); } } @@ -63,8 +58,8 @@ private FluentCaseInsensitiveStringsMap computerHeaders() { /** * Return the HTTP header - * - * @return an {@link com.ning.http.client.FluentCaseInsensitiveStringsMap} + * + * @return an {@link org.asynchttpclient.FluentCaseInsensitiveStringsMap} */ @Override public FluentCaseInsensitiveStringsMap getHeaders() { diff --git a/src/main/java/com/ning/http/client/providers/netty/response/ResponseStatus.java b/src/main/java/com/ning/http/client/providers/netty/response/ResponseStatus.java index 075b7bc3bb..a0c742ad4c 100644 --- a/src/main/java/com/ning/http/client/providers/netty/response/ResponseStatus.java +++ b/src/main/java/com/ning/http/client/providers/netty/response/ResponseStatus.java @@ -1,18 +1,15 @@ /* - * Copyright 2010 Ning, Inc. + * Copyright (c) 2014 AsyncHttpClient Project. All rights reserved. * - * 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. + * 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.providers.netty.response; diff --git a/src/main/java/com/ning/http/client/providers/netty/util/ChannelBufferUtil.java b/src/main/java/com/ning/http/client/providers/netty/util/ChannelBufferUtil.java deleted file mode 100644 index d86d7f96ba..0000000000 --- a/src/main/java/com/ning/http/client/providers/netty/util/ChannelBufferUtil.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * 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.util; - -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/util/ChannelBufferUtils.java b/src/main/java/com/ning/http/client/providers/netty/util/ChannelBufferUtils.java new file mode 100644 index 0000000000..1bbd3c8678 --- /dev/null +++ b/src/main/java/com/ning/http/client/providers/netty/util/ChannelBufferUtils.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2014 AsyncHttpClient Project. 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.providers.netty.util; + +import org.jboss.netty.buffer.ChannelBuffer; + +public class ChannelBufferUtils { + + 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/util/HttpUtil.java b/src/main/java/com/ning/http/client/providers/netty/util/HttpUtils.java similarity index 64% rename from src/main/java/com/ning/http/client/providers/netty/util/HttpUtil.java rename to src/main/java/com/ning/http/client/providers/netty/util/HttpUtils.java index d52ab8966d..67d08fe3a3 100644 --- a/src/main/java/com/ning/http/client/providers/netty/util/HttpUtil.java +++ b/src/main/java/com/ning/http/client/providers/netty/util/HttpUtils.java @@ -1,3 +1,16 @@ +/* + * Copyright (c) 2014 AsyncHttpClient Project. 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.providers.netty.util; import static com.ning.http.util.MiscUtils.isNonEmpty; @@ -10,14 +23,14 @@ import java.util.List; import java.util.Map.Entry; -public final class HttpUtil { +public final class HttpUtils { public static final String HTTP = "http"; public static final String HTTPS = "https"; public static final String WEBSOCKET = "ws"; public static final String WEBSOCKET_SSL = "wss"; - private HttpUtil() { + private HttpUtils() { } public static boolean isNTLM(List auth) { diff --git a/src/main/java/com/ning/http/client/providers/netty/ws/NettyWebSocket.java b/src/main/java/com/ning/http/client/providers/netty/ws/NettyWebSocket.java index 3ff9f8ff6a..2fd03e2cba 100644 --- a/src/main/java/com/ning/http/client/providers/netty/ws/NettyWebSocket.java +++ b/src/main/java/com/ning/http/client/providers/netty/ws/NettyWebSocket.java @@ -1,9 +1,10 @@ /* - * Copyright (c) 2010-2012 Sonatype, Inc. All rights reserved. + * Copyright (c) 2014 AsyncHttpClient Project. 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. + * 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 diff --git a/src/main/java/com/ning/http/client/providers/netty/ws/WebSocketUtil.java b/src/main/java/com/ning/http/client/providers/netty/ws/WebSocketUtils.java similarity index 91% rename from src/main/java/com/ning/http/client/providers/netty/ws/WebSocketUtil.java rename to src/main/java/com/ning/http/client/providers/netty/ws/WebSocketUtils.java index 90bd48269a..f5d3fe923e 100644 --- a/src/main/java/com/ning/http/client/providers/netty/ws/WebSocketUtil.java +++ b/src/main/java/com/ning/http/client/providers/netty/ws/WebSocketUtils.java @@ -1,9 +1,10 @@ /* - * Copyright (c) 2010-2012 Sonatype, Inc. All rights reserved. + * Copyright (c) 2014 AsyncHttpClient Project. 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. + * 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 @@ -18,7 +19,7 @@ import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; -public final class WebSocketUtil { +public final class WebSocketUtils { public static final String MAGIC_GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; public static String getKey() { diff --git a/src/main/java/com/ning/http/multipart/ByteArrayPartSource.java b/src/main/java/com/ning/http/multipart/ByteArrayPartSource.java deleted file mode 100644 index a50f6ff490..0000000000 --- a/src/main/java/com/ning/http/multipart/ByteArrayPartSource.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * 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.multipart; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; - -/** - * This class is an adaptation of the Apache HttpClient implementation - * - * @link http://hc.apache.org/httpclient-3.x/ - */ -public class ByteArrayPartSource implements PartSource { - - /** - * Name of the source file. - */ - private final String fileName; - - /** - * Byte array of the source file. - */ - private final byte[] bytes; - - /** - * Constructor for ByteArrayPartSource. - * - * @param fileName the name of the file these bytes represent - * @param bytes the content of this part - */ - public ByteArrayPartSource(String fileName, byte[] bytes) { - this.fileName = fileName; - this.bytes = bytes; - } - - /** - * @see PartSource#getLength() - */ - public long getLength() { - return bytes.length; - } - - /** - * @see PartSource#getFileName() - */ - public String getFileName() { - return fileName; - } - - /** - * @see PartSource#createInputStream() - */ - public InputStream createInputStream() throws IOException { - return new ByteArrayInputStream(bytes); - } - - public byte[] getBytes() { - return bytes; - } -} diff --git a/src/main/java/com/ning/http/multipart/FilePart.java b/src/main/java/com/ning/http/multipart/FilePart.java deleted file mode 100644 index aef2c64c8d..0000000000 --- a/src/main/java/com/ning/http/multipart/FilePart.java +++ /dev/null @@ -1,221 +0,0 @@ -/* - * 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.multipart; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - -/** - * This class is an adaptation of the Apache HttpClient implementation - * - * @link http://hc.apache.org/httpclient-3.x/ - */ -public class FilePart extends PartBase { - - /** - * Default content encoding of file attachments. - */ - public static final String DEFAULT_CONTENT_TYPE = "application/octet-stream"; - - /** - * Default transfer encoding of file attachments. - */ - public static final String DEFAULT_TRANSFER_ENCODING = "binary"; - - /** - * Attachment's file name - */ - protected static final String FILE_NAME = "; filename="; - - /** - * Attachment's file name as a byte array - */ - private static final byte[] FILE_NAME_BYTES = MultipartEncodingUtil.getAsciiBytes(FILE_NAME); - - /** - * Source of the file part. - */ - 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 - */ - public FilePart(String name, PartSource partSource, String contentType, String charset, String contentId) { - - super(name, contentType == null ? DEFAULT_CONTENT_TYPE : contentType, charset, DEFAULT_TRANSFER_ENCODING, contentId); - if (partSource == null) - throw new NullPointerException("parSource"); - 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 partSource the source for this part - */ - public FilePart(String name, PartSource partSource) { - this(name, partSource, null, null); - } - - /** - * 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. - */ - 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 { - this(name, new FilePartSource(file), contentType, charset); - } - - /** - * FilePart Constructor. - * - * @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. - */ - 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 { - 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 { - String filename = this.source.getFileName(); - super.sendDispositionHeader(out); - if (filename != null) { - out.write(FILE_NAME_BYTES); - out.write(QUOTE_BYTES); - out.write(MultipartEncodingUtil.getAsciiBytes(filename)); - out.write(QUOTE_BYTES); - } - } - - protected long dispositionHeaderLength() { - String filename = this.source.getFileName(); - long length = super.dispositionHeaderLength(); - if (filename != null) { - length += FILE_NAME_BYTES.length; - length += QUOTE_BYTES.length; - length += MultipartEncodingUtil.getAsciiBytes(filename).length; - length += QUOTE_BYTES.length; - } - return length; - } - - /** - * Write the data in "source" to the specified stream. - * - * @param out The output stream. - * @throws IOException if an IO problem occurs. - */ - protected void sendData(OutputStream out) throws IOException { - if (lengthOfData() == 0) { - - // this file contains no data, so there is nothing to send. - // we don't want to create a zero length buffer as this will - // cause an infinite loop when reading. - return; - } - - byte[] tmp = new byte[4096]; - InputStream instream = source.createInputStream(); - try { - int len; - while ((len = instream.read(tmp)) >= 0) { - out.write(tmp, 0, len); - } - } finally { - // we're done with the stream, close it - instream.close(); - } - } - - public void setStalledTime(long ms) { - _stalledTime = ms; - } - - public long getStalledTime() { - return _stalledTime; - } - - /** - * Returns the source of the file part. - * - * @return The source. - */ - public PartSource getSource() { - return source; - } - - /** - * Return the length of the data. - * - * @return The length. - */ - protected long lengthOfData() { - return source.getLength(); - } - - private long _stalledTime = -1; - -} diff --git a/src/main/java/com/ning/http/multipart/FilePartSource.java b/src/main/java/com/ning/http/multipart/FilePartSource.java deleted file mode 100644 index 70e2b22232..0000000000 --- a/src/main/java/com/ning/http/multipart/FilePartSource.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * 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.multipart; - -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; - -/** - * This class is an adaptation of the Apache HttpClient implementation - * - * @link http://hc.apache.org/httpclient-3.x/ - */ -public class FilePartSource implements PartSource { - - /** - * File part file. - */ - private File file = null; - - /** - * File part file name. - */ - private String fileName = null; - - /** - * Constructor for FilePartSource. - * - * @param file the FilePart source File. - * @throws java.io.FileNotFoundException if the file does not exist or - * cannot be read - */ - public FilePartSource(File file) throws FileNotFoundException { - this.file = file; - if (file != null) { - if (!file.isFile()) { - throw new FileNotFoundException("File is not a normal file."); - } - if (!file.canRead()) { - throw new FileNotFoundException("File is not readable."); - } - this.fileName = file.getName(); - } - } - - /** - * Constructor for FilePartSource. - * - * @param fileName the file name of the FilePart - * @param file the source File for the FilePart - * @throws FileNotFoundException if the file does not exist or - * cannot be read - */ - public FilePartSource(String fileName, File file) - throws FileNotFoundException { - this(file); - this.fileName = fileName; - } - - /** - * Return the length of the file - * - * @return the length of the file. - * @see PartSource#getLength() - */ - public long getLength() { - if (this.file != null) { - return this.file.length(); - } else { - return 0; - } - } - - /** - * Return the current filename - * - * @return the filename. - * @see PartSource#getFileName() - */ - public String getFileName() { - return fileName; - } - - /** - * Return a new {@link java.io.FileInputStream} for the current filename. - * - * @return the new input stream. - * @throws java.io.IOException If an IO problem occurs. - * @see PartSource#createInputStream() - */ - public InputStream createInputStream() throws IOException { - if (this.file != null) { - return new FileInputStream(this.file); - } else { - return new ByteArrayInputStream(new byte[]{}); - } - } - - public File getFile() { - return file; - } -} diff --git a/src/main/java/com/ning/http/multipart/FilePartStallHandler.java b/src/main/java/com/ning/http/multipart/FilePartStallHandler.java deleted file mode 100644 index 460aea8b6c..0000000000 --- a/src/main/java/com/ning/http/multipart/FilePartStallHandler.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * 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.multipart; - -import java.util.Timer; -import java.util.TimerTask; - -/** - * @author Gail Hernandez - */ -public class FilePartStallHandler extends TimerTask { - public FilePartStallHandler(long waitTime, FilePart filePart) { - _waitTime = waitTime; - _failed = false; - _written = false; - } - - public void completed() { - if(_waitTime > 0) { - _timer.cancel(); - } - } - - public boolean isFailed() { - return _failed; - } - - public void run() { - if(!_written) { - _failed = true; - _timer.cancel(); - } - _written = false; - } - - public void start() { - if(_waitTime > 0) { - _timer = new Timer(); - _timer.scheduleAtFixedRate(this, _waitTime, _waitTime); - } - } - - public void writeHappened() { - _written = true; - } - - private long _waitTime; - private Timer _timer; - private boolean _failed; - private boolean _written; -} diff --git a/src/main/java/com/ning/http/multipart/MultipartBody.java b/src/main/java/com/ning/http/multipart/MultipartBody.java deleted file mode 100644 index 021ab71ba1..0000000000 --- a/src/main/java/com/ning/http/multipart/MultipartBody.java +++ /dev/null @@ -1,602 +0,0 @@ -/* - * 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.multipart; - -import com.ning.http.client.RandomAccessBody; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.io.RandomAccessFile; -import java.nio.ByteBuffer; -import java.nio.channels.*; -import java.util.ArrayList; -import java.util.List; -import java.util.Set; - -public class MultipartBody implements RandomAccessBody { - - private final static Logger logger = LoggerFactory.getLogger(MultipartBody.class); - - private final byte[] boundary; - private final long contentLength; - private final List parts; - private final List files = new ArrayList(); - - private int startPart = 0; - private ByteArrayInputStream currentStream; - private int currentStreamPosition = -1; - private boolean endWritten = false; - private boolean doneWritingParts = false; - private FileLocation fileLocation = FileLocation.NONE; - private FilePart currentFilePart; - private FileChannel currentFileChannel; - - enum FileLocation {NONE, START, MIDDLE, END} - - public MultipartBody(List parts, String contentType, long contentLength) { - this.boundary = MultipartEncodingUtil.getAsciiBytes(contentType.substring(contentType.indexOf("boundary=") + "boundary=".length())); - this.parts = parts; - this.contentLength = contentLength; - } - - public void close() throws IOException { - for (RandomAccessFile file : files) { - file.close(); - } - } - - public long getContentLength() { - return contentLength; - } - - public long read(ByteBuffer buffer) throws IOException { - try { - int overallLength = 0; - - final int maxLength = buffer.remaining(); - - if (startPart == parts.size() && endWritten) { - return -1; - } - - boolean full = false; - while (!full && !doneWritingParts) { - com.ning.http.client.Part part = null; - if (startPart < parts.size()) { - part = parts.get(startPart); - } - if (currentFileChannel != null) { - overallLength += currentFileChannel.read(buffer); - - if (currentFileChannel.position() == currentFileChannel.size()) { - currentFileChannel.close(); - currentFileChannel = null; - } - - if (overallLength == maxLength) { - full = true; - } - } else if (currentStreamPosition > -1) { - overallLength += writeToBuffer(buffer, maxLength - overallLength); - - if (overallLength == maxLength) { - full = true; - } - if (startPart == parts.size() && currentStream.available() == 0) { - doneWritingParts = true; - } - } else if (part instanceof StringPart) { - StringPart currentPart = (StringPart) part; - - initializeStringPart(currentPart); - - startPart++; - } else if (part instanceof com.ning.http.client.StringPart) { - StringPart currentPart = generateClientStringpart(part); - - initializeStringPart(currentPart); - - startPart++; - } else if (part instanceof FilePart) { - if (fileLocation == FileLocation.NONE) { - currentFilePart = (FilePart) part; - initializeFilePart(currentFilePart); - } else if (fileLocation == FileLocation.START) { - initializeFileBody(currentFilePart); - } else if (fileLocation == FileLocation.MIDDLE) { - initializeFileEnd(currentFilePart); - } else if (fileLocation == FileLocation.END) { - startPart++; - fileLocation = FileLocation.NONE; - if (startPart == parts.size() && currentStream.available() == 0) { - doneWritingParts = true; - } - } - } else if (part instanceof com.ning.http.client.FilePart) { - if (fileLocation == FileLocation.NONE) { - currentFilePart = generateClientFilePart(part); - initializeFilePart(currentFilePart); - } else if (fileLocation == FileLocation.START) { - initializeFileBody(currentFilePart); - } else if (fileLocation == FileLocation.MIDDLE) { - initializeFileEnd(currentFilePart); - } else if (fileLocation == FileLocation.END) { - startPart++; - fileLocation = FileLocation.NONE; - if (startPart == parts.size() && currentStream.available() == 0) { - doneWritingParts = true; - } - } - } else if (part instanceof com.ning.http.client.ByteArrayPart) { - com.ning.http.client.ByteArrayPart bytePart = - (com.ning.http.client.ByteArrayPart) part; - - if (fileLocation == FileLocation.NONE) { - currentFilePart = - generateClientByteArrayPart(bytePart); - - initializeFilePart(currentFilePart); - } else if (fileLocation == FileLocation.START) { - initializeByteArrayBody(currentFilePart); - } else if (fileLocation == FileLocation.MIDDLE) { - initializeFileEnd(currentFilePart); - } else if (fileLocation == FileLocation.END) { - startPart++; - fileLocation = FileLocation.NONE; - if (startPart == parts.size() && currentStream.available() == 0) { - doneWritingParts = true; - } - } - } - } - - if (doneWritingParts) { - if (currentStreamPosition == -1) { - ByteArrayOutputStream endWriter = new ByteArrayOutputStream(); - - Part.sendMessageEnd(endWriter, boundary); - - initializeBuffer(endWriter.toByteArray()); - } - - if (currentStreamPosition > -1) { - overallLength += writeToBuffer(buffer, maxLength - overallLength); - - if (currentStream.available() == 0) { - currentStream.close(); - currentStreamPosition = -1; - endWritten = true; - } - } - } - return overallLength; - - } catch (Exception e) { - logger.info("read exception", e); - return 0; - } - } - - private void initializeByteArrayBody(FilePart filePart) - throws IOException { - - ByteArrayOutputStream output = new ByteArrayOutputStream(); - filePart.sendData(output); - - initializeBuffer(output.toByteArray()); - - fileLocation = FileLocation.MIDDLE; - } - - private void initializeFileEnd(FilePart currentPart) - throws IOException { - - ByteArrayOutputStream output = generateFileEnd(currentPart); - - initializeBuffer(output.toByteArray()); - - fileLocation = FileLocation.END; - - } - - private void initializeFileBody(FilePart currentPart) - throws IOException { - - if (currentPart.getSource() instanceof FilePartSource) { - - FilePartSource source = (FilePartSource) currentPart.getSource(); - - File file = source.getFile(); - - RandomAccessFile raf = new RandomAccessFile(file, "r"); - files.add(raf); - - currentFileChannel = raf.getChannel(); - - } else { - // ByteArrayPartSource - PartSource partSource = currentPart.getSource(); - - InputStream stream = partSource.createInputStream(); - - byte[] bytes = new byte[(int) partSource.getLength()]; - - stream.read(bytes); - - currentStream = new ByteArrayInputStream(bytes); - - currentStreamPosition = 0; - } - - fileLocation = FileLocation.MIDDLE; - } - - private void initializeFilePart(FilePart filePart) - throws IOException { - - ByteArrayOutputStream output = generateFileStart(filePart); - - initializeBuffer(output.toByteArray()); - - fileLocation = FileLocation.START; - } - - private void initializeStringPart(StringPart currentPart) - throws IOException { - - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - - Part.sendPart(outputStream, currentPart, boundary); - - initializeBuffer(outputStream.toByteArray()); - } - - private int writeToBuffer(ByteBuffer buffer, int length) - throws IOException { - - int available = currentStream.available(); - - int writeLength = Math.min(available, length); - - byte[] bytes = new byte[writeLength]; - - currentStream.read(bytes); - - buffer.put(bytes); - - if (available <= length) { - currentStream.close(); - currentStreamPosition = -1; - } else { - currentStreamPosition += writeLength; - } - - return writeLength; - } - - private void initializeBuffer(byte[] bytes) - throws IOException { - - currentStream = new ByteArrayInputStream(bytes); - - currentStreamPosition = 0; - - } - - public long transferTo(long position, long count, WritableByteChannel target) - throws IOException { - - long overallLength = 0; - - if (startPart == parts.size()) { - return contentLength; - } - - int tempPart = startPart; - - for (com.ning.http.client.Part part : parts) { - if (part instanceof Part) { - overallLength += handleMultiPart(target, (Part) part); - } else { - overallLength += handleClientPart(target, part); - } - - tempPart++; - } - ByteArrayOutputStream endWriter = new ByteArrayOutputStream(); - - Part.sendMessageEnd(endWriter, boundary); - - overallLength += writeToTarget(target, endWriter.toByteArray()); - - startPart = tempPart; - - return overallLength; - } - - private long handleClientPart( - WritableByteChannel target, com.ning.http.client.Part part) throws IOException { - - if (part.getClass().equals(com.ning.http.client.StringPart.class)) { - StringPart currentPart = generateClientStringpart(part); - - return handleStringPart(target, currentPart); - } else if (part.getClass().equals(com.ning.http.client.FilePart.class)) { - FilePart filePart = generateClientFilePart(part); - - return handleFilePart(target, filePart); - } else if (part.getClass().equals(com.ning.http.client.ByteArrayPart.class)) { - com.ning.http.client.ByteArrayPart bytePart = (com.ning.http.client.ByteArrayPart) part; - - FilePart filePart = generateClientByteArrayPart(bytePart); - - return handleByteArrayPart(target, filePart, bytePart.getData()); - } - - return 0; - } - - private FilePart generateClientByteArrayPart( - com.ning.http.client.ByteArrayPart bytePart) { - ByteArrayPartSource source = new ByteArrayPartSource(bytePart.getFileName(), bytePart.getData()); - - FilePart filePart = new FilePart(bytePart.getName(), source, bytePart.getMimeType(), bytePart.getCharSet()); - return filePart; - } - - private FilePart generateClientFilePart(com.ning.http.client.Part part) - throws FileNotFoundException { - com.ning.http.client.FilePart currentPart = (com.ning.http.client.FilePart) part; - - FilePart filePart = new FilePart(currentPart.getName(), currentPart.getFile(), currentPart.getMimeType(), currentPart.getCharSet()); - return filePart; - } - - private StringPart generateClientStringpart(com.ning.http.client.Part part) { - com.ning.http.client.StringPart stringPart = (com.ning.http.client.StringPart) part; - - StringPart currentPart = new StringPart(stringPart.getName(), stringPart.getValue(), stringPart.getCharset()); - return currentPart; - } - - private long handleByteArrayPart(WritableByteChannel target, - FilePart filePart, byte[] data) throws IOException { - - final ByteArrayOutputStream output = new ByteArrayOutputStream(); - Part.sendPart(output, filePart, boundary); - return writeToTarget(target, output.toByteArray()); - } - - private long handleFileEnd(WritableByteChannel target, FilePart filePart) - throws IOException { - - ByteArrayOutputStream endOverhead = generateFileEnd(filePart); - - return this.writeToTarget(target, endOverhead.toByteArray()); - } - - private ByteArrayOutputStream generateFileEnd(FilePart filePart) - throws IOException { - ByteArrayOutputStream endOverhead = new ByteArrayOutputStream(); - - filePart.sendEnd(endOverhead); - return endOverhead; - } - - private long handleFileHeaders(WritableByteChannel target, FilePart filePart) throws IOException { - - ByteArrayOutputStream overhead = generateFileStart(filePart); - - return writeToTarget(target, overhead.toByteArray()); - } - - private ByteArrayOutputStream generateFileStart(FilePart filePart) - throws IOException { - ByteArrayOutputStream overhead = new ByteArrayOutputStream(); - - filePart.sendStart(overhead, boundary); - filePart.sendDispositionHeader(overhead); - filePart.sendContentTypeHeader(overhead); - filePart.sendTransferEncodingHeader(overhead); - filePart.sendContentIdHeader(overhead); - filePart.sendEndOfHeader(overhead); - return overhead; - } - - private long handleFilePart(WritableByteChannel target, FilePart filePart) throws IOException { - FilePartStallHandler handler = new FilePartStallHandler( - filePart.getStalledTime(), filePart); - - handler.start(); - - if (filePart.getSource() instanceof FilePartSource) { - int length = 0; - - length += handleFileHeaders(target, filePart); - FilePartSource source = (FilePartSource) filePart.getSource(); - - File file = source.getFile(); - - RandomAccessFile raf = new RandomAccessFile(file, "r"); - files.add(raf); - - FileChannel fc = raf.getChannel(); - - long l = file.length(); - int fileLength = 0; - long nWrite = 0; - synchronized (fc) { - while (fileLength != l) { - if(handler.isFailed()) { - logger.debug("Stalled error"); - throw new FileUploadStalledException(); - } - try { - nWrite = fc.transferTo(fileLength, l, target); - - if (nWrite == 0) { - logger.info("Waiting for writing..."); - try { - fc.wait(50); - } catch (InterruptedException e) { - logger.trace(e.getMessage(), e); - } - } - else { - handler.writeHappened(); - } - } catch (IOException ex) { - String message = ex.getMessage(); - - // http://bugs.sun.com/view_bug.do?bug_id=5103988 - if (message != null && message.equalsIgnoreCase("Resource temporarily unavailable")) { - try { - fc.wait(1000); - } catch (InterruptedException e) { - logger.trace(e.getMessage(), e); - } - logger.warn("Experiencing NIO issue http://bugs.sun.com/view_bug.do?bug_id=5103988. Retrying"); - continue; - } else { - throw ex; - } - } - fileLength += nWrite; - } - } - handler.completed(); - - fc.close(); - - length += handleFileEnd(target, filePart); - - return length; - } else { - return handlePartSource(target, filePart); - } - } - - private long handlePartSource(WritableByteChannel target, FilePart filePart) throws IOException { - - int length = 0; - - length += handleFileHeaders(target, filePart); - - PartSource partSource = filePart.getSource(); - - InputStream stream = partSource.createInputStream(); - - try { - int nRead = 0; - while (nRead != -1) { - // Do not buffer the entire monster in memory. - byte[] bytes = new byte[8192]; - nRead = stream.read(bytes); - if (nRead > 0) { - ByteArrayOutputStream bos = new ByteArrayOutputStream(nRead); - bos.write(bytes, 0, nRead); - length += writeToTarget(target, bos.toByteArray()); - } - } - } finally { - stream.close(); - } - length += handleFileEnd(target, filePart); - - return length; - } - - private long handleStringPart(WritableByteChannel target, StringPart currentPart) throws IOException { - - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - - Part.sendPart(outputStream, currentPart, boundary); - - return writeToTarget(target, outputStream.toByteArray()); - } - - private long handleMultiPart(WritableByteChannel target, Part currentPart) throws IOException { - - if (currentPart.getClass().equals(StringPart.class)) { - return handleStringPart(target, (StringPart) currentPart); - } else if (currentPart.getClass().equals(FilePart.class)) { - FilePart filePart = (FilePart) currentPart; - - return handleFilePart(target, filePart); - } - return 0; - } - - private long writeToTarget(WritableByteChannel target, byte[] bytes) - throws IOException { - - int written = 0; - int maxSpin = 0; - synchronized (bytes) { - ByteBuffer message = ByteBuffer.wrap(bytes); - - if (target instanceof SocketChannel) { - final Selector selector = Selector.open(); - try { - final SocketChannel channel = (SocketChannel) target; - channel.register(selector, SelectionKey.OP_WRITE); - - while (written < bytes.length) { - selector.select(1000); - maxSpin++; - final Set selectedKeys = selector.selectedKeys(); - - for (SelectionKey key : selectedKeys) { - if (key.isWritable()) { - written += target.write(message); - maxSpin = 0; - } - } - - if (maxSpin >= 10) { - throw new IOException("Unable to write on channel " + target); - } - } - } finally { - selector.close(); - } - } else { - while ((target.isOpen()) && (written < bytes.length)) { - long nWrite = target.write(message); - written += nWrite; - if (nWrite == 0 && maxSpin++ < 10) { - logger.info("Waiting for writing..."); - try { - bytes.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; - } - } - } - } - return written; - } -} diff --git a/src/main/java/com/ning/http/multipart/MultipartEncodingUtil.java b/src/main/java/com/ning/http/multipart/MultipartEncodingUtil.java deleted file mode 100644 index d249babae3..0000000000 --- a/src/main/java/com/ning/http/multipart/MultipartEncodingUtil.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * 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.multipart; - -import java.io.UnsupportedEncodingException; - -/** - * This class is an adaptation of the Apache HttpClient implementation - * - * @link http://hc.apache.org/httpclient-3.x/ - */ -public class MultipartEncodingUtil { - - public static byte[] getAsciiBytes(String data) { - try { - return data.getBytes("US-ASCII"); - } catch (UnsupportedEncodingException e) { - throw new RuntimeException(e); - } - } - - public static String getAsciiString(final byte[] data) { - if (data == null) - throw new NullPointerException("data"); - - try { - return new String(data, "US-ASCII"); - } catch (UnsupportedEncodingException e) { - throw new RuntimeException(e); - } - } - - public static byte[] getBytes(final String data, String charset) { - - if (data == null) - throw new NullPointerException("data"); - - if (charset == null || charset.length() == 0) { - throw new IllegalArgumentException("charset may not be null or empty"); - } - - try { - return data.getBytes(charset); - } catch (UnsupportedEncodingException e) { - throw new IllegalArgumentException(String.format("Unsupported encoding: %s", charset)); - } - } -} diff --git a/src/main/java/com/ning/http/multipart/Part.java b/src/main/java/com/ning/http/multipart/Part.java deleted file mode 100644 index 99e0a0047d..0000000000 --- a/src/main/java/com/ning/http/multipart/Part.java +++ /dev/null @@ -1,514 +0,0 @@ -/* - * 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.multipart; - -import java.io.IOException; -import java.io.OutputStream; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * 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 { - - private static final Logger LOGGER = LoggerFactory.getLogger(Part.class); - - /** - * Carriage return/linefeed - */ - public static final String CRLF = "\r\n"; - - /** - * Carriage return/linefeed as a byte array - */ - public static final byte[] CRLF_BYTES = MultipartEncodingUtil.getAsciiBytes(CRLF); - - /** - * Content dispostion characters - */ - public static final String QUOTE = "\""; - - /** - * Content dispostion as a byte array - */ - public static final byte[] QUOTE_BYTES = MultipartEncodingUtil.getAsciiBytes(QUOTE); - - /** - * Extra characters - */ - public static final String EXTRA = "--"; - - /** - * Extra characters as a byte array - */ - public static final byte[] EXTRA_BYTES = MultipartEncodingUtil.getAsciiBytes(EXTRA); - - /** - * Content disposition characters - */ - public static final String CONTENT_DISPOSITION = "Content-Disposition: "; - - /** - * Content disposition as a byte array - */ - public static final byte[] CONTENT_DISPOSITION_BYTES = MultipartEncodingUtil.getAsciiBytes(CONTENT_DISPOSITION); - - /** - * form-data characters - */ - public static final String FORM_DATA_DISPOSITION_TYPE = "form-data"; - - /** - * form-data as a byte array - */ - public static final byte[] FORM_DATA_DISPOSITION_TYPE_BYTES = MultipartEncodingUtil.getAsciiBytes(FORM_DATA_DISPOSITION_TYPE); - - /** - * name characters - */ - public static final String NAME = "; name="; - - /** - * name as a byte array - */ - public static final byte[] NAME_BYTES = MultipartEncodingUtil.getAsciiBytes(NAME); - - /** - * Content type header - */ - public static final String CONTENT_TYPE = "Content-Type: "; - - /** - * Content type header as a byte array - */ - public static final byte[] CONTENT_TYPE_BYTES = MultipartEncodingUtil.getAsciiBytes(CONTENT_TYPE); - - /** - * Content charset - */ - public static final String CHARSET = "; charset="; - - /** - * Content charset as a byte array - */ - public static final byte[] CHARSET_BYTES = MultipartEncodingUtil.getAsciiBytes(CHARSET); - - /** - * Content type header - */ - public static final String CONTENT_TRANSFER_ENCODING = "Content-Transfer-Encoding: "; - - /** - * Content type header as a byte array - */ - public static final byte[] CONTENT_TRANSFER_ENCODING_BYTES = MultipartEncodingUtil.getAsciiBytes(CONTENT_TRANSFER_ENCODING); - - /** - * Content type header - */ - public static final String CONTENT_ID = "Content-ID: "; - - /** - * Content type header as a byte array - */ - public static final byte[] CONTENT_ID_BYTES = MultipartEncodingUtil.getAsciiBytes(CONTENT_ID); - - /** - * 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 - */ - 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(); - - private String dispositionType; - - /** - * Gets the disposition-type to be used in Content-Disposition header - * - * @return the disposition-type - */ - public String getDispositionType() { - return dispositionType; - } - - public void setDispositionType(String dispositionType) { - this.dispositionType = dispositionType; - } - - /** - * Write the start to the specified output stream - * - * @param out The output stream - * @param boundary the boundary - * @throws java.io.IOException If an IO problem occurs. - */ - protected void sendStart(OutputStream out, byte[] boundary) throws IOException { - out.write(EXTRA_BYTES); - out.write(boundary); - } - - private int startLength(byte[] boundary) { - return EXTRA_BYTES.length + boundary.length; - } - - /** - * Write the content disposition header to the specified output stream - * - * @param out The output stream - * @throws IOException If an IO problem occurs. - */ - protected void sendDispositionHeader(OutputStream out) throws IOException { - out.write(CRLF_BYTES); - out.write(CONTENT_DISPOSITION_BYTES); - if (dispositionType != null) - out.write(MultipartEncodingUtil.getAsciiBytes(dispositionType)); - else - out.write(FORM_DATA_DISPOSITION_TYPE_BYTES); - - if (getName() != null) { - out.write(NAME_BYTES); - out.write(QUOTE_BYTES); - out.write(MultipartEncodingUtil.getAsciiBytes(getName())); - out.write(QUOTE_BYTES); - } - } - - protected long dispositionHeaderLength() { - long length = 0L; - - length += CRLF_BYTES.length; - length += CONTENT_DISPOSITION_BYTES.length; - if (dispositionType != null) - length += MultipartEncodingUtil.getAsciiBytes(dispositionType).length; - else - length += FORM_DATA_DISPOSITION_TYPE_BYTES.length; - - if (getName() != null) { - length += NAME_BYTES.length; - length += QUOTE_BYTES.length; - length += MultipartEncodingUtil.getAsciiBytes(getName()).length; - length += QUOTE_BYTES.length; - } - return length; - } - - /** - * Write the content type header to the specified output stream - * - * @param out The output stream - * @throws IOException If an IO problem occurs. - */ - protected void sendContentTypeHeader(OutputStream out) throws IOException { - String contentType = getContentType(); - if (contentType != null) { - out.write(CRLF_BYTES); - out.write(CONTENT_TYPE_BYTES); - out.write(MultipartEncodingUtil.getAsciiBytes(contentType)); - String charSet = getCharSet(); - if (charSet != null) { - out.write(CHARSET_BYTES); - out.write(MultipartEncodingUtil.getAsciiBytes(charSet)); - } - } - } - - protected long contentTypeHeaderLength() { - long length = 0L; - String contentType = getContentType(); - if (contentType != null) { - length += CRLF_BYTES.length; - length += CONTENT_TYPE_BYTES.length; - length += MultipartEncodingUtil.getAsciiBytes(contentType).length; - String charSet = getCharSet(); - if (charSet != null) { - length += CHARSET_BYTES.length; - length += MultipartEncodingUtil.getAsciiBytes(charSet).length; - } - } - return length; - } - - /** - * Write the content transfer encoding header to the specified output stream - * - * @param out The output stream - * @throws IOException If an IO problem occurs. - */ - protected void sendTransferEncodingHeader(OutputStream out) throws IOException { - String transferEncoding = getTransferEncoding(); - if (transferEncoding != null) { - out.write(CRLF_BYTES); - out.write(CONTENT_TRANSFER_ENCODING_BYTES); - out.write(MultipartEncodingUtil.getAsciiBytes(transferEncoding)); - } - } - - protected long transferEncodingHeaderLength() { - long length = 0L; - String transferEncoding = getTransferEncoding(); - if (transferEncoding != null) { - length += CRLF_BYTES.length; - length += CONTENT_TRANSFER_ENCODING_BYTES.length; - length += MultipartEncodingUtil.getAsciiBytes(transferEncoding).length; - } - return length; - } - - /** - * 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)); - } - } - - protected long contentIdHeaderLength() { - long length = 0L; - String contentId = getContentId(); - if (contentId != null) { - length += CRLF_BYTES.length; - length += CONTENT_ID_BYTES.length; - length += MultipartEncodingUtil.getAsciiBytes(contentId).length; - } - return length; - } - - /** - * Write the end of the header to the output stream - * - * @param out The output stream - * @throws IOException If an IO problem occurs. - */ - protected void sendEndOfHeader(OutputStream out) throws IOException { - out.write(CRLF_BYTES); - out.write(CRLF_BYTES); - } - - protected long endOfHeaderLength() { - return CRLF_BYTES.length * 2; - } - - /** - * Write the data to the specified output stream - * - * @param out The output stream - * @throws IOException If an IO problem occurs. - */ - protected abstract void sendData(OutputStream out) throws IOException; - - /** - * Return the length of the main content - * - * @return long The length. - */ - protected abstract long lengthOfData(); - - /** - * Write the end data to the output stream. - * - * @param out The output stream - * @throws IOException If an IO problem occurs. - */ - protected void sendEnd(OutputStream out) throws IOException { - out.write(CRLF_BYTES); - } - - protected long endLength() { - return CRLF_BYTES.length; - } - - /** - * 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 - * @param boundary the boundary - * @throws IOException If an IO problem occurs. - */ - public void send(OutputStream out, byte[] boundary) throws IOException { - sendStart(out, boundary); - 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 long The length. - * @throws IOException If an IO problem occurs - */ - public long length(byte[] boundary) { - - long lengthOfData = lengthOfData(); - - if (lengthOfData < 0L) { - return -1L; - } else { - return lengthOfData// - + startLength(boundary)// - + dispositionHeaderLength()// - + contentTypeHeaderLength()// - + transferEncodingHeaderLength()// - + contentIdHeaderLength()// - + endOfHeaderLength()// - + endLength(); - } - } - - /** - * Return a string representation of this object. - * - * @return A string representation of this object. - * @see java.lang.Object#toString() - */ - public String toString() { - return new StringBuilder()// - .append("name=").append(getName())// - .append(" contentType=").append(getContentType())// - .append(" charset=").append(getCharSet())// - .append(" tranferEncoding=").append(getTransferEncoding())// - .append(" contentId=").append(getContentId())// - .append(" dispositionType=").append(getDispositionType())// - .toString(); - } - - /** - * 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 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 { - - if (parts == null) - throw new NullPointerException("partsl"); - if (partBoundary == null || partBoundary.length == 0) - throw new IllegalArgumentException("partBoundary may not be empty"); - for (Part part : parts) { - part.send(out, partBoundary); - } - out.write(EXTRA_BYTES); - out.write(partBoundary); - out.write(EXTRA_BYTES); - out.write(CRLF_BYTES); - } - - public static void sendMessageEnd(OutputStream out, byte[] partBoundary) throws IOException { - - if (partBoundary == null || partBoundary.length == 0) { - throw new IllegalArgumentException("partBoundary may not be empty"); - } - - out.write(EXTRA_BYTES); - out.write(partBoundary); - out.write(EXTRA_BYTES); - out.write(CRLF_BYTES); - } - - /** - * Write all parts and the last boundary to the specified output stream. - * - * @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 { - if (part == null) - throw new NullPointerException("parts"); - - part.send(out, partBoundary); - } - - /** - * Gets the length of the multipart message including the given 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. - * @since 3.0 - */ - public static long getLengthOfParts(Part[] parts, byte[] partBoundary) { - - try { - if (parts == null) - throw new NullPointerException("parts"); - long total = 0; - for (Part part : parts) { - long l = part.length(partBoundary); - if (l < 0) { - return -1; - } - total += l; - } - total += EXTRA_BYTES.length; - total += partBoundary.length; - total += EXTRA_BYTES.length; - total += CRLF_BYTES.length; - return total; - } catch (Exception e) { - LOGGER.error("An exception occurred while getting the length of the parts", e); - return 0L; - } - } -} diff --git a/src/main/java/com/ning/http/multipart/PartBase.java b/src/main/java/com/ning/http/multipart/PartBase.java deleted file mode 100644 index 67a75a3ab6..0000000000 --- a/src/main/java/com/ning/http/multipart/PartBase.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * 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.multipart; - -/** - * This class is an adaptation of the Apache HttpClient implementation - * - * @link http://hc.apache.org/httpclient-3.x/ - */ -public abstract class PartBase extends Part { - - /** - * Name of the file part. - */ - private String name; - - /** - * Content type of the file part. - */ - private String contentType; - - /** - * Content encoding of the file part. - */ - private String charSet; - - /** - * The transfer encoding. - */ - private String transferEncoding; - - private String contentId; - - /** - * Constructor. - * - * @param name The name of the part, or null - * @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, String contentId) { - this.name = name; - this.contentType = contentType; - this.charSet = charSet; - this.transferEncoding = transferEncoding; - this.contentId = contentId; - } - - /** - * Returns the name. - * - * @return The name. - */ - public String getName() { - return this.name; - } - - /** - * Returns the content type of this part. - * - * @return String The name. - */ - public String getContentType() { - return this.contentType; - } - - /** - * Return the character encoding of this part. - * - * @return String The name. - */ - public String getCharSet() { - return this.charSet; - } - - /** - * Returns the transfer encoding of this part. - * - * @return String The name. - */ - public String getTransferEncoding() { - return transferEncoding; - } - - /** - * Sets the character encoding. - * - * @param charSet the character encoding, or null to exclude the character encoding header - */ - public void setCharSet(String charSet) { - this.charSet = charSet; - } - - /** - * Sets the content type. - * - * @param contentType the content type, or null to exclude the content type header - */ - public void setContentType(String contentType) { - this.contentType = contentType; - } - - /** - * Sets the part name. - * - * @param name - */ - public void setName(String name) { - if (name == null) - throw new NullPointerException("name"); - this.name = name; - } - - /** - * Sets the transfer encoding. - * - * @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/PartSource.java b/src/main/java/com/ning/http/multipart/PartSource.java deleted file mode 100644 index 06fcc8044f..0000000000 --- a/src/main/java/com/ning/http/multipart/PartSource.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * 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.multipart; - -import java.io.IOException; -import java.io.InputStream; - -/** - * This class is an adaptation of the Apache HttpClient implementation - * - * @link http://hc.apache.org/httpclient-3.x/ - */ -public interface PartSource { - - /** - * Gets the number of bytes contained in this source. - * - * @return a value >= 0 - */ - long getLength(); - - /** - * Gets the name of the file this source represents. - * - * @return the fileName used for posting a MultiPart file part - */ - String getFileName(); - - /** - * Gets a new InputStream for reading this source. This method can be - * called more than once and should therefore return a new stream every - * time. - * - * @return a new InputStream - * @throws java.io.IOException if an error occurs when creating the InputStream - */ - InputStream createInputStream() throws IOException; -} - diff --git a/src/main/java/com/ning/http/multipart/StringPart.java b/src/main/java/com/ning/http/multipart/StringPart.java deleted file mode 100644 index c2c6765f62..0000000000 --- a/src/main/java/com/ning/http/multipart/StringPart.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * 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.multipart; - -import java.io.IOException; -import java.io.OutputStream; - -/** - * This class is an adaptation of the Apache HttpClient implementation - * - * @link http://hc.apache.org/httpclient-3.x/ - */ -public class StringPart extends PartBase { - - /** - * Default content encoding of string parameters. - */ - public static final String DEFAULT_CONTENT_TYPE = "text/plain"; - - /** - * Default charset of string parameters - */ - public static final String DEFAULT_CHARSET = "US-ASCII"; - - /** - * Default transfer encoding of string parameters - */ - public static final String DEFAULT_TRANSFER_ENCODING = "8bit"; - - /** - * Contents of this StringPart. - */ - private byte[] content; - - /** - * The String value of this part. - */ - 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 - */ - public StringPart(String name, String value, String charset, String contentId) { - - super(name, DEFAULT_CONTENT_TYPE, charset == null ? DEFAULT_CHARSET : charset, DEFAULT_TRANSFER_ENCODING, contentId); - if (value == null) - throw new NullPointerException("value"); - if (value.indexOf(0) != -1) { - // See RFC 2048, 2.8. "8bit Data" - throw new IllegalArgumentException("NULs may not be present in string parts"); - } - 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 value the string to post - */ - public StringPart(String name, String value) { - this(name, value, null); - } - - /** - * 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() { - if (content == null) { - content = MultipartEncodingUtil.getBytes(value, getCharSet()); - } - return content; - } - - /** - * Writes the data to the given OutputStream. - * - * @param out the OutputStream to write to - * @throws java.io.IOException if there is a write error - */ - protected void sendData(OutputStream out) throws IOException { - out.write(getContent()); - } - - /** - * Return the length of the data. - * - * @return The length of the data. - */ - protected long lengthOfData() { - return getContent().length; - } - - /* - * (non-Javadoc) - * - * @see org.apache.commons.httpclient.methods.multipart.BasePart#setCharSet(java.lang.String) - */ - public void setCharSet(String charSet) { - super.setCharSet(charSet); - this.content = null; - } - -} diff --git a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java index e65c2bf74e..cfe66f5e3a 100644 --- a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java +++ b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java @@ -16,22 +16,13 @@ import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.AsyncHttpProvider; -import com.ning.http.client.ByteArrayPart; -import com.ning.http.client.FilePart; -import com.ning.http.client.FluentCaseInsensitiveStringsMap; import com.ning.http.client.HttpResponseBodyPart; import com.ning.http.client.HttpResponseBodyPartsInputStream; import com.ning.http.client.Param; -import com.ning.http.client.Part; import com.ning.http.client.Request; -import com.ning.http.client.StringPart; import com.ning.http.client.uri.UriComponents; -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; import java.io.UnsupportedEncodingException; @@ -48,7 +39,7 @@ public class AsyncHttpProviderUtils { public final static Charset DEFAULT_CHARSET = StandardCharsets.ISO_8859_1; static final byte[] EMPTY_BYTE_ARRAY = "".getBytes(); - + public static final void validateSupportedScheme(UriComponents uri) { final String scheme = uri.getScheme(); if (scheme == null || !scheme.equalsIgnoreCase("http") && !scheme.equalsIgnoreCase("https") && !scheme.equalsIgnoreCase("ws") @@ -63,7 +54,7 @@ public final static String getBaseUrl(UriComponents uri) { } public final static String getAuthority(UriComponents uri) { - int port = uri.getPort() != -1? uri.getPort() : getDefaultPort(uri); + int port = uri.getPort() != -1 ? uri.getPort() : getDefaultPort(uri); return uri.getHost() + ":" + port; } @@ -93,7 +84,7 @@ public final static byte[] contentToByte(List bodyParts) t } public final static InputStream contentToInputStream(List bodyParts) throws UnsupportedEncodingException { - return bodyParts.isEmpty()? new ByteArrayInputStream(EMPTY_BYTE_ARRAY) : new HttpResponseBodyPartsInputStream(bodyParts); + return bodyParts.isEmpty() ? new ByteArrayInputStream(EMPTY_BYTE_ARRAY) : new HttpResponseBodyPartsInputStream(bodyParts); } public final static int getDefaultPort(UriComponents uri) { @@ -112,47 +103,6 @@ public final static String getNonEmptyPath(UriComponents uri) { return isNonEmpty(uri.getPath()) ? uri.getPath() : "/"; } - /** - * This is quite ugly as our internal names are duplicated, but we build on top of HTTP Client implementation. - * - * @param params - * @param requestHeaders - * @return a MultipartRequestEntity. - * @throws java.io.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; - - for (Part part : params) { - if (part instanceof com.ning.http.multipart.Part) { - parts[i] = (com.ning.http.multipart.Part) part; - - } else if (part instanceof StringPart) { - StringPart stringPart = (StringPart) part; - parts[i] = new com.ning.http.multipart.StringPart(part.getName(), stringPart.getValue(), stringPart.getCharset()); - - } else if (part instanceof FilePart) { - FilePart filePart = (FilePart) part; - parts[i] = new com.ning.http.multipart.FilePart(part.getName(), filePart.getFile(), filePart.getMimeType(), filePart.getCharSet()); - - } else if (part instanceof ByteArrayPart) { - ByteArrayPart byteArrayPart = (ByteArrayPart) part; - PartSource source = new ByteArrayPartSource(byteArrayPart.getFileName(), byteArrayPart.getData()); - parts[i] = new com.ning.http.multipart.FilePart(part.getName(), source, byteArrayPart.getMimeType(), byteArrayPart.getCharSet()); - - } else if (part == null) { - throw new NullPointerException("Part cannot be null"); - - } else { - throw new IllegalArgumentException(String.format("Unsupported part type for multipart parameter %s", - part.getName())); - } - ++i; - } - return new MultipartRequestEntity(parts, requestHeaders); - } - public final static byte[] readFully(InputStream in, int[] lengthWrapper) throws IOException { // just in case available() returns bogus (or -1), allocate non-trivial chunk byte[] b = new byte[Math.max(512, in.available())]; @@ -180,21 +130,12 @@ private static byte[] doubleUp(byte[] b) { return b2; } - public static String constructUserAgent(Class httpProvider) { - StringBuilder b = new StringBuilder("AsyncHttpClient/1.0") - .append(" ") - .append("(") - .append(httpProvider.getSimpleName()) - .append(" - ") - .append(System.getProperty("os.name")) - .append(" - ") - .append(System.getProperty("os.version")) - .append(" - ") - .append(System.getProperty("java.version")) - .append(" - ") - .append(Runtime.getRuntime().availableProcessors()) - .append(" core(s))"); - return b.toString(); + public static String constructUserAgent(Class httpProvider, AsyncHttpClientConfig config) { + return new StringBuilder("AHC (").append(httpProvider.getSimpleName())// + .append(" - ").append(System.getProperty("os.name"))// + .append(" - ").append(System.getProperty("os.version"))// + .append(" - ").append(System.getProperty("java.version"))// + .append(" - ").append(Runtime.getRuntime().availableProcessors()).append(" core(s))").toString(); } public static String parseCharset(String contentType) { @@ -219,15 +160,15 @@ public static String parseCharset(String contentType) { public static String keepAliveHeaderValue(AsyncHttpClientConfig config) { return config.isAllowPoolingConnections() ? "keep-alive" : "close"; } - + public static int requestTimeout(AsyncHttpClientConfig config, Request request) { return request.getRequestTimeout() != 0 ? request.getRequestTimeout() : config.getRequestTimeout(); } public static boolean followRedirect(AsyncHttpClientConfig config, Request request) { - return request.getFollowRedirect() != null? request.getFollowRedirect().booleanValue() : config.isFollowRedirect(); + return request.getFollowRedirect() != null ? request.getFollowRedirect().booleanValue() : config.isFollowRedirect(); } - + public static String formParams2UTF8String(List params) { StringBuilder sb = new StringBuilder(params.size() * 15); for (Param param : params) { diff --git a/src/main/java/com/ning/http/util/StandardCharsets.java b/src/main/java/com/ning/http/util/StandardCharsets.java index 627ba051ea..bcea14845e 100644 --- a/src/main/java/com/ning/http/util/StandardCharsets.java +++ b/src/main/java/com/ning/http/util/StandardCharsets.java @@ -19,6 +19,7 @@ public final class StandardCharsets { public static final Charset US_ASCII = Charset.forName("US-ASCII"); public static final Charset UTF_8 = Charset.forName("UTF-8"); + public static final Charset UTF_16 = Charset.forName("UTF-16"); public static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1"); public static final Charset UNICODE_LITTLE_UNMARKED = Charset.forName("UnicodeLittleUnmarked"); 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 45e3b1e192..1f2e1b789f 100755 --- a/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java +++ b/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java @@ -22,6 +22,26 @@ 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.FluentCaseInsensitiveStringsMap; +import com.ning.http.client.MaxRedirectException; +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.cookie.Cookie; +import com.ning.http.client.multipart.Part; +import com.ning.http.client.multipart.StringPart; +import com.ning.http.util.StandardCharsets; + import java.io.ByteArrayInputStream; import java.io.IOException; import java.net.ConnectException; @@ -42,26 +62,6 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; -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.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.cookie.Cookie; -import com.ning.http.util.StandardCharsets; - public abstract class AsyncProvidersBasicTest extends AbstractBasicTest { private static final String UTF_8 = "text/html;charset=UTF-8"; @@ -677,7 +677,7 @@ public void asyncDoPostMultiPartTest() throws Throwable { try { final CountDownLatch l = new CountDownLatch(1); - Part p = new StringPart("foo", "bar"); + Part p = new StringPart("foo", "bar", StandardCharsets.UTF_8.name()); client.preparePost(getTargetUrl()).addBodyPart(p).execute(new AsyncCompletionHandlerAdapter() { @@ -773,7 +773,7 @@ public void onThrowable(Throwable t) { }).get(); assertEquals(response.getStatusCode(), 200); - assertEquals(response.getHeader("X-Proxy-Connection"), "keep-alive"); + assertEquals(response.getHeader("X-Connection"), "keep-alive"); } finally { client.close(); } diff --git a/src/test/java/com/ning/http/client/async/FastUnauthorizedUploadTest.java b/src/test/java/com/ning/http/client/async/FastUnauthorizedUploadTest.java index 8d59a47bdf..984a8b7238 100644 --- a/src/test/java/com/ning/http/client/async/FastUnauthorizedUploadTest.java +++ b/src/test/java/com/ning/http/client/async/FastUnauthorizedUploadTest.java @@ -12,13 +12,6 @@ */ package com.ning.http.client.async; -import java.io.File; -import java.io.IOException; - -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.Assert; @@ -26,8 +19,16 @@ import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClient.BoundRequestBuilder; -import com.ning.http.client.FilePart; import com.ning.http.client.Response; +import com.ning.http.client.multipart.FilePart; +import com.ning.http.util.StandardCharsets; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import java.io.File; +import java.io.IOException; public abstract class FastUnauthorizedUploadTest extends AbstractBasicTest { @@ -48,7 +49,7 @@ public void handle(String target, Request baseRequest, HttpServletRequest req, H @Test(groups = { "standalone", "default_provider" }, enabled = true) public void testUnauthorizedWhileUploading() throws Exception { - byte[] bytes = "RatherLargeFileRatherLargeFileRatherLargeFileRatherLargeFile".getBytes("UTF-16"); + byte[] bytes = "RatherLargeFileRatherLargeFileRatherLargeFileRatherLargeFile".getBytes(StandardCharsets.UTF_16); long repeats = (1024 * 1024 / bytes.length) + 1; File largeFile = FilePartLargeFileTest.createTempFile(bytes, (int) repeats); @@ -56,7 +57,7 @@ public void testUnauthorizedWhileUploading() throws Exception { 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", StandardCharsets.UTF_8.name())); Response response = rb.execute().get(); Assert.assertEquals(401, response.getStatusCode()); 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 6749ad4c84..b9ed713d9d 100644 --- a/src/test/java/com/ning/http/client/async/FilePartLargeFileTest.java +++ b/src/test/java/com/ning/http/client/async/FilePartLargeFileTest.java @@ -14,17 +14,6 @@ import static org.testng.FileAssert.fail; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.net.URL; -import java.util.UUID; - -import javax.servlet.ServletException; -import javax.servlet.ServletInputStream; -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.Assert; @@ -33,8 +22,19 @@ 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 com.ning.http.client.multipart.FilePart; + +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; public abstract class FilePartLargeFileTest extends AbstractBasicTest { 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 861c58bd66..d290795e5d 100644 --- a/src/test/java/com/ning/http/client/async/MultipartUploadTest.java +++ b/src/test/java/com/ning/http/client/async/MultipartUploadTest.java @@ -12,15 +12,10 @@ */ package com.ning.http.client.async; -import com.ning.http.client.AsyncHttpClient; -import com.ning.http.client.AsyncHttpClientConfig; -import com.ning.http.client.ByteArrayPart; -import com.ning.http.client.FilePart; -import com.ning.http.client.RequestBuilder; -import com.ning.http.client.Response; -import com.ning.http.client.StringPart; -import com.ning.http.util.AsyncHttpProviderUtils; -import com.ning.http.util.StandardCharsets; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; +import static org.testng.Assert.fail; import org.apache.commons.fileupload.FileItemIterator; import org.apache.commons.fileupload.FileItemStream; @@ -38,6 +33,16 @@ import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; +import com.ning.http.client.AsyncHttpClient; +import com.ning.http.client.AsyncHttpClientConfig; +import com.ning.http.client.RequestBuilder; +import com.ning.http.client.Response; +import com.ning.http.client.multipart.ByteArrayPart; +import com.ning.http.client.multipart.FilePart; +import com.ning.http.client.multipart.StringPart; +import com.ning.http.util.AsyncHttpProviderUtils; +import com.ning.http.util.StandardCharsets; + import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; @@ -61,16 +66,10 @@ import java.util.UUID; import java.util.zip.GZIPInputStream; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertNotNull; -import static org.testng.Assert.assertTrue; -import static org.testng.Assert.fail; - /** * @author dominict */ 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 }; @@ -221,14 +220,14 @@ public void testSendingSmallFilesAndByteArray() { builder.setUrl(servletEndpointRedirectUrl + "/upload/bob"); builder.addBodyPart(new FilePart("file1", testResource1File, "text/plain", "UTF-8")); builder.addBodyPart(new FilePart("file2", testResource2File, "application/x-gzip", null)); - builder.addBodyPart(new StringPart("Name", "Dominic")); + builder.addBodyPart(new StringPart("Name", "Dominic", "UTF-8")); builder.addBodyPart(new FilePart("file3", testResource3File, "text/plain", "UTF-8")); builder.addBodyPart(new StringPart("Age", "3", AsyncHttpProviderUtils.DEFAULT_CHARSET.name())); builder.addBodyPart(new StringPart("Height", "shrimplike", AsyncHttpProviderUtils.DEFAULT_CHARSET.name())); builder.addBodyPart(new StringPart("Hair", "ridiculous", AsyncHttpProviderUtils.DEFAULT_CHARSET.name())); - builder.addBodyPart(new ByteArrayPart("file4", "bytearray.txt", expectedContents.getBytes(StandardCharsets.UTF_8), "text/plain", StandardCharsets.UTF_8.name())); + builder.addBodyPart(new ByteArrayPart("file4", expectedContents.getBytes(StandardCharsets.UTF_8), "text/plain", StandardCharsets.UTF_8.name(), "bytearray.txt")); com.ning.http.client.Request r = builder.build(); diff --git a/src/test/java/com/ning/http/client/async/ProxyTunnellingTest.java b/src/test/java/com/ning/http/client/async/ProxyTunnellingTest.java index 01b6ee0876..f41839a6da 100644 --- a/src/test/java/com/ning/http/client/async/ProxyTunnellingTest.java +++ b/src/test/java/com/ning/http/client/async/ProxyTunnellingTest.java @@ -115,7 +115,7 @@ public Response onCompleted(Response response) throws Exception { }); Response r = responseFuture.get(); assertEquals(r.getStatusCode(), 200); - assertEquals(r.getHeader("X-Proxy-Connection"), "keep-alive"); + assertEquals(r.getHeader("X-Connection"), "keep-alive"); } finally { client.close(); @@ -147,7 +147,7 @@ public Response onCompleted(Response response) throws Exception { }); Response r = responseFuture.get(); assertEquals(r.getStatusCode(), 200); - assertEquals(r.getHeader("X-Proxy-Connection"), "keep-alive"); + assertEquals(r.getHeader("X-Connection"), "keep-alive"); } finally { client.close(); } @@ -168,7 +168,7 @@ public void testSimpleAHCConfigProxy() throws IOException, InterruptedException, Response r = client.get().get(); assertEquals(r.getStatusCode(), 200); - assertEquals(r.getHeader("X-Proxy-Connection"), "keep-alive"); + assertEquals(r.getHeader("X-Connection"), "keep-alive"); } finally { client.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 53539389ab..026a87fd4f 100644 --- a/src/test/java/com/ning/http/client/async/SimpleAsyncHttpClientTest.java +++ b/src/test/java/com/ning/http/client/async/SimpleAsyncHttpClientTest.java @@ -12,18 +12,25 @@ */ package com.ning.http.client.async; -import com.ning.http.client.ByteArrayPart; +import static junit.framework.Assert.assertTrue; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.fail; +import static org.testng.AssertJUnit.assertNotNull; +import static org.testng.AssertJUnit.assertNotSame; + +import org.testng.annotations.Test; + import com.ning.http.client.Response; import com.ning.http.client.SimpleAsyncHttpClient; import com.ning.http.client.consumers.AppendableBodyConsumer; import com.ning.http.client.consumers.OutputStreamBodyConsumer; import com.ning.http.client.generators.FileBodyGenerator; import com.ning.http.client.generators.InputStreamBodyGenerator; +import com.ning.http.client.multipart.ByteArrayPart; import com.ning.http.client.simple.HeaderMap; import com.ning.http.client.simple.SimpleAHCTransferListener; import com.ning.http.client.uri.UriComponents; - -import org.testng.annotations.Test; +import com.ning.http.util.StandardCharsets; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -31,12 +38,6 @@ import java.io.IOException; import java.util.concurrent.Future; -import static junit.framework.Assert.assertTrue; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.fail; -import static org.testng.AssertJUnit.assertNotNull; -import static org.testng.AssertJUnit.assertNotSame; - public abstract class SimpleAsyncHttpClientTest extends AbstractBasicTest { private final static String MY_MESSAGE = "my message"; @@ -265,7 +266,7 @@ public void testCloseMasterInvalidDerived() throws Exception { public void testMultiPartPut() throws Exception { 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(); + Response response = client.put(new ByteArrayPart("baPart", "testMultiPart".getBytes(StandardCharsets.UTF_8), "application/test", StandardCharsets.UTF_8.name(), "fileName")).get(); String body = response.getResponseBody(); String contentType = response.getHeader("X-Content-Type"); @@ -289,7 +290,7 @@ public void testMultiPartPut() throws Exception { public void testMultiPartPost() throws Exception { 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(); + Response response = client.post(new ByteArrayPart("baPart", "testMultiPart".getBytes(StandardCharsets.UTF_8), "application/test", StandardCharsets.UTF_8.name(), "fileName")).get(); String body = response.getResponseBody(); String contentType = response.getHeader("X-Content-Type"); 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 2497027dae..f423119e60 100644 --- a/src/test/java/com/ning/http/client/async/TransferListenerTest.java +++ b/src/test/java/com/ning/http/client/async/TransferListenerTest.java @@ -12,33 +12,34 @@ */ package com.ning.http.client.async; +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 org.eclipse.jetty.server.handler.AbstractHandler; +import org.testng.annotations.Test; + import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.FluentCaseInsensitiveStringsMap; import com.ning.http.client.Response; import com.ning.http.client.generators.FileBodyGenerator; import com.ning.http.client.listener.TransferCompletionHandler; import com.ning.http.client.listener.TransferListener; -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.File; import java.io.FileOutputStream; import java.io.IOException; -import java.nio.ByteBuffer; import java.util.Enumeration; import java.util.UUID; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertNotNull; -import static org.testng.Assert.assertNull; -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)); @@ -79,7 +80,7 @@ public void basicGetTest() throws Throwable { final AtomicReference throwable = new AtomicReference(); final AtomicReference hSent = new AtomicReference(); final AtomicReference hRead = new AtomicReference(); - final AtomicReference bb = new AtomicReference(); + final AtomicReference bb = new AtomicReference(); final AtomicBoolean completed = new AtomicBoolean(false); TransferCompletionHandler tl = new TransferCompletionHandler(); @@ -93,11 +94,11 @@ public void onResponseHeadersReceived(FluentCaseInsensitiveStringsMap headers) { hRead.set(headers); } - public void onBytesReceived(ByteBuffer buffer) { - bb.set(buffer); + public void onBytesReceived(byte[] b) { + bb.set(b); } - public void onBytesSent(ByteBuffer buffer) { + public void onBytesSent(long amount, long current, long total) { } public void onRequestResponseCompleted() { @@ -132,8 +133,8 @@ public void basicPutTest() throws Throwable { final AtomicReference throwable = new AtomicReference(); final AtomicReference hSent = new AtomicReference(); final AtomicReference hRead = new AtomicReference(); - final AtomicInteger bbReceivedLenght = new AtomicInteger(0); - final AtomicInteger bbSentLenght = new AtomicInteger(0); + final AtomicLong bbReceivedLenght = new AtomicLong(0); + final AtomicLong bbSentLenght = new AtomicLong(0); final AtomicBoolean completed = new AtomicBoolean(false); @@ -152,12 +153,12 @@ public void onResponseHeadersReceived(FluentCaseInsensitiveStringsMap headers) { hRead.set(headers); } - public void onBytesReceived(ByteBuffer buffer) { - bbReceivedLenght.addAndGet(buffer.capacity()); + public void onBytesReceived(byte[] b) { + bbReceivedLenght.addAndGet(b.length); } - public void onBytesSent(ByteBuffer buffer) { - bbSentLenght.addAndGet(buffer.capacity()); + public void onBytesSent(long amount, long current, long total) { + bbSentLenght.addAndGet(amount); } public void onRequestResponseCompleted() { @@ -192,8 +193,8 @@ public void basicPutBodyTest() throws Throwable { final AtomicReference throwable = new AtomicReference(); final AtomicReference hSent = new AtomicReference(); final AtomicReference hRead = new AtomicReference(); - final AtomicInteger bbReceivedLenght = new AtomicInteger(0); - final AtomicInteger bbSentLenght = new AtomicInteger(0); + final AtomicLong bbReceivedLenght = new AtomicLong(0); + final AtomicLong bbSentLenght = new AtomicLong(0); final AtomicBoolean completed = new AtomicBoolean(false); @@ -212,12 +213,12 @@ public void onResponseHeadersReceived(FluentCaseInsensitiveStringsMap headers) { hRead.set(headers); } - public void onBytesReceived(ByteBuffer buffer) { - bbReceivedLenght.addAndGet(buffer.capacity()); + public void onBytesReceived(byte[] b) { + bbReceivedLenght.addAndGet(b.length); } - public void onBytesSent(ByteBuffer buffer) { - bbSentLenght.addAndGet(buffer.capacity()); + public void onBytesSent(long amount, long current, long total) { + bbSentLenght.addAndGet(amount); } public void onRequestResponseCompleted() { diff --git a/src/test/java/com/ning/http/multipart/MultipartBodyTest.java b/src/test/java/com/ning/http/client/multipart/MultipartBodyTest.java similarity index 75% rename from src/test/java/com/ning/http/multipart/MultipartBodyTest.java rename to src/test/java/com/ning/http/client/multipart/MultipartBodyTest.java index 2e40533451..8b7af839a4 100644 --- a/src/test/java/com/ning/http/multipart/MultipartBodyTest.java +++ b/src/test/java/com/ning/http/client/multipart/MultipartBodyTest.java @@ -10,18 +10,17 @@ * "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.multipart; +package com.ning.http.client.multipart; -import com.ning.http.client.*; -import com.ning.http.client.Part; -import com.ning.http.util.AsyncHttpProviderUtils; import org.testng.Assert; import org.testng.annotations.Test; +import com.ning.http.client.Body; +import com.ning.http.client.FluentCaseInsensitiveStringsMap; +import com.ning.http.util.StandardCharsets; + import java.io.File; -import java.io.FileNotFoundException; import java.io.IOException; -import java.io.UnsupportedEncodingException; import java.net.URISyntaxException; import java.net.URL; import java.nio.ByteBuffer; @@ -36,17 +35,10 @@ public void testBasics() { // add a file final File testFile = getTestfile(); - try { - parts.add(new FilePart("filePart", testFile)); - } catch (FileNotFoundException fne) { - Assert.fail("file not found: " + testFile); - } + parts.add(new FilePart("filePart", testFile)); // add a byte array - try { - parts.add(new ByteArrayPart("baPart", "fileName", "testMultiPart".getBytes("utf-8"), "application/test", "utf-8")); - } catch (UnsupportedEncodingException ignore) { - } + parts.add(new ByteArrayPart("baPart", "testMultiPart".getBytes(StandardCharsets.UTF_8), "application/test", StandardCharsets.UTF_8.name(), "fileName")); // add a string parts.add(new StringPart("stringPart", "testString", "utf-8")); @@ -70,16 +62,11 @@ private static File getTestfile() { private static void compareContentLength(final List parts) { Assert.assertNotNull(parts); // get expected values - MultipartRequestEntity mre = null; - try { - mre = AsyncHttpProviderUtils.createMultipartRequestEntity(parts, new FluentCaseInsensitiveStringsMap()); - } catch (FileNotFoundException fne) { - Assert.fail("file not found: " + parts); - } + MultipartRequestEntity mre = new MultipartRequestEntity(parts, new FluentCaseInsensitiveStringsMap()); final long expectedContentLength = mre.getContentLength(); // get real bytes - final Body multipartBody = new MultipartBody(parts, mre.getContentType(), expectedContentLength); + final Body multipartBody = new MultipartBody(parts, mre.getContentType(), expectedContentLength, mre.getMultipartBoundary()); try { final ByteBuffer buffer = ByteBuffer.allocate(8192); boolean last = false; From 997f6a0c0e00f1a05e4ed983e0221afa20726b3d Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 23 Jul 2014 18:38:05 +0200 Subject: [PATCH 466/701] Use SslContext.getDefault, close #644 --- .../java/com/ning/http/util/SslUtils.java | 48 ++++++++----------- 1 file changed, 19 insertions(+), 29 deletions(-) diff --git a/src/main/java/com/ning/http/util/SslUtils.java b/src/main/java/com/ning/http/util/SslUtils.java index ec4d84716e..5d09e407b9 100644 --- a/src/main/java/com/ning/http/util/SslUtils.java +++ b/src/main/java/com/ning/http/util/SslUtils.java @@ -15,42 +15,18 @@ */ package com.ning.http.util; -import com.ning.http.client.AsyncHttpClientConfig; - import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLEngine; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; import java.io.IOException; import java.security.GeneralSecurityException; +import java.security.KeyManagementException; +import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; public class SslUtils { - private static class SingletonHolder { - public static final SslUtils instance = new SslUtils(); - } - - public static SslUtils getInstance() { - return SingletonHolder.instance; - } - - public SSLEngine createClientSSLEngine(AsyncHttpClientConfig config, String peerHost, int peerPort) throws GeneralSecurityException, IOException { - SSLContext sslContext = config.getSSLContext(); - if (sslContext == null) { - sslContext = SslUtils.getInstance().getSSLContext(config.isAcceptAnyCertificate()); - } - SSLEngine sslEngine = sslContext.createSSLEngine(peerHost, peerPort); - sslEngine.setUseClientMode(true); - return sslEngine; - } - - public SSLContext getSSLContext(boolean acceptAnyCertificate) throws GeneralSecurityException, IOException { - // SSLContext.getDefault() doesn't exist in JDK5 - return acceptAnyCertificate ? looseTrustManagerSSLContext : SSLContext.getInstance("Default"); - } - static class LooseTrustManager implements X509TrustManager { public java.security.cert.X509Certificate[] getAcceptedIssuers() { @@ -64,15 +40,29 @@ public void checkServerTrusted(java.security.cert.X509Certificate[] certs, Strin } } - private SSLContext looseTrustManagerSSLContext = looseTrustManagerSSLContext(); - + private SSLContext looseTrustManagerSSLContext = looseTrustManagerSSLContext(); + private SSLContext looseTrustManagerSSLContext() { try { SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(null, new TrustManager[] { new LooseTrustManager() }, new SecureRandom()); return sslContext; - } catch (Exception e) { + } catch (NoSuchAlgorithmException e) { + throw new ExceptionInInitializerError(e); + } catch (KeyManagementException e) { throw new ExceptionInInitializerError(e); } } + + private static class SingletonHolder { + public static final SslUtils instance = new SslUtils(); + } + + public static SslUtils getInstance() { + return SingletonHolder.instance; + } + + public SSLContext getSSLContext(boolean acceptAnyCertificate) throws GeneralSecurityException, IOException { + return acceptAnyCertificate? looseTrustManagerSSLContext: SSLContext.getDefault(); + } } From 6c2cb460dace5f43cf7c32758a63f5c6722483f2 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 23 Jul 2014 18:41:40 +0200 Subject: [PATCH 467/701] Fix build, honor acceptAnyCertificate, close #644 --- .../http/client/providers/netty/channel/ChannelManager.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java b/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java index 32f85f7ee6..04b4bda569 100644 --- a/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java +++ b/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java @@ -346,8 +346,7 @@ private HttpClientCodec newHttpClientCodec() { } public SslHandler createSslHandler(String peerHost, int peerPort) throws GeneralSecurityException, IOException { - // FIXME use SslContext.defaultContext - SSLEngine sslEngine = SslUtils.getInstance().createClientSSLEngine(config, peerHost, peerPort); + SSLEngine sslEngine = SslUtils.getInstance().getSSLContext(config.isAcceptAnyCertificate()).createSSLEngine(); return handshakeTimeoutInMillis > 0 ? new SslHandler(sslEngine, getDefaultBufferPool(), false, nettyTimer, handshakeTimeoutInMillis) : new SslHandler(sslEngine); } From 2682a407bd43eff6cc786541690f087ef0ab2e81 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 23 Jul 2014 20:09:55 +0200 Subject: [PATCH 468/701] [maven-release-plugin] prepare release async-http-client-1.9.0-BETA3 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 824c0acaff..3f2c2c6c9b 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.9.0-SNAPSHOT + 1.9.0-BETA3 jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From 27b06737c55b3059223a138ef1a648b20509ddfb Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 23 Jul 2014 20:09:59 +0200 Subject: [PATCH 469/701] [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 3f2c2c6c9b..5db9ef0154 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.9.0-BETA3 + async-http-client-1.9.0-SNAPSHOT jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From 8ea73c627f507ed53e052db4a43a76ee7a189e6c Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 24 Jul 2014 10:44:04 +0200 Subject: [PATCH 470/701] Fix version --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 5db9ef0154..824c0acaff 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - async-http-client-1.9.0-SNAPSHOT + 1.9.0-SNAPSHOT jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From 028fef6e6cccc6aa19b1c020b850e951ba95b08f Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 24 Jul 2014 10:55:12 +0200 Subject: [PATCH 471/701] Who would write schemes not in lower case?! --- .../com/ning/http/client/providers/netty/util/HttpUtils.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/util/HttpUtils.java b/src/main/java/com/ning/http/client/providers/netty/util/HttpUtils.java index 67d08fe3a3..ec9ff1c0a9 100644 --- a/src/main/java/com/ning/http/client/providers/netty/util/HttpUtils.java +++ b/src/main/java/com/ning/http/client/providers/netty/util/HttpUtils.java @@ -48,11 +48,11 @@ public static List getNettyHeaderValuesByCaseInsensitiveName(HttpHeaders } public static boolean isWebSocket(String scheme) { - return WEBSOCKET.equalsIgnoreCase(scheme) || WEBSOCKET_SSL.equalsIgnoreCase(scheme); + return WEBSOCKET.equals(scheme) || WEBSOCKET_SSL.equalsIgnoreCase(scheme); } public static boolean isSecure(String scheme) { - return HTTPS.equalsIgnoreCase(scheme) || WEBSOCKET_SSL.equalsIgnoreCase(scheme); + return HTTPS.equals(scheme) || WEBSOCKET_SSL.equals(scheme); } public static boolean isSecure(UriComponents uri) { From d78a94bdd3776f2d782e2074dd0966c58b274bbf Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 24 Jul 2014 11:27:54 +0200 Subject: [PATCH 472/701] Rename attachment into attribute --- .../netty/channel/ChannelManager.java | 36 ++++++++++------- .../providers/netty/channel/Channels.java | 8 ++-- .../channel/pool/DefaultChannelPool.java | 6 +-- .../providers/netty/handler/HttpProtocol.java | 2 +- .../providers/netty/handler/Processor.java | 40 +++++++++---------- .../providers/netty/handler/Protocol.java | 2 +- .../netty/handler/WebSocketProtocol.java | 4 +- .../netty/request/NettyRequestSender.java | 8 ++-- .../request/body/NettyConnectListener.java | 4 +- 9 files changed, 59 insertions(+), 51 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java b/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java index 04b4bda569..0f0d858d68 100644 --- a/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java +++ b/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java @@ -293,9 +293,9 @@ public void close() { openChannels.close(); for (Channel channel : openChannels) { - Object attachment = Channels.getAttachment(channel); - if (attachment instanceof NettyResponseFuture) { - NettyResponseFuture future = (NettyResponseFuture) attachment; + Object attribute = Channels.getAttribute(channel); + if (attribute instanceof NettyResponseFuture) { + NettyResponseFuture future = (NettyResponseFuture) attribute; future.cancelTimeouts(); } } @@ -351,19 +351,26 @@ public SslHandler createSslHandler(String peerHost, int peerPort) throws General : new SslHandler(sslEngine); } + public SslHandler getSslHandler(ChannelPipeline pipeline) { + return (SslHandler) pipeline.get(SSL_HANDLER); + } + + private boolean isSslHandlerConfigured(ChannelPipeline pipeline) { + return pipeline.get(SSL_HANDLER) != null; + } + public void upgradeProtocol(ChannelPipeline pipeline, String scheme, String host, int port) throws IOException, GeneralSecurityException { if (pipeline.get(HTTP_HANDLER) != null) pipeline.remove(HTTP_HANDLER); if (isSecure(scheme)) - if (pipeline.get(SSL_HANDLER) == null) { + if (isSslHandlerConfigured(pipeline)){ + pipeline.addAfter(SSL_HANDLER, HTTP_HANDLER, newHttpClientCodec()); + } else { pipeline.addFirst(HTTP_HANDLER, newHttpClientCodec()); pipeline.addFirst(SSL_HANDLER, createSslHandler(host, port)); - } else { - pipeline.addAfter(SSL_HANDLER, HTTP_HANDLER, newHttpClientCodec()); } - else pipeline.addFirst(HTTP_HANDLER, newHttpClientCodec()); @@ -377,13 +384,14 @@ public String getPoolKey(NettyResponseFuture future) { public void verifyChannelPipeline(ChannelPipeline pipeline, String scheme) throws IOException, GeneralSecurityException { - boolean isSecure = isSecure(scheme); - if (pipeline.get(SSL_HANDLER) != null) { - if (!isSecure) - pipeline.remove(SSL_HANDLER); + boolean sslHandlerConfigured = isSslHandlerConfigured(pipeline); + + if (isSecure(scheme)) { + if (!sslHandlerConfigured) + pipeline.addFirst(SSL_HANDLER, new SslInitializer(this)); - } else if (isSecure) - pipeline.addFirst(SSL_HANDLER, new SslInitializer(this)); + } else if (sslHandlerConfigured) + pipeline.remove(SSL_HANDLER); } public ClientBootstrap getBootstrap(String scheme, boolean useProxy, boolean useSSl) { @@ -408,6 +416,6 @@ public void call() throws Exception { } public void drainChannel(final Channel channel, final NettyResponseFuture future) { - Channels.setAttachment(channel, newDrainCallback(future, channel, future.isKeepAlive(), getPoolKey(future))); + Channels.setAttribute(channel, newDrainCallback(future, channel, future.isKeepAlive(), getPoolKey(future))); } } diff --git a/src/main/java/com/ning/http/client/providers/netty/channel/Channels.java b/src/main/java/com/ning/http/client/providers/netty/channel/Channels.java index 2af934eca4..378b668e93 100644 --- a/src/main/java/com/ning/http/client/providers/netty/channel/Channels.java +++ b/src/main/java/com/ning/http/client/providers/netty/channel/Channels.java @@ -22,16 +22,16 @@ public final class Channels { private Channels() { } - public static void setAttachment(Channel channel, Object attachment) { - channel.setAttachment(attachment); + public static void setAttribute(Channel channel, Object attribute) { + channel.setAttachment(attribute); } - public static Object getAttachment(Channel channel) { + public static Object getAttribute(Channel channel) { return channel.getAttachment(); } public static void setDiscard(Channel channel) { - setAttachment(channel, DiscardEvent.INSTANCE); + setAttribute(channel, DiscardEvent.INSTANCE); } public static boolean isChannelValid(Channel channel) { diff --git a/src/main/java/com/ning/http/client/providers/netty/channel/pool/DefaultChannelPool.java b/src/main/java/com/ning/http/client/providers/netty/channel/pool/DefaultChannelPool.java index 4d67d33afe..225b4260e7 100644 --- a/src/main/java/com/ning/http/client/providers/netty/channel/pool/DefaultChannelPool.java +++ b/src/main/java/com/ning/http/client/providers/netty/channel/pool/DefaultChannelPool.java @@ -146,9 +146,9 @@ private List expiredChannels(ConcurrentLinkedQueue poo } private boolean isChannelCloseable(Channel channel) { - Object attachment = Channels.getAttachment(channel); - if (attachment instanceof NettyResponseFuture) { - NettyResponseFuture future = (NettyResponseFuture) attachment; + Object attribute = Channels.getAttribute(channel); + if (attribute instanceof NettyResponseFuture) { + NettyResponseFuture future = (NettyResponseFuture) attribute; if (!future.isDone()) LOGGER.error("Future not in appropriate state %s, not closing", future); } diff --git a/src/main/java/com/ning/http/client/providers/netty/handler/HttpProtocol.java b/src/main/java/com/ning/http/client/providers/netty/handler/HttpProtocol.java index 7c8b5bcfe6..d3ea33fb52 100644 --- a/src/main/java/com/ning/http/client/providers/netty/handler/HttpProtocol.java +++ b/src/main/java/com/ning/http/client/providers/netty/handler/HttpProtocol.java @@ -246,7 +246,7 @@ public void call() throws Exception { if (future.isKeepAlive() && HttpHeaders.isTransferEncodingChunked(response)) // We must make sure there is no bytes left // before executing the next request. - Channels.setAttachment(channel, callback); + Channels.setAttribute(channel, callback); else callback.call(); diff --git a/src/main/java/com/ning/http/client/providers/netty/handler/Processor.java b/src/main/java/com/ning/http/client/providers/netty/handler/Processor.java index 6d44b49393..42200cf50c 100644 --- a/src/main/java/com/ning/http/client/providers/netty/handler/Processor.java +++ b/src/main/java/com/ning/http/client/providers/netty/handler/Processor.java @@ -69,14 +69,14 @@ public void messageReceived(final ChannelHandlerContext ctx, MessageEvent e) thr super.messageReceived(ctx, e); Channel channel = ctx.getChannel(); - Object attachment = Channels.getAttachment(channel); + Object attribute = Channels.getAttribute(channel); - if (attachment == null) - LOGGER.debug("ChannelHandlerContext doesn't have any attachment"); + if (attribute == null) + LOGGER.debug("ChannelHandlerContext doesn't have any attribute"); - if (attachment instanceof Callback) { + if (attribute instanceof Callback) { Object message = e.getMessage(); - Callback ac = (Callback) attachment; + Callback ac = (Callback) attribute; if (message instanceof HttpChunk) { // the AsyncCallable is to be processed on the last chunk if (HttpChunk.class.cast(message).isLast()) @@ -88,11 +88,11 @@ public void messageReceived(final ChannelHandlerContext ctx, MessageEvent e) thr Channels.setDiscard(channel); } - } else if (attachment instanceof NettyResponseFuture) { - NettyResponseFuture future = (NettyResponseFuture) attachment; + } else if (attribute instanceof NettyResponseFuture) { + NettyResponseFuture future = (NettyResponseFuture) attribute; protocol.handle(channel, future, e.getMessage()); - } else if (attachment != DiscardEvent.INSTANCE) { + } else if (attribute != DiscardEvent.INSTANCE) { // unhandled message try { ctx.getChannel().close(); @@ -117,16 +117,16 @@ public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws LOGGER.trace("super.channelClosed", ex); } - Object attachment = Channels.getAttachment(channel); - LOGGER.debug("Channel Closed: {} with attachment {}", channel, attachment); + Object attribute = Channels.getAttribute(channel); + LOGGER.debug("Channel Closed: {} with attribute {}", channel, attribute); - if (attachment instanceof Callback) { - Callback callback = (Callback) attachment; - Channels.setAttachment(channel, callback.future()); + if (attribute instanceof Callback) { + Callback callback = (Callback) attribute; + Channels.setAttribute(channel, callback.future()); callback.call(); - } else if (attachment instanceof NettyResponseFuture) { - NettyResponseFuture future = (NettyResponseFuture) attachment; + } else if (attribute instanceof NettyResponseFuture) { + NettyResponseFuture future = (NettyResponseFuture) attribute; future.touch(); if (!config.getIOExceptionFilters().isEmpty() @@ -155,9 +155,9 @@ public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws LOGGER.debug("Unexpected I/O exception on channel {}", channel, cause); try { - Object attachment = Channels.getAttachment(channel); - if (attachment instanceof NettyResponseFuture) { - future = (NettyResponseFuture) attachment; + Object attribute = Channels.getAttribute(channel); + if (attribute instanceof NettyResponseFuture) { + future = (NettyResponseFuture) attribute; future.attachChannel(null, false); future.touch(); @@ -182,8 +182,8 @@ public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws LOGGER.debug("Trying to recover from dead Channel: {}", channel); return; } - } else if (attachment instanceof Callback) { - future = ((Callback) attachment).future(); + } else if (attribute instanceof Callback) { + future = ((Callback) attribute).future(); } } catch (Throwable t) { cause = t; diff --git a/src/main/java/com/ning/http/client/providers/netty/handler/Protocol.java b/src/main/java/com/ning/http/client/providers/netty/handler/Protocol.java index c9bfe7c634..e03e2b1d60 100644 --- a/src/main/java/com/ning/http/client/providers/netty/handler/Protocol.java +++ b/src/main/java/com/ning/http/client/providers/netty/handler/Protocol.java @@ -145,7 +145,7 @@ protected boolean exitAfterHandlingRedirect(// // We must make sure there is no bytes left before // executing the next request. // FIXME investigate this - Channels.setAttachment(channel, callback); + Channels.setAttribute(channel, callback); } else { // FIXME don't understand: this offers the connection to the pool, or even closes it, while the // request has not been sent, right? diff --git a/src/main/java/com/ning/http/client/providers/netty/handler/WebSocketProtocol.java b/src/main/java/com/ning/http/client/providers/netty/handler/WebSocketProtocol.java index fe70261cd8..1382ac37fe 100644 --- a/src/main/java/com/ning/http/client/providers/netty/handler/WebSocketProtocol.java +++ b/src/main/java/com/ning/http/client/providers/netty/handler/WebSocketProtocol.java @@ -177,7 +177,7 @@ public void setContent(ChannelBuffer content) { @Override public void onError(Channel channel, Throwable e) { try { - Object attribute = Channels.getAttachment(channel); + Object attribute = Channels.getAttribute(channel); logger.warn("onError {}", e); if (!(attribute instanceof NettyResponseFuture)) { return; @@ -199,7 +199,7 @@ public void onError(Channel channel, Throwable e) { @Override public void onClose(Channel channel) { logger.trace("onClose {}"); - Object attribute = Channels.getAttachment(channel); + Object attribute = Channels.getAttribute(channel); if (!(attribute instanceof NettyResponseFuture)) return; diff --git a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java index 5accbe8e5d..51756b4b8a 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java @@ -202,7 +202,7 @@ private ListenableFuture sendRequestWithCachedChannel(Request request, Ur future.attachChannel(channel, false); LOGGER.debug("\nUsing cached Channel {}\n for request \n{}\n", channel, future.getNettyRequest().getHttpRequest()); - Channels.setAttachment(channel, future); + Channels.setAttribute(channel, future); try { writeRequest(future, channel); @@ -416,9 +416,9 @@ public boolean retry(NettyResponseFuture future, Channel channel) { // channelManager.removeAll(channel); if (future == null) { - Object attachment = Channels.getAttachment(channel); - if (attachment instanceof NettyResponseFuture) - future = (NettyResponseFuture) attachment; + Object attribute = Channels.getAttribute(channel); + if (attribute instanceof NettyResponseFuture) + future = (NettyResponseFuture) attribute; } if (future != null && future.canBeReplayed()) { diff --git a/src/main/java/com/ning/http/client/providers/netty/request/body/NettyConnectListener.java b/src/main/java/com/ning/http/client/providers/netty/request/body/NettyConnectListener.java index d94c415995..df24add34a 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/body/NettyConnectListener.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/body/NettyConnectListener.java @@ -90,8 +90,8 @@ private void writeRequest(Channel channel, String poolKey) { public final void operationComplete(ChannelFuture f) throws Exception { Channel channel = f.getChannel(); if (f.isSuccess()) { - Channels.setAttachment(channel, future); - final SslHandler sslHandler = (SslHandler) channel.getPipeline().get(ChannelManager.SSL_HANDLER); + Channels.setAttribute(channel, future); + final SslHandler sslHandler = channelManager.getSslHandler(channel.getPipeline()); final HostnameVerifier hostnameVerifier = config.getHostnameVerifier(); if (hostnameVerifier != null && sslHandler != null) { From d0b727d6f0605dacf71e4fdd066e73ad643ddb62 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 24 Jul 2014 14:03:24 +0200 Subject: [PATCH 473/701] Properly set SSLEngine client mode, back port SSLEngineFactory, close #646 --- .../ning/http/client/SSLEngineFactory.java | 31 +++++++++++++++++++ .../netty/NettyAsyncHttpProviderConfig.java | 19 +++++++++--- .../netty/channel/ChannelManager.java | 15 ++++++++- 3 files changed, 60 insertions(+), 5 deletions(-) create mode 100644 src/main/java/com/ning/http/client/SSLEngineFactory.java diff --git a/src/main/java/com/ning/http/client/SSLEngineFactory.java b/src/main/java/com/ning/http/client/SSLEngineFactory.java new file mode 100644 index 0000000000..ec34af3871 --- /dev/null +++ b/src/main/java/com/ning/http/client/SSLEngineFactory.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2014 AsyncHttpClient Project. 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; + +import javax.net.ssl.SSLEngine; + +import java.security.GeneralSecurityException; + +/** + * Factory that creates an {@link SSLEngine} to be used for a single SSL connection. + */ +public interface SSLEngineFactory { + /** + * Creates new {@link SSLEngine}. + * + * @return new engine + * @throws GeneralSecurityException if the SSLEngine cannot be created + */ + SSLEngine newSSLEngine() throws GeneralSecurityException; +} 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 eb00258341..4d03c31171 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 @@ -17,6 +17,7 @@ import org.jboss.netty.util.Timer; import com.ning.http.client.AsyncHttpProviderConfig; +import com.ning.http.client.SSLEngineFactory; import com.ning.http.client.providers.netty.channel.pool.ChannelPool; import java.util.Map; @@ -28,7 +29,7 @@ * This class can be used to pass Netty's internal configuration options. See Netty documentation for more information. */ public class NettyAsyncHttpProviderConfig implements AsyncHttpProviderConfig { - + private final ConcurrentHashMap properties = new ConcurrentHashMap(); /** @@ -104,14 +105,16 @@ public Set> propertiesSet() { private int httpClientCodecMaxInitialLineLength = 4096; private int httpClientCodecMaxHeaderSize = 8192; private int httpClientCodecMaxChunkSize = 8192; - + /** * Allow configuring the Netty's socket channel factory. */ private NioClientSocketChannelFactory socketChannelFactory; + private ChannelPool channelPool; + /** - * Allow one to disable zero copy for bodies and use chunking instead; + * Allow one to disable zero copy for bodies and use chunking instead */ private boolean disableZeroCopy; @@ -119,7 +122,7 @@ public Set> propertiesSet() { private long handshakeTimeoutInMillis = 10000L; - private ChannelPool channelPool; + private SSLEngineFactory sslEngineFactory; /** * chunkedFileChunkSize @@ -206,6 +209,14 @@ public void setChannelPool(ChannelPool channelPool) { this.channelPool = channelPool; } + public SSLEngineFactory getSslEngineFactory() { + return sslEngineFactory; + } + + public void setSslEngineFactory(SSLEngineFactory sslEngineFactory) { + this.sslEngineFactory = sslEngineFactory; + } + public int getChunkedFileChunkSize() { return chunkedFileChunkSize; } diff --git a/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java b/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java index 0f0d858d68..a22a416737 100644 --- a/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java +++ b/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java @@ -51,6 +51,7 @@ import com.ning.http.client.providers.netty.request.NettyRequestSender; import com.ning.http.util.SslUtils; +import javax.net.ssl.SSLContext; import javax.net.ssl.SSLEngine; import java.io.IOException; @@ -346,7 +347,19 @@ private HttpClientCodec newHttpClientCodec() { } public SslHandler createSslHandler(String peerHost, int peerPort) throws GeneralSecurityException, IOException { - SSLEngine sslEngine = SslUtils.getInstance().getSSLContext(config.isAcceptAnyCertificate()).createSSLEngine(); + SSLEngine sslEngine = null; + if (nettyConfig.getSslEngineFactory() != null) { + sslEngine = nettyConfig.getSslEngineFactory().newSSLEngine(); + + } else { + SSLContext sslContext = config.getSSLContext(); + if (sslContext == null) + sslContext = SslUtils.getInstance().getSSLContext(config.isAcceptAnyCertificate()); + + sslEngine = sslContext.createSSLEngine(peerHost, peerPort); + sslEngine.setUseClientMode(true); + } + return handshakeTimeoutInMillis > 0 ? new SslHandler(sslEngine, getDefaultBufferPool(), false, nettyTimer, handshakeTimeoutInMillis) : new SslHandler(sslEngine); } From 2655fcf5382cd385661c0f462bcb08c4374b9582 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 24 Jul 2014 14:15:51 +0200 Subject: [PATCH 474/701] Notify FeedableBodyGenerator --- .../netty/channel/ChannelManager.java | 4 +-- .../netty/request/body/NettyBodyBody.java | 31 +++++++++++++------ .../request/body/NettyConnectListener.java | 2 +- .../netty/request/body/NettyFileBody.java | 5 ++- 4 files changed, 27 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java b/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java index a22a416737..9e9d1f02bf 100644 --- a/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java +++ b/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java @@ -364,11 +364,11 @@ public SslHandler createSslHandler(String peerHost, int peerPort) throws General : new SslHandler(sslEngine); } - public SslHandler getSslHandler(ChannelPipeline pipeline) { + public static SslHandler getSslHandler(ChannelPipeline pipeline) { return (SslHandler) pipeline.get(SSL_HANDLER); } - private boolean isSslHandlerConfigured(ChannelPipeline pipeline) { + public static boolean isSslHandlerConfigured(ChannelPipeline pipeline) { return pipeline.get(SSL_HANDLER) != null; } diff --git a/src/main/java/com/ning/http/client/providers/netty/request/body/NettyBodyBody.java b/src/main/java/com/ning/http/client/providers/netty/request/body/NettyBodyBody.java index 523cf6e858..d074f64f62 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/body/NettyBodyBody.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/body/NettyBodyBody.java @@ -15,15 +15,19 @@ import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFuture; -import org.jboss.netty.handler.ssl.SslHandler; +import org.jboss.netty.handler.stream.ChunkedWriteHandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.Body; +import com.ning.http.client.BodyGenerator; import com.ning.http.client.RandomAccessBody; import com.ning.http.client.providers.netty.NettyAsyncHttpProviderConfig; +import com.ning.http.client.providers.netty.channel.ChannelManager; import com.ning.http.client.providers.netty.future.NettyResponseFuture; +import com.ning.http.client.providers.netty.request.FeedableBodyGenerator; +import com.ning.http.client.providers.netty.request.FeedableBodyGenerator.FeedListener; import com.ning.http.client.providers.netty.request.ProgressListener; import java.io.IOException; @@ -57,16 +61,25 @@ public String getContentType() { @Override public void write(final Channel channel, NettyResponseFuture future, AsyncHttpClientConfig config) throws IOException { - ChannelFuture writeFuture; - boolean ssl = channel.getPipeline().get(SslHandler.class) != null; - if (ssl || !(body instanceof RandomAccessBody) || nettyConfig.isDisableZeroCopy()) { - BodyChunkedInput bodyChunkedInput = new BodyChunkedInput(body); - writeFuture = channel.write(bodyChunkedInput); + Object msg; + if (!ChannelManager.isSslHandlerConfigured(channel.getPipeline()) && body instanceof RandomAccessBody && !nettyConfig.isDisableZeroCopy()) { + msg = new BodyFileRegion((RandomAccessBody) body); + } else { - BodyFileRegion bodyFileRegion = new BodyFileRegion((RandomAccessBody) body); - writeFuture = channel.write(bodyFileRegion); + msg = new BodyChunkedInput(body); + + BodyGenerator bg = future.getRequest().getBodyGenerator(); + if (bg instanceof FeedableBodyGenerator) { + FeedableBodyGenerator.class.cast(bg).setListener(new FeedListener() { + @Override + public void onContentAdded() { + channel.getPipeline().get(ChunkedWriteHandler.class).resumeTransfer(); + } + }); + } } - writeFuture.addListener(new ProgressListener(config, future.getAsyncHandler(), future, false) { + + channel.write(msg).addListener(new ProgressListener(config, future.getAsyncHandler(), future, false) { public void operationComplete(ChannelFuture cf) { try { body.close(); diff --git a/src/main/java/com/ning/http/client/providers/netty/request/body/NettyConnectListener.java b/src/main/java/com/ning/http/client/providers/netty/request/body/NettyConnectListener.java index df24add34a..e7e028c7d7 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/body/NettyConnectListener.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/body/NettyConnectListener.java @@ -91,7 +91,7 @@ public final void operationComplete(ChannelFuture f) throws Exception { Channel channel = f.getChannel(); if (f.isSuccess()) { Channels.setAttribute(channel, future); - final SslHandler sslHandler = channelManager.getSslHandler(channel.getPipeline()); + final SslHandler sslHandler = ChannelManager.getSslHandler(channel.getPipeline()); final HostnameVerifier hostnameVerifier = config.getHostnameVerifier(); if (hostnameVerifier != null && sslHandler != null) { diff --git a/src/main/java/com/ning/http/client/providers/netty/request/body/NettyFileBody.java b/src/main/java/com/ning/http/client/providers/netty/request/body/NettyFileBody.java index 45d16ddb12..09c5b911ff 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/body/NettyFileBody.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/body/NettyFileBody.java @@ -16,13 +16,13 @@ import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.FileRegion; -import org.jboss.netty.handler.ssl.SslHandler; import org.jboss.netty.handler.stream.ChunkedFile; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.providers.netty.NettyAsyncHttpProviderConfig; +import com.ning.http.client.providers.netty.channel.ChannelManager; import com.ning.http.client.providers.netty.future.NettyResponseFuture; import com.ning.http.client.providers.netty.request.ProgressListener; @@ -77,10 +77,9 @@ public String getContentType() { public void write(Channel channel, NettyResponseFuture future, AsyncHttpClientConfig config) throws IOException { final RandomAccessFile raf = new RandomAccessFile(file, "r"); - boolean ssl = channel.getPipeline().get(SslHandler.class) != null; try { ChannelFuture writeFuture; - if (ssl || nettyConfig.isDisableZeroCopy()) { + if (ChannelManager.isSslHandlerConfigured(channel.getPipeline()) || nettyConfig.isDisableZeroCopy()) { writeFuture = channel.write(new ChunkedFile(raf, 0, raf.length(), nettyConfig.getChunkedFileChunkSize())); } else { final FileRegion region = new OptimizedFileRegion(raf, 0, raf.length()); From dc8e3a82c274149323a3d5d2ac978e4414d63a68 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 24 Jul 2014 14:30:43 +0200 Subject: [PATCH 475/701] Make transferEncoding configurable, fix FilePart constructors, close #647 --- .../client/multipart/AbstractFilePart.java | 9 ++++--- .../http/client/multipart/ByteArrayPart.java | 11 +++++--- .../ning/http/client/multipart/FilePart.java | 27 ++++++++++--------- .../ning/http/client/multipart/PartBase.java | 10 ++++--- .../http/client/multipart/StringPart.java | 3 +-- 5 files changed, 35 insertions(+), 25 deletions(-) diff --git a/src/main/java/com/ning/http/client/multipart/AbstractFilePart.java b/src/main/java/com/ning/http/client/multipart/AbstractFilePart.java index 7b44027950..dbe2f7755d 100644 --- a/src/main/java/com/ning/http/client/multipart/AbstractFilePart.java +++ b/src/main/java/com/ning/http/client/multipart/AbstractFilePart.java @@ -55,9 +55,12 @@ public abstract class AbstractFilePart extends PartBase { * @param charset * the charset encoding for this part */ - public AbstractFilePart(String name, String contentType, String charset, String contentId) { - super(name, contentType == null ? DEFAULT_CONTENT_TYPE : contentType, charset, - DEFAULT_TRANSFER_ENCODING, contentId); + public AbstractFilePart(String name, String contentType, String charset, String contentId, String transferEncoding) { + super(name,// + contentType == null ? DEFAULT_CONTENT_TYPE : contentType,// + charset,// + contentId, // + transferEncoding == null ? DEFAULT_TRANSFER_ENCODING : transferEncoding); } protected void visitDispositionHeader(PartVisitor visitor) throws IOException { diff --git a/src/main/java/com/ning/http/client/multipart/ByteArrayPart.java b/src/main/java/com/ning/http/client/multipart/ByteArrayPart.java index 6977d3ff4b..c4800bb5f3 100644 --- a/src/main/java/com/ning/http/client/multipart/ByteArrayPart.java +++ b/src/main/java/com/ning/http/client/multipart/ByteArrayPart.java @@ -37,14 +37,17 @@ public ByteArrayPart(String name, byte[] bytes, String contentType, String chars } public ByteArrayPart(String name, byte[] bytes, String contentType, String charset, String fileName, String contentId) { - super(name, contentType, charset, contentId); - if (bytes == null) { + this(name, bytes, contentType, charset, fileName, contentId, null); + } + + public ByteArrayPart(String name, byte[] bytes, String contentType, String charset, String fileName, String contentId, String transferEncoding) { + super(name, contentType, charset, contentId, transferEncoding); + if (bytes == null) throw new NullPointerException("bytes"); - } this.bytes = bytes; setFileName(fileName); } - + @Override protected void sendData(OutputStream out) throws IOException { out.write(bytes); diff --git a/src/main/java/com/ning/http/client/multipart/FilePart.java b/src/main/java/com/ning/http/client/multipart/FilePart.java index 64e8727f22..6932a28fa9 100644 --- a/src/main/java/com/ning/http/client/multipart/FilePart.java +++ b/src/main/java/com/ning/http/client/multipart/FilePart.java @@ -31,36 +31,37 @@ public class FilePart extends AbstractFilePart { private final File file; public FilePart(String name, File file) { - this(name, file, null, null); + this(name, file, null); } public FilePart(String name, File file, String contentType) { - this(name, file, null, contentType, null); + this(name, file, contentType, null); } public FilePart(String name, File file, String contentType, String charset) { - this(name, file, null, contentType, charset, null); + this(name, file, contentType, charset, null); } public FilePart(String name, File file, String contentType, String charset, String fileName) { - this(name, file, null, contentType, charset, fileName); + this(name, file, contentType, charset, fileName, null); } public FilePart(String name, File file, String contentType, String charset, String fileName, String contentId) { - super(name, contentType, charset, contentId); - this.file = file; - if (file == null) { + this(name, file, contentType, charset, fileName, contentId, null); + } + + public FilePart(String name, File file, String contentType, String charset, String fileName, String contentId, String transferEncoding) { + super(name, contentType, charset, contentId, transferEncoding); + if (file == null) throw new NullPointerException("file"); - } - if (!file.isFile()) { + if (!file.isFile()) throw new IllegalArgumentException("File is not a normal file " + file.getAbsolutePath()); - } - if (!file.canRead()) { + if (!file.canRead()) throw new IllegalArgumentException("File is not readable " + file.getAbsolutePath()); - } + this.file = file; setFileName(fileName != null ? fileName : file.getName()); } - + @Override protected void sendData(OutputStream out) throws IOException { if (getDataLength() == 0) { diff --git a/src/main/java/com/ning/http/client/multipart/PartBase.java b/src/main/java/com/ning/http/client/multipart/PartBase.java index 8819b0fbba..c7805d8897 100644 --- a/src/main/java/com/ning/http/client/multipart/PartBase.java +++ b/src/main/java/com/ning/http/client/multipart/PartBase.java @@ -49,21 +49,25 @@ public abstract class PartBase implements Part { */ private String dispositionType; + public PartBase(String name, String contentType, String charSet, String contentId) { + this(name, contentType, charSet, contentId, null); + } + /** * Constructor. * * @param name The name of the part, or null * @param contentType The content type, or null * @param charSet The character encoding, or null - * @param transferEncoding The transfer encoding, or null * @param contentId The content id, or null + * @param transferEncoding The transfer encoding, or null */ - public PartBase(String name, String contentType, String charSet, String transferEncoding, String contentId) { + public PartBase(String name, String contentType, String charSet, String contentId, String transferEncoding) { this.name = name; this.contentType = contentType; this.charSet = charSet; - this.transferEncoding = transferEncoding; this.contentId = contentId; + this.transferEncoding = transferEncoding; } protected void visitStart(PartVisitor visitor, byte[] boundary) throws IOException { diff --git a/src/main/java/com/ning/http/client/multipart/StringPart.java b/src/main/java/com/ning/http/client/multipart/StringPart.java index 9f46bcd866..8a87a89a5c 100644 --- a/src/main/java/com/ning/http/client/multipart/StringPart.java +++ b/src/main/java/com/ning/http/client/multipart/StringPart.java @@ -58,8 +58,7 @@ public StringPart(String name, String value, String charset) { * the content id */ public StringPart(String name, String value, String charset, String contentId) { - - super(name, DEFAULT_CONTENT_TYPE, charset == null ? DEFAULT_CHARSET : charset, DEFAULT_TRANSFER_ENCODING, contentId); + super(name, DEFAULT_CONTENT_TYPE, charset == null ? DEFAULT_CHARSET : charset, contentId, DEFAULT_TRANSFER_ENCODING); if (value == null) { throw new NullPointerException("value"); } From 9d87b9a46c825145b8a4908a6712ee4981e400a9 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 24 Jul 2014 14:43:14 +0200 Subject: [PATCH 476/701] minor clean up --- src/main/java/com/ning/http/client/multipart/ByteArrayPart.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/ning/http/client/multipart/ByteArrayPart.java b/src/main/java/com/ning/http/client/multipart/ByteArrayPart.java index c4800bb5f3..7f5933e40d 100644 --- a/src/main/java/com/ning/http/client/multipart/ByteArrayPart.java +++ b/src/main/java/com/ning/http/client/multipart/ByteArrayPart.java @@ -47,7 +47,7 @@ public ByteArrayPart(String name, byte[] bytes, String contentType, String chars this.bytes = bytes; setFileName(fileName); } - + @Override protected void sendData(OutputStream out) throws IOException { out.write(bytes); From e514e3bb4a13d05b222cd35436b4050db2828315 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 24 Jul 2014 14:44:07 +0200 Subject: [PATCH 477/701] [maven-release-plugin] prepare release async-http-client-1.9.0-BETA4 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 824c0acaff..4daff2c3fe 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.9.0-SNAPSHOT + 1.9.0-BETA4 jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From 0ab527b3c02e281c5706b5378d909c055ded233f Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 24 Jul 2014 14:44:11 +0200 Subject: [PATCH 478/701] [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 4daff2c3fe..824c0acaff 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.9.0-BETA4 + 1.9.0-SNAPSHOT jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From 9c03760b0de5dd4383a6025e0178248d870b1e12 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 24 Jul 2014 17:13:20 +0200 Subject: [PATCH 479/701] Drop useless broken test --- .../client/async/AsyncStreamHandlerTest.java | 43 +------------------ 1 file changed, 1 insertion(+), 42 deletions(-) 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 2a5a79e6f2..5336e23c15 100644 --- a/src/test/java/com/ning/http/client/async/AsyncStreamHandlerTest.java +++ b/src/test/java/com/ning/http/client/async/AsyncStreamHandlerTest.java @@ -330,54 +330,13 @@ public String onCompleted() throws Exception { } } - @Test(groups = { "online", "default_provider" }) - public void asyncStream302WithBody() throws Exception { - AsyncHttpClient client = getAsyncHttpClient(null); - final AtomicReference statusCode = new AtomicReference(0); - final AtomicReference headers = new AtomicReference(); - try { - Future f = client.prepareGet("http://google.com/").execute(new AsyncHandlerAdapter() { - - public STATE onStatusReceived(HttpResponseStatus status) throws Exception { - statusCode.set(status.getStatusCode()); - return STATE.CONTINUE; - } - - @Override - public STATE onHeadersReceived(HttpResponseHeaders content) throws Exception { - headers.set(content.getHeaders()); - return STATE.CONTINUE; - } - - @Override - public STATE onBodyPartReceived(HttpResponseBodyPart content) throws Exception { - return STATE.CONTINUE; - } - - @Override - public String onCompleted() throws Exception { - return null; - } - }); - - f.get(20, TimeUnit.SECONDS); - assertEquals(statusCode.get().intValue(), 302); - FluentCaseInsensitiveStringsMap h = headers.get(); - assertNotNull(h); - assertEquals(h.getJoinedValue("content-type", ", ").toLowerCase(Locale.ENGLISH), TEXT_HTML_CONTENT_TYPE_WITH_UTF_8_CHARSET.toLowerCase(Locale.ENGLISH)); - - } finally { - client.close(); - } - } - @Test(groups = { "online", "default_provider" }) public void asyncStream302RedirectWithBody() throws Exception { AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setFollowRedirect(true).build()); final AtomicReference statusCode = new AtomicReference(0); final AtomicReference responseHeaders = new AtomicReference(); try { - Future f = client.prepareGet("http://google.com/").execute(new AsyncHandlerAdapter() { + Future f = client.prepareGet("http://google.com").execute(new AsyncHandlerAdapter() { public STATE onStatusReceived(HttpResponseStatus status) throws Exception { statusCode.set(status.getStatusCode()); From e3a079ad073d0a8e2ae84e73b3015e876ce1c54b Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 24 Jul 2014 17:17:35 +0200 Subject: [PATCH 480/701] Fix RemoteSiteTest.testGoogleComWithTimeout, redirect depends on geoloc --- src/test/java/com/ning/http/client/async/RemoteSiteTest.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) 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 f5b2d043c4..4957db37cb 100644 --- a/src/test/java/com/ning/http/client/async/RemoteSiteTest.java +++ b/src/test/java/com/ning/http/client/async/RemoteSiteTest.java @@ -17,7 +17,7 @@ import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNotNull; -import static org.testng.AssertJUnit.assertTrue; +import static org.testng.Assert.assertTrue; import java.io.InputStream; import java.net.URLEncoder; @@ -116,7 +116,8 @@ public void testGoogleComWithTimeout() throws Throwable { try { Response response = client.prepareGet("http://google.com/").execute().get(10, TimeUnit.SECONDS); assertNotNull(response); - assertEquals(response.getStatusCode(), 302); + // depends on user IP/Locale + assertTrue(response.getStatusCode() == 301 || response.getStatusCode() == 302); } finally { client.close(); } From ff20dd97985740af1a0ff60300d64867710cafb6 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 25 Jul 2014 08:55:22 +0200 Subject: [PATCH 481/701] rename handshakeTimeoutInMillis into handshakeTimeout --- .../providers/netty/NettyAsyncHttpProviderConfig.java | 2 +- .../http/client/providers/netty/channel/ChannelManager.java | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) 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 4d03c31171..20d6497094 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 @@ -193,7 +193,7 @@ public void setNettyTimer(Timer nettyTimer) { this.nettyTimer = nettyTimer; } - public long getHandshakeTimeoutInMillis() { + public long getHandshakeTimeout() { return handshakeTimeoutInMillis; } diff --git a/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java b/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java index 9e9d1f02bf..030d95d630 100644 --- a/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java +++ b/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java @@ -86,7 +86,7 @@ public class ChannelManager { private final boolean maxConnectionsPerHostEnabled; private final ConcurrentHashMap freeChannelsPerHost; private final ConcurrentHashMap channelId2KeyPool; - private final long handshakeTimeoutInMillis; + private final long handshakeTimeout; private final Timer nettyTimer; private final ClientSocketChannelFactory socketChannelFactory; @@ -148,7 +148,7 @@ public boolean remove(Object o) { channelId2KeyPool = null; } - handshakeTimeoutInMillis = nettyConfig.getHandshakeTimeoutInMillis(); + handshakeTimeout = nettyConfig.getHandshakeTimeout(); if (nettyConfig.getSocketChannelFactory() != null) { socketChannelFactory = nettyConfig.getSocketChannelFactory(); @@ -360,7 +360,7 @@ public SslHandler createSslHandler(String peerHost, int peerPort) throws General sslEngine.setUseClientMode(true); } - return handshakeTimeoutInMillis > 0 ? new SslHandler(sslEngine, getDefaultBufferPool(), false, nettyTimer, handshakeTimeoutInMillis) + return handshakeTimeout > 0 ? new SslHandler(sslEngine, getDefaultBufferPool(), false, nettyTimer, handshakeTimeout) : new SslHandler(sslEngine); } From 4f182825ec8c2f9d54e52628068c29100de8880d Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 25 Jul 2014 08:55:28 +0200 Subject: [PATCH 482/701] minor clean up --- .../com/ning/http/client/providers/netty/handler/Processor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/handler/Processor.java b/src/main/java/com/ning/http/client/providers/netty/handler/Processor.java index 42200cf50c..03f19d4a4d 100644 --- a/src/main/java/com/ning/http/client/providers/netty/handler/Processor.java +++ b/src/main/java/com/ning/http/client/providers/netty/handler/Processor.java @@ -149,7 +149,7 @@ public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Throwable cause = e.getCause(); NettyResponseFuture future = null; - if (e.getCause() instanceof PrematureChannelClosureException || cause instanceof ClosedChannelException) + if (cause instanceof PrematureChannelClosureException || cause instanceof ClosedChannelException) return; LOGGER.debug("Unexpected I/O exception on channel {}", channel, cause); From 639660e2b7d36cf1298e8c11309711b5faff363c Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 25 Jul 2014 09:47:07 +0200 Subject: [PATCH 483/701] Rename Netty response elements --- .../providers/netty/handler/HttpProtocol.java | 22 +++++++++---------- .../netty/handler/WebSocketProtocol.java | 14 ++++++------ .../netty/response/NettyResponse.java | 4 ++-- ...dyPart.java => NettyResponseBodyPart.java} | 13 +++-------- ...Headers.java => NettyResponseHeaders.java} | 6 ++--- ...seStatus.java => NettyResponseStatus.java} | 4 ++-- .../netty/NettyAsyncResponseTest.java | 8 +++---- 7 files changed, 32 insertions(+), 39 deletions(-) rename src/main/java/com/ning/http/client/providers/netty/response/{ResponseBodyPart.java => NettyResponseBodyPart.java} (85%) rename src/main/java/com/ning/http/client/providers/netty/response/{ResponseHeaders.java => NettyResponseHeaders.java} (90%) rename src/main/java/com/ning/http/client/providers/netty/response/{ResponseStatus.java => NettyResponseStatus.java} (93%) diff --git a/src/main/java/com/ning/http/client/providers/netty/handler/HttpProtocol.java b/src/main/java/com/ning/http/client/providers/netty/handler/HttpProtocol.java index d3ea33fb52..706b4a1b98 100644 --- a/src/main/java/com/ning/http/client/providers/netty/handler/HttpProtocol.java +++ b/src/main/java/com/ning/http/client/providers/netty/handler/HttpProtocol.java @@ -45,9 +45,9 @@ import com.ning.http.client.providers.netty.channel.Channels; import com.ning.http.client.providers.netty.future.NettyResponseFuture; import com.ning.http.client.providers.netty.request.NettyRequestSender; -import com.ning.http.client.providers.netty.response.ResponseBodyPart; -import com.ning.http.client.providers.netty.response.ResponseHeaders; -import com.ning.http.client.providers.netty.response.ResponseStatus; +import com.ning.http.client.providers.netty.response.NettyResponseBodyPart; +import com.ning.http.client.providers.netty.response.NettyResponseHeaders; +import com.ning.http.client.providers.netty.response.NettyResponseStatus; import com.ning.http.client.providers.netty.spnego.SpnegoEngine; import com.ning.http.client.uri.UriComponents; @@ -170,7 +170,7 @@ private void finishUpdate(final NettyResponseFuture future, Channel channel, markAsDone(future, channel); } - private boolean updateBodyAndInterrupt(NettyResponseFuture future, AsyncHandler handler, ResponseBodyPart bodyPart) + private boolean updateBodyAndInterrupt(NettyResponseFuture future, AsyncHandler handler, NettyResponseBodyPart bodyPart) throws Exception { boolean interrupt = handler.onBodyPartReceived(bodyPart) != STATE.CONTINUE; if (bodyPart.isUnderlyingConnectionToBeClosed()) @@ -353,7 +353,7 @@ private boolean exitAfterHandlingConnect(// } private boolean exitAfterHandlingStatus(Channel channel, NettyResponseFuture future, HttpResponse response, - AsyncHandler handler, ResponseStatus status) throws IOException, Exception { + AsyncHandler handler, NettyResponseStatus status) throws IOException, Exception { if (!future.getAndSetStatusReceived(true) && handler.onStatusReceived(status) != STATE.CONTINUE) { finishUpdate(future, channel, HttpHeaders.isTransferEncodingChunked(response)); return true; @@ -362,7 +362,7 @@ private boolean exitAfterHandlingStatus(Channel channel, NettyResponseFuture } private boolean exitAfterHandlingHeaders(Channel channel, NettyResponseFuture future, HttpResponse response, - AsyncHandler handler, ResponseHeaders responseHeaders) throws IOException, Exception { + AsyncHandler handler, NettyResponseHeaders responseHeaders) throws IOException, Exception { if (!response.headers().isEmpty() && handler.onHeadersReceived(responseHeaders) != STATE.CONTINUE) { finishUpdate(future, channel, HttpHeaders.isTransferEncodingChunked(response)); return true; @@ -377,7 +377,7 @@ private boolean exitAfterHandlingBody(Channel channel, NettyResponseFuture fu // no chunks expected, exiting if (response.getContent().readableBytes() > 0) // FIXME no need to notify an empty bodypart? - updateBodyAndInterrupt(future, handler, new ResponseBodyPart(response, null, true)); + updateBodyAndInterrupt(future, handler, new NettyResponseBodyPart(response, null, true)); finishUpdate(future, channel, false); return true; } @@ -399,11 +399,11 @@ private boolean handleHttpResponse(final HttpResponse response,// future.setKeepAlive(!HttpHeaders.Values.CLOSE.equalsIgnoreCase(response.headers().get(HttpHeaders.Names.CONNECTION))); - ResponseStatus status = new ResponseStatus(future.getURI(), config, response); + NettyResponseStatus status = new NettyResponseStatus(future.getURI(), config, response); int statusCode = response.getStatus().getCode(); Request request = future.getRequest(); Realm realm = request.getRealm() != null ? request.getRealm() : config.getRealm(); - ResponseHeaders responseHeaders = new ResponseHeaders(response.headers()); + NettyResponseHeaders responseHeaders = new NettyResponseHeaders(response.headers()); return exitAfterProcessingFilters(channel, future, handler, status, responseHeaders) || exitAfterHandling401(channel, future, response, request, statusCode, realm, proxyServer) || // @@ -423,13 +423,13 @@ private void handleChunk(HttpChunk chunk,// boolean last = chunk.isLast(); // we don't notify updateBodyAndInterrupt with the last chunk as it's empty - if (last || updateBodyAndInterrupt(future, handler, new ResponseBodyPart(null, chunk, last))) { + if (last || updateBodyAndInterrupt(future, handler, new NettyResponseBodyPart(null, chunk, last))) { // only possible if last is true if (chunk instanceof HttpChunkTrailer) { HttpChunkTrailer chunkTrailer = (HttpChunkTrailer) chunk; if (!chunkTrailer.trailingHeaders().isEmpty()) { - ResponseHeaders responseHeaders = new ResponseHeaders(future.getHttpHeaders(), chunkTrailer.trailingHeaders()); + NettyResponseHeaders responseHeaders = new NettyResponseHeaders(future.getHttpHeaders(), chunkTrailer.trailingHeaders()); handler.onHeadersReceived(responseHeaders); } } diff --git a/src/main/java/com/ning/http/client/providers/netty/handler/WebSocketProtocol.java b/src/main/java/com/ning/http/client/providers/netty/handler/WebSocketProtocol.java index 1382ac37fe..3e341373a7 100644 --- a/src/main/java/com/ning/http/client/providers/netty/handler/WebSocketProtocol.java +++ b/src/main/java/com/ning/http/client/providers/netty/handler/WebSocketProtocol.java @@ -36,9 +36,9 @@ import com.ning.http.client.providers.netty.channel.Channels; import com.ning.http.client.providers.netty.future.NettyResponseFuture; import com.ning.http.client.providers.netty.request.NettyRequestSender; -import com.ning.http.client.providers.netty.response.ResponseBodyPart; -import com.ning.http.client.providers.netty.response.ResponseHeaders; -import com.ning.http.client.providers.netty.response.ResponseStatus; +import com.ning.http.client.providers.netty.response.NettyResponseBodyPart; +import com.ning.http.client.providers.netty.response.NettyResponseHeaders; +import com.ning.http.client.providers.netty.response.NettyResponseStatus; import com.ning.http.client.providers.netty.ws.NettyWebSocket; import com.ning.http.client.websocket.WebSocketUpgradeHandler; import com.ning.http.util.StandardCharsets; @@ -74,8 +74,8 @@ public void handle(Channel channel, NettyResponseFuture future, Object e) thr if (e instanceof HttpResponse) { HttpResponse response = (HttpResponse) e; - HttpResponseStatus status = new ResponseStatus(future.getURI(), config, response); - HttpResponseHeaders responseHeaders = new ResponseHeaders(response.headers()); + HttpResponseStatus status = new NettyResponseStatus(future.getURI(), config, response); + HttpResponseHeaders responseHeaders = new NettyResponseHeaders(response.headers()); if (exitAfterProcessingFilters(channel, future, handler, status, responseHeaders)) { return; @@ -94,7 +94,7 @@ public void handle(Channel channel, NettyResponseFuture future, Object e) thr boolean validConnection = c != null && c.equalsIgnoreCase(HttpHeaders.Values.UPGRADE); - status = new ResponseStatus(future.getURI(), config, response); + status = new NettyResponseStatus(future.getURI(), config, response); final boolean statusReceived = handler.onStatusReceived(status) == STATE.UPGRADE; if (!statusReceived) { @@ -156,7 +156,7 @@ public void setContent(ChannelBuffer content) { } }; - ResponseBodyPart rp = new ResponseBodyPart(null, webSocketChunk, true); + NettyResponseBodyPart rp = new NettyResponseBodyPart(null, webSocketChunk, true); handler.onBodyPartReceived(rp); if (frame instanceof BinaryWebSocketFrame) { diff --git a/src/main/java/com/ning/http/client/providers/netty/response/NettyResponse.java b/src/main/java/com/ning/http/client/providers/netty/response/NettyResponse.java index 70d813b677..edf578b7a7 100644 --- a/src/main/java/com/ning/http/client/providers/netty/response/NettyResponse.java +++ b/src/main/java/com/ning/http/client/providers/netty/response/NettyResponse.java @@ -74,12 +74,12 @@ public ChannelBuffer getResponseBodyAsChannelBuffer() throws IOException { b = ChannelBuffers.EMPTY_BUFFER; break; case 1: - b = ResponseBodyPart.class.cast(bodyParts.get(0)).getChannelBuffer(); + b = NettyResponseBodyPart.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(); + channelBuffers[i] = NettyResponseBodyPart.class.cast(bodyParts.get(i)).getChannelBuffer(); } b = ChannelBuffers.wrappedBuffer(channelBuffers); } diff --git a/src/main/java/com/ning/http/client/providers/netty/response/ResponseBodyPart.java b/src/main/java/com/ning/http/client/providers/netty/response/NettyResponseBodyPart.java similarity index 85% rename from src/main/java/com/ning/http/client/providers/netty/response/ResponseBodyPart.java rename to src/main/java/com/ning/http/client/providers/netty/response/NettyResponseBodyPart.java index f2566d4673..e367e0190f 100644 --- a/src/main/java/com/ning/http/client/providers/netty/response/ResponseBodyPart.java +++ b/src/main/java/com/ning/http/client/providers/netty/response/NettyResponseBodyPart.java @@ -21,26 +21,24 @@ import com.ning.http.client.HttpResponseBodyPart; -import java.io.ByteArrayInputStream; import java.io.IOException; -import java.io.InputStream; import java.io.OutputStream; import java.nio.ByteBuffer; /** * A callback class used when an HTTP response body is received. */ -public class ResponseBodyPart extends HttpResponseBodyPart { +public class NettyResponseBodyPart extends HttpResponseBodyPart { private final ChannelBuffer content; private volatile byte[] bytes; private final int length; - public ResponseBodyPart(HttpResponse response, boolean last) { + public NettyResponseBodyPart(HttpResponse response, boolean last) { this(response, null, last); } - public ResponseBodyPart(HttpResponse response, HttpChunk chunk, boolean last) { + public NettyResponseBodyPart(HttpResponse response, HttpChunk chunk, boolean last) { super(last); content = chunk != null ? chunk.getContent() : response.getContent(); length = content.readableBytes(); @@ -81,9 +79,4 @@ public ByteBuffer getBodyByteBuffer() { public int length() { return length; } - - @Override - public InputStream readBodyPartBytes() { - return new ByteArrayInputStream(getBodyPartBytes()); - } } diff --git a/src/main/java/com/ning/http/client/providers/netty/response/ResponseHeaders.java b/src/main/java/com/ning/http/client/providers/netty/response/NettyResponseHeaders.java similarity index 90% rename from src/main/java/com/ning/http/client/providers/netty/response/ResponseHeaders.java rename to src/main/java/com/ning/http/client/providers/netty/response/NettyResponseHeaders.java index 8f8cfea1bf..dec0e10920 100644 --- a/src/main/java/com/ning/http/client/providers/netty/response/ResponseHeaders.java +++ b/src/main/java/com/ning/http/client/providers/netty/response/NettyResponseHeaders.java @@ -23,18 +23,18 @@ /** * A class that represent the HTTP headers. */ -public class ResponseHeaders extends HttpResponseHeaders { +public class NettyResponseHeaders extends HttpResponseHeaders { private final HttpHeaders responseHeaders; private final HttpHeaders trailingHeaders; private final FluentCaseInsensitiveStringsMap headers; // FIXME unused AsyncHttpProvider provider - public ResponseHeaders(HttpHeaders responseHeaders) { + public NettyResponseHeaders(HttpHeaders responseHeaders) { this(responseHeaders, null); } - public ResponseHeaders(HttpHeaders responseHeaders, HttpHeaders traillingHeaders) { + public NettyResponseHeaders(HttpHeaders responseHeaders, HttpHeaders traillingHeaders) { super(traillingHeaders != null); this.responseHeaders = responseHeaders; this.trailingHeaders = traillingHeaders; diff --git a/src/main/java/com/ning/http/client/providers/netty/response/ResponseStatus.java b/src/main/java/com/ning/http/client/providers/netty/response/NettyResponseStatus.java similarity index 93% rename from src/main/java/com/ning/http/client/providers/netty/response/ResponseStatus.java rename to src/main/java/com/ning/http/client/providers/netty/response/NettyResponseStatus.java index a0c742ad4c..f2640b93d0 100644 --- a/src/main/java/com/ning/http/client/providers/netty/response/ResponseStatus.java +++ b/src/main/java/com/ning/http/client/providers/netty/response/NettyResponseStatus.java @@ -27,11 +27,11 @@ /** * A class that represent the HTTP response' status line (code + text) */ -public class ResponseStatus extends HttpResponseStatus { +public class NettyResponseStatus extends HttpResponseStatus { private final HttpResponse response; - public ResponseStatus(UriComponents uri, AsyncHttpClientConfig config, HttpResponse response) { + public NettyResponseStatus(UriComponents uri, AsyncHttpClientConfig config, HttpResponse response) { super(uri, config); this.response = response; } 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 037ce12076..92752758b0 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 @@ -27,7 +27,7 @@ import com.ning.http.client.HttpResponseHeaders; import com.ning.http.client.cookie.Cookie; import com.ning.http.client.providers.netty.response.NettyResponse; -import com.ning.http.client.providers.netty.response.ResponseStatus; +import com.ning.http.client.providers.netty.response.NettyResponseStatus; /** * @author Benjamin Hanzelmann @@ -43,7 +43,7 @@ public void testCookieParseExpires() { 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(false) { + NettyResponse response = new NettyResponse(new NettyResponseStatus(null, null, null), new HttpResponseHeaders(false) { @Override public FluentCaseInsensitiveStringsMap getHeaders() { return new FluentCaseInsensitiveStringsMap().add("Set-Cookie", cookieDef); @@ -61,7 +61,7 @@ public FluentCaseInsensitiveStringsMap getHeaders() { @Test(groups = "standalone") public void testCookieParseMaxAge() { final String cookieDef = "efmembercheck=true; max-age=60; path=/; domain=.eclipse.org"; - NettyResponse response = new NettyResponse(new ResponseStatus(null, null, null), new HttpResponseHeaders(false) { + NettyResponse response = new NettyResponse(new NettyResponseStatus(null, null, null), new HttpResponseHeaders(false) { @Override public FluentCaseInsensitiveStringsMap getHeaders() { return new FluentCaseInsensitiveStringsMap().add("Set-Cookie", cookieDef); @@ -77,7 +77,7 @@ public FluentCaseInsensitiveStringsMap getHeaders() { @Test(groups = "standalone") public void testCookieParseWeirdExpiresValue() { final String cookieDef = "efmembercheck=true; expires=60; path=/; domain=.eclipse.org"; - NettyResponse response = new NettyResponse(new ResponseStatus(null, null, null), new HttpResponseHeaders(false) { + NettyResponse response = new NettyResponse(new NettyResponseStatus(null, null, null), new HttpResponseHeaders(false) { @Override public FluentCaseInsensitiveStringsMap getHeaders() { return new FluentCaseInsensitiveStringsMap().add("Set-Cookie", cookieDef); From d4b9a4ff650e528fa6f62ad1c7a883e4e9c2544e Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 25 Jul 2014 09:47:29 +0200 Subject: [PATCH 484/701] Drop readBodyPartBytes that's just a ByteArrayInputStream on top of getBytes --- .../com/ning/http/client/HttpResponseBodyPart.java | 6 ------ .../providers/apache/ApacheResponseBodyPart.java | 7 ------- .../providers/grizzly/GrizzlyResponseBodyPart.java | 14 ++++---------- .../client/providers/jdk/ResponseBodyPart.java | 7 ------- 4 files changed, 4 insertions(+), 30 deletions(-) diff --git a/src/main/java/com/ning/http/client/HttpResponseBodyPart.java b/src/main/java/com/ning/http/client/HttpResponseBodyPart.java index d0fc141be4..d8711ec59b 100644 --- a/src/main/java/com/ning/http/client/HttpResponseBodyPart.java +++ b/src/main/java/com/ning/http/client/HttpResponseBodyPart.java @@ -16,7 +16,6 @@ package com.ning.http.client; import java.io.IOException; -import java.io.InputStream; import java.io.OutputStream; import java.nio.ByteBuffer; @@ -71,11 +70,6 @@ public boolean isLast() { */ public abstract byte[] getBodyPartBytes(); - /** - * Method for accessing contents of this part via stream. - */ - public abstract InputStream readBodyPartBytes(); - /** * Write the available bytes to the {@link java.io.OutputStream} * diff --git a/src/main/java/com/ning/http/client/providers/apache/ApacheResponseBodyPart.java b/src/main/java/com/ning/http/client/providers/apache/ApacheResponseBodyPart.java index d89e4f874a..87633f8c34 100644 --- a/src/main/java/com/ning/http/client/providers/apache/ApacheResponseBodyPart.java +++ b/src/main/java/com/ning/http/client/providers/apache/ApacheResponseBodyPart.java @@ -14,9 +14,7 @@ import com.ning.http.client.HttpResponseBodyPart; -import java.io.ByteArrayInputStream; import java.io.IOException; -import java.io.InputStream; import java.io.OutputStream; import java.nio.ByteBuffer; @@ -56,9 +54,4 @@ public ByteBuffer getBodyByteBuffer() { public int length() { return chunk != null ? chunk.length : 0; } - - @Override - public InputStream readBodyPartBytes() { - return chunk != null ? new ByteArrayInputStream(chunk) : null; - } } diff --git a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponseBodyPart.java b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponseBodyPart.java index 6e2548afca..7d536977be 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponseBodyPart.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponseBodyPart.java @@ -13,21 +13,20 @@ package com.ning.http.client.providers.grizzly; -import com.ning.http.client.HttpResponseBodyPart; +import static com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProvider.ConnectionManager.isConnectionCacheable; +import static com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProvider.ConnectionManager.markConnectionAsDoNotCache; import org.glassfish.grizzly.Buffer; import org.glassfish.grizzly.Connection; import org.glassfish.grizzly.http.HttpContent; -import java.io.ByteArrayInputStream; +import com.ning.http.client.HttpResponseBodyPart; + import java.io.IOException; -import java.io.InputStream; import java.io.OutputStream; import java.nio.ByteBuffer; import java.util.concurrent.atomic.AtomicReference; -import static com.ning.http.client.providers.grizzly.GrizzlyAsyncHttpProvider.ConnectionManager.*; - /** * {@link HttpResponseBodyPart} implementation using the Grizzly 2.0 HTTP client * codec. @@ -109,11 +108,6 @@ public boolean isUnderlyingConnectionToBeClosed() { return !isConnectionCacheable(connection); } - @Override - public InputStream readBodyPartBytes() { - return new ByteArrayInputStream(getBodyPartBytes()); - } - // ----------------------------------------------- Package Protected Methods diff --git a/src/main/java/com/ning/http/client/providers/jdk/ResponseBodyPart.java b/src/main/java/com/ning/http/client/providers/jdk/ResponseBodyPart.java index 8184d05401..c0202c3240 100644 --- a/src/main/java/com/ning/http/client/providers/jdk/ResponseBodyPart.java +++ b/src/main/java/com/ning/http/client/providers/jdk/ResponseBodyPart.java @@ -14,9 +14,7 @@ import com.ning.http.client.HttpResponseBodyPart; -import java.io.ByteArrayInputStream; import java.io.IOException; -import java.io.InputStream; import java.io.OutputStream; import java.nio.ByteBuffer; @@ -56,9 +54,4 @@ public ByteBuffer getBodyByteBuffer() { public int length() { return chunk != null? chunk.length: 0; } - - @Override - public InputStream readBodyPartBytes() { - return chunk != null ? new ByteArrayInputStream(chunk) : null; - } } From 884744175d50ced5ccfe4babc728b00d6d0275df Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 25 Jul 2014 10:01:48 +0200 Subject: [PATCH 485/701] Fix log + NettyConnectListener doesn't need a ref to the NettyRequest --- .../client/providers/netty/request/NettyRequestSender.java | 4 ++-- .../providers/netty/request/body/NettyConnectListener.java | 4 ---- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java index 51756b4b8a..48b104c94b 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java @@ -414,7 +414,7 @@ public boolean retry(NettyResponseFuture future, Channel channel) { // FIXME this was done in AHC2, is this a bug? // channelManager.removeAll(channel); - + if (future == null) { Object attribute = Channels.getAttribute(channel); if (attribute instanceof NettyResponseFuture) @@ -424,7 +424,7 @@ public boolean retry(NettyResponseFuture future, Channel channel) { if (future != null && future.canBeReplayed()) { future.setState(NettyResponseFuture.STATE.RECONNECTED); - LOGGER.debug("Trying to recover request {}\n", future.getNettyRequest()); + LOGGER.debug("Trying to recover request {}\n", future.getNettyRequest().getHttpRequest()); if (future.getAsyncHandler() instanceof AsyncHandlerExtensions) AsyncHandlerExtensions.class.cast(future.getAsyncHandler()).onRetry(); diff --git a/src/main/java/com/ning/http/client/providers/netty/request/body/NettyConnectListener.java b/src/main/java/com/ning/http/client/providers/netty/request/body/NettyConnectListener.java index e7e028c7d7..098da30c50 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/body/NettyConnectListener.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/body/NettyConnectListener.java @@ -25,7 +25,6 @@ import com.ning.http.client.providers.netty.channel.Channels; import com.ning.http.client.providers.netty.future.NettyResponseFuture; import com.ning.http.client.providers.netty.future.StackTraceInspector; -import com.ning.http.client.providers.netty.request.NettyRequest; import com.ning.http.client.providers.netty.request.NettyRequestSender; import com.ning.http.util.Base64; @@ -43,7 +42,6 @@ public final class NettyConnectListener implements ChannelFutureListener { private static final Logger LOGGER = LoggerFactory.getLogger(NettyConnectListener.class); private final AsyncHttpClientConfig config; private final NettyResponseFuture future; - private final NettyRequest nettyRequest; private final NettyRequestSender requestSender; private final ChannelManager channelManager; private final boolean channelPreempted; @@ -57,7 +55,6 @@ public NettyConnectListener(AsyncHttpClientConfig config,// String poolKey) { this.config = config; this.future = future; - this.nettyRequest = future.getNettyRequest(); this.requestSender = requestSender; this.channelManager = channelManager; this.channelPreempted = channelPreempted; @@ -132,7 +129,6 @@ public void operationComplete(ChannelFuture handshakeFuture) throws Exception { && cause != null && (cause instanceof ClosedChannelException || future.getState() != NettyResponseFuture.STATE.NEW || StackTraceInspector.abortOnDisconnectException(cause))) { - LOGGER.debug("Retrying {} ", nettyRequest.getHttpRequest()); if (!requestSender.retry(future, channel)) return; } From 5ec89ae2912ecf9038f2d3939dff18af9774b581 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 25 Jul 2014 13:29:06 +0200 Subject: [PATCH 486/701] Make acceptAnyCertificate doesn't disable HostnameVerifier, close #649 --- .../http/client/AsyncHttpClientConfig.java | 19 +++++++++------- .../client/AsyncHttpClientConfigBean.java | 1 - .../client/AsyncHttpClientConfigDefaults.java | 8 ------- .../http/util/AllowAllHostnameVerifier.java | 22 ------------------- 4 files changed, 11 insertions(+), 39 deletions(-) delete mode 100644 src/main/java/com/ning/http/util/AllowAllHostnameVerifier.java diff --git a/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java b/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java index 07f9466cf6..76c1c82643 100644 --- a/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java @@ -21,6 +21,7 @@ import com.ning.http.client.filter.IOExceptionFilter; import com.ning.http.client.filter.RequestFilter; import com.ning.http.client.filter.ResponseFilter; +import com.ning.http.util.DefaultHostnameVerifier; import com.ning.http.util.ProxyUtils; import javax.net.ssl.HostnameVerifier; @@ -231,7 +232,7 @@ public int getMaxRedirects() { } /** - * Is the {@link ChannelPool} support enabled. + * Is pooling connections enabled. * * @return if polling connections is enabled */ @@ -463,7 +464,7 @@ public static class Builder { private int pooledConnectionIdleTimeout = defaultPooledConnectionIdleTimeout(); private int connectionTTL = defaultConnectionTTL(); private SSLContext sslContext; - private HostnameVerifier hostnameVerifier = defaultHostnameVerifier(); + private HostnameVerifier hostnameVerifier; private boolean acceptAnyCertificate = defaultAcceptAnyCertificate(); private boolean followRedirect = defaultFollowRedirect(); private int maxRedirects = defaultMaxRedirects(); @@ -961,17 +962,19 @@ public Thread newThread(Runnable r) { }); } - if (proxyServerSelector == null && useProxySelector) { + if (proxyServerSelector == null && useProxySelector) proxyServerSelector = ProxyUtils.getJdkDefaultProxyServerSelector(); - } - if (proxyServerSelector == null && useProxyProperties) { + if (proxyServerSelector == null && useProxyProperties) proxyServerSelector = ProxyUtils.createProxyServerSelector(System.getProperties()); - } - if (proxyServerSelector == null) { + if (proxyServerSelector == null) proxyServerSelector = ProxyServerSelector.NO_PROXY_SELECTOR; - } + + if (acceptAnyCertificate) + hostnameVerifier = null; + else if (hostnameVerifier == null) + hostnameVerifier = new DefaultHostnameVerifier(); return new AsyncHttpClientConfig(connectionTimeout,// maxConnections,// diff --git a/src/main/java/com/ning/http/client/AsyncHttpClientConfigBean.java b/src/main/java/com/ning/http/client/AsyncHttpClientConfigBean.java index 397748b19c..7d43520df5 100644 --- a/src/main/java/com/ning/http/client/AsyncHttpClientConfigBean.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClientConfigBean.java @@ -65,7 +65,6 @@ void configureDefaults() { disableUrlEncodingForBoundRequests = defaultDisableUrlEncodingForBoundRequests(); removeQueryParamOnRedirect = defaultRemoveQueryParamOnRedirect(); strict302Handling = defaultStrict302Handling(); - hostnameVerifier = defaultHostnameVerifier(); acceptAnyCertificate = defaultAcceptAnyCertificate(); if (defaultUseProxySelector()) { diff --git a/src/main/java/com/ning/http/client/AsyncHttpClientConfigDefaults.java b/src/main/java/com/ning/http/client/AsyncHttpClientConfigDefaults.java index 4e2f5f74b1..121792490e 100644 --- a/src/main/java/com/ning/http/client/AsyncHttpClientConfigDefaults.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClientConfigDefaults.java @@ -14,10 +14,6 @@ import static com.ning.http.util.MiscUtils.getBoolean; -import com.ning.http.util.DefaultHostnameVerifier; - -import javax.net.ssl.HostnameVerifier; - public final class AsyncHttpClientConfigDefaults { private AsyncHttpClientConfigDefaults() { @@ -112,10 +108,6 @@ public static boolean defaultDisableUrlEncodingForBoundRequests() { public static boolean defaultRemoveQueryParamOnRedirect() { return getBoolean(ASYNC_CLIENT + "removeQueryParamOnRedirect", true); } - - public static HostnameVerifier defaultHostnameVerifier() { - return new DefaultHostnameVerifier(); - } public static boolean defaultAcceptAnyCertificate() { return getBoolean(ASYNC_CLIENT + "acceptAnyCertificate", false); diff --git a/src/main/java/com/ning/http/util/AllowAllHostnameVerifier.java b/src/main/java/com/ning/http/util/AllowAllHostnameVerifier.java deleted file mode 100644 index 0223cc1ee6..0000000000 --- a/src/main/java/com/ning/http/util/AllowAllHostnameVerifier.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * 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 javax.net.ssl.HostnameVerifier; -import javax.net.ssl.SSLSession; - -public class AllowAllHostnameVerifier implements HostnameVerifier { - public boolean verify(String s, SSLSession sslSession) { - return true; - } -} From fba819263627c1d6cfeff226e04557aa812374e7 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 25 Jul 2014 13:29:10 +0200 Subject: [PATCH 487/701] format --- src/main/java/com/ning/http/util/SslUtils.java | 10 +++++----- 1 file changed, 5 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 5d09e407b9..f298f9dbcd 100644 --- a/src/main/java/com/ning/http/util/SslUtils.java +++ b/src/main/java/com/ning/http/util/SslUtils.java @@ -40,20 +40,20 @@ public void checkServerTrusted(java.security.cert.X509Certificate[] certs, Strin } } - private SSLContext looseTrustManagerSSLContext = looseTrustManagerSSLContext(); - + private SSLContext looseTrustManagerSSLContext = looseTrustManagerSSLContext(); + private SSLContext looseTrustManagerSSLContext() { try { SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(null, new TrustManager[] { new LooseTrustManager() }, new SecureRandom()); return sslContext; } catch (NoSuchAlgorithmException e) { - throw new ExceptionInInitializerError(e); + throw new ExceptionInInitializerError(e); } catch (KeyManagementException e) { throw new ExceptionInInitializerError(e); } } - + private static class SingletonHolder { public static final SslUtils instance = new SslUtils(); } @@ -63,6 +63,6 @@ public static SslUtils getInstance() { } public SSLContext getSSLContext(boolean acceptAnyCertificate) throws GeneralSecurityException, IOException { - return acceptAnyCertificate? looseTrustManagerSSLContext: SSLContext.getDefault(); + return acceptAnyCertificate ? looseTrustManagerSSLContext : SSLContext.getDefault(); } } From b35a10d0c66278d98da77e2aac6d36677ddcbc49 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 25 Jul 2014 13:30:47 +0200 Subject: [PATCH 488/701] [maven-release-plugin] prepare release async-http-client-1.9.0-BETA5 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 824c0acaff..d803ec2dc6 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.9.0-SNAPSHOT + 1.9.0-BETA5 jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From 9a83707f78790c3398d950e7e767be4896528951 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 25 Jul 2014 13:30:51 +0200 Subject: [PATCH 489/701] [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 d803ec2dc6..824c0acaff 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.9.0-BETA5 + 1.9.0-SNAPSHOT jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From d536b47a031c69b3ef995aea62980fe9d17376e7 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 25 Jul 2014 14:10:18 +0200 Subject: [PATCH 490/701] No need to get the bytes to get a ByteBuffer --- .../client/providers/netty/response/NettyResponseBodyPart.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/response/NettyResponseBodyPart.java b/src/main/java/com/ning/http/client/providers/netty/response/NettyResponseBodyPart.java index e367e0190f..6883f94104 100644 --- a/src/main/java/com/ning/http/client/providers/netty/response/NettyResponseBodyPart.java +++ b/src/main/java/com/ning/http/client/providers/netty/response/NettyResponseBodyPart.java @@ -72,7 +72,7 @@ public ChannelBuffer getChannelBuffer() { @Override public ByteBuffer getBodyByteBuffer() { - return ByteBuffer.wrap(getBodyPartBytes()); + return content.toByteBuffer(); } @Override From d1a4182b91d1f73e44616aaca946fa00318c97d9 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 28 Jul 2014 11:14:12 +0200 Subject: [PATCH 491/701] Fix NPE when passing a null charset, close #651 --- .../http/client/multipart/StringPart.java | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/ning/http/client/multipart/StringPart.java b/src/main/java/com/ning/http/client/multipart/StringPart.java index 8a87a89a5c..f3dfd9a4b3 100644 --- a/src/main/java/com/ning/http/client/multipart/StringPart.java +++ b/src/main/java/com/ning/http/client/multipart/StringPart.java @@ -12,6 +12,8 @@ */ package com.ning.http.client.multipart; +import com.ning.http.util.StandardCharsets; + import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; @@ -28,7 +30,7 @@ public class StringPart extends PartBase { /** * Default charset of string parameters */ - public static final String DEFAULT_CHARSET = "US-ASCII"; + public static final Charset DEFAULT_CHARSET = StandardCharsets.US_ASCII; /** * Default transfer encoding of string parameters @@ -45,6 +47,10 @@ public StringPart(String name, String value, String charset) { this(name, value, charset, null); } + private static Charset charsetOrDefault(String charset) { + return charset == null ? DEFAULT_CHARSET : Charset.forName(charset); + } + /** * Constructor. * @@ -58,15 +64,15 @@ public StringPart(String name, String value, String charset) { * the content id */ public StringPart(String name, String value, String charset, String contentId) { - super(name, DEFAULT_CONTENT_TYPE, charset == null ? DEFAULT_CHARSET : charset, contentId, DEFAULT_TRANSFER_ENCODING); - if (value == null) { + super(name, DEFAULT_CONTENT_TYPE, charsetOrDefault(charset).name(), contentId, DEFAULT_TRANSFER_ENCODING); + if (value == null) throw new NullPointerException("value"); - } - if (value.indexOf(0) != -1) { + + if (value.indexOf(0) != -1) // See RFC 2048, 2.8. "8bit Data" throw new IllegalArgumentException("NULs may not be present in string parts"); - } - content = value.getBytes(Charset.forName(charset)); + + content = value.getBytes(charsetOrDefault(charset)); this.value = value; } From d1d744fe2128265dff3c72470b48e3c5db99d99f Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 28 Jul 2014 11:37:29 +0200 Subject: [PATCH 492/701] Clean up warnings --- .../java/com/ning/http/client/AsyncHttpClient.java | 3 +++ .../extra/ResumableRandomAccessFileListener.java | 4 ---- .../http/client/extra/ThrottleRequestFilter.java | 1 + .../com/ning/http/client/filter/FilterContext.java | 13 +++++++++++-- .../ning/http/client/filter/FilterException.java | 1 + .../ning/http/client/filter/IOExceptionFilter.java | 1 + .../com/ning/http/client/filter/RequestFilter.java | 1 + .../com/ning/http/client/filter/ResponseFilter.java | 1 + .../client/listener/TransferCompletionHandler.java | 1 - .../providers/netty/request/NettyRequestSender.java | 2 ++ .../client/resumable/ResumableAsyncHandler.java | 2 ++ .../resumable/ResumableIOExceptionFilter.java | 1 + .../client/websocket/WebSocketUpgradeHandler.java | 1 + .../com/ning/http/util/AsyncHttpProviderUtils.java | 1 + .../com/ning/http/util/ProxyHostnameChecker.java | 1 + 15 files changed, 27 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/ning/http/client/AsyncHttpClient.java b/src/main/java/com/ning/http/client/AsyncHttpClient.java index 693aaa94d3..f2d1f409bb 100755 --- a/src/main/java/com/ning/http/client/AsyncHttpClient.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClient.java @@ -482,6 +482,7 @@ public BoundRequestBuilder prepareRequest(Request request) { * @return a {@link Future} of type T * @throws IOException */ + @SuppressWarnings({ "rawtypes", "unchecked" }) public ListenableFuture executeRequest(Request request, AsyncHandler handler) throws IOException { FilterContext fc = new FilterContext.FilterContextBuilder().asyncHandler(handler).request(request).build(); @@ -497,6 +498,7 @@ public ListenableFuture executeRequest(Request request, AsyncHandler h * @return a {@link Future} of type Response * @throws IOException */ + @SuppressWarnings({ "rawtypes", "unchecked" }) public ListenableFuture executeRequest(Request request) throws IOException { FilterContext fc = new FilterContext.FilterContextBuilder().asyncHandler(new AsyncCompletionHandlerBase()).request(request).build(); fc = preProcessRequest(fc); @@ -509,6 +511,7 @@ public ListenableFuture executeRequest(Request request) throws IOExcep * @param fc {@link FilterContext} * @return {@link FilterContext} */ + @SuppressWarnings("rawtypes") private FilterContext preProcessRequest(FilterContext fc) throws IOException { for (RequestFilter asyncFilter : config.getRequestFilters()) { try { diff --git a/src/main/java/com/ning/http/client/extra/ResumableRandomAccessFileListener.java b/src/main/java/com/ning/http/client/extra/ResumableRandomAccessFileListener.java index ec68f7ea1b..aa7bdbd1ca 100644 --- a/src/main/java/com/ning/http/client/extra/ResumableRandomAccessFileListener.java +++ b/src/main/java/com/ning/http/client/extra/ResumableRandomAccessFileListener.java @@ -14,9 +14,6 @@ import com.ning.http.client.resumable.ResumableListener; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import java.io.IOException; import java.io.RandomAccessFile; import java.nio.ByteBuffer; @@ -26,7 +23,6 @@ */ public class ResumableRandomAccessFileListener implements ResumableListener { private final RandomAccessFile file; - private final static Logger logger = LoggerFactory.getLogger(ThrottleRequestFilter.class); public ResumableRandomAccessFileListener(RandomAccessFile file) { this.file = file; diff --git a/src/main/java/com/ning/http/client/extra/ThrottleRequestFilter.java b/src/main/java/com/ning/http/client/extra/ThrottleRequestFilter.java index 2bdb9b6eae..5862800acd 100644 --- a/src/main/java/com/ning/http/client/extra/ThrottleRequestFilter.java +++ b/src/main/java/com/ning/http/client/extra/ThrottleRequestFilter.java @@ -46,6 +46,7 @@ public ThrottleRequestFilter(int maxConnections, int maxWait) { } @Override + @SuppressWarnings({ "rawtypes", "unchecked" }) public FilterContext filter(FilterContext ctx) throws FilterException { try { diff --git a/src/main/java/com/ning/http/client/filter/FilterContext.java b/src/main/java/com/ning/http/client/filter/FilterContext.java index 544a461edb..1f564bc11d 100644 --- a/src/main/java/com/ning/http/client/filter/FilterContext.java +++ b/src/main/java/com/ning/http/client/filter/FilterContext.java @@ -33,6 +33,7 @@ */ public class FilterContext { + @SuppressWarnings("rawtypes") private final FilterContextBuilder b; /** @@ -40,7 +41,7 @@ public class FilterContext { * * @param b a {@link FilterContextBuilder} */ - private FilterContext(FilterContextBuilder b) { + private FilterContext(@SuppressWarnings("rawtypes") FilterContextBuilder b) { this.b = b; } @@ -49,6 +50,7 @@ private FilterContext(FilterContextBuilder b) { * * @return the original or decorated {@link AsyncHandler} */ + @SuppressWarnings("unchecked") public AsyncHandler getAsyncHandler() { return b.asyncHandler; } @@ -107,6 +109,7 @@ public static class FilterContextBuilder { public FilterContextBuilder() { } + @SuppressWarnings({ "rawtypes", "unchecked" }) public FilterContextBuilder(FilterContext clone) { asyncHandler = clone.getAsyncHandler(); request = clone.getRequest(); @@ -119,6 +122,7 @@ public AsyncHandler getAsyncHandler() { return asyncHandler; } + @SuppressWarnings("rawtypes") public FilterContextBuilder asyncHandler(AsyncHandler asyncHandler) { this.asyncHandler = asyncHandler; return this; @@ -128,34 +132,39 @@ public Request getRequest() { return request; } + @SuppressWarnings("rawtypes") public FilterContextBuilder request(Request request) { this.request = request; return this; } + @SuppressWarnings("rawtypes") public FilterContextBuilder responseStatus(HttpResponseStatus responseStatus) { this.responseStatus = responseStatus; return this; } + @SuppressWarnings("rawtypes") public FilterContextBuilder responseHeaders(HttpResponseHeaders headers) { this.headers = headers; return this; } + @SuppressWarnings("rawtypes") public FilterContextBuilder replayRequest(boolean replayRequest) { this.replayRequest = replayRequest; return this; } + @SuppressWarnings("rawtypes") public FilterContextBuilder ioException(IOException ioException) { this.ioException = ioException; return this; } + @SuppressWarnings("rawtypes") public FilterContext build() { return new FilterContext(this); } } - } diff --git a/src/main/java/com/ning/http/client/filter/FilterException.java b/src/main/java/com/ning/http/client/filter/FilterException.java index c8e68ee731..b467dd4c7e 100644 --- a/src/main/java/com/ning/http/client/filter/FilterException.java +++ b/src/main/java/com/ning/http/client/filter/FilterException.java @@ -16,6 +16,7 @@ * An exception that can be thrown by an {@link com.ning.http.client.AsyncHandler} to interrupt invocation of * the {@link RequestFilter} and {@link ResponseFilter}. It also interrupt the request and response processing. */ +@SuppressWarnings("serial") public class FilterException extends Exception { /** diff --git a/src/main/java/com/ning/http/client/filter/IOExceptionFilter.java b/src/main/java/com/ning/http/client/filter/IOExceptionFilter.java index 645587df47..81350968fb 100644 --- a/src/main/java/com/ning/http/client/filter/IOExceptionFilter.java +++ b/src/main/java/com/ning/http/client/filter/IOExceptionFilter.java @@ -25,5 +25,6 @@ public interface IOExceptionFilter { * @return {@link FilterContext}. The {@link FilterContext} instance may not the same as the original one. * @throws FilterException to interrupt the filter processing. */ + @SuppressWarnings("rawtypes") FilterContext filter(FilterContext ctx) throws FilterException; } diff --git a/src/main/java/com/ning/http/client/filter/RequestFilter.java b/src/main/java/com/ning/http/client/filter/RequestFilter.java index 9f405aaded..bd10e5b7f6 100644 --- a/src/main/java/com/ning/http/client/filter/RequestFilter.java +++ b/src/main/java/com/ning/http/client/filter/RequestFilter.java @@ -26,5 +26,6 @@ public interface RequestFilter { * @return {@link FilterContext}. The {@link FilterContext} instance may not the same as the original one. * @throws FilterException to interrupt the filter processing. */ + @SuppressWarnings("rawtypes") FilterContext filter(FilterContext ctx) throws FilterException; } diff --git a/src/main/java/com/ning/http/client/filter/ResponseFilter.java b/src/main/java/com/ning/http/client/filter/ResponseFilter.java index 3edf3d9126..4a955aa40f 100644 --- a/src/main/java/com/ning/http/client/filter/ResponseFilter.java +++ b/src/main/java/com/ning/http/client/filter/ResponseFilter.java @@ -29,5 +29,6 @@ public interface ResponseFilter { * @return {@link FilterContext}. The {@link FilterContext} instance may not the same as the original one. * @throws FilterException to interrupt the filter processing. */ + @SuppressWarnings("rawtypes") FilterContext filter(FilterContext ctx) throws FilterException; } 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 8d305bd528..df95eeb8a1 100644 --- a/src/main/java/com/ning/http/client/listener/TransferCompletionHandler.java +++ b/src/main/java/com/ning/http/client/listener/TransferCompletionHandler.java @@ -22,7 +22,6 @@ import com.ning.http.client.Response; import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.atomic.AtomicLong; /** * A {@link org.asynchttpclient.AsyncHandler} that can be used to notify a set of {@link TransferListener} diff --git a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java index 48b104c94b..6132217325 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java @@ -144,6 +144,7 @@ private ListenableFuture sendRequestWithCertainForceConnect(// * Loop until we get a valid channel from the pool and it's still valid * once the request is built */ + @SuppressWarnings("unused") private ListenableFuture sendRequestThroughSslProxy(// Request request,// AsyncHandler asyncHandler,// @@ -450,6 +451,7 @@ public boolean applyIoExceptionFiltersAndReplayRequest(NettyResponseFuture fu boolean replayed = false; + @SuppressWarnings({ "unchecked", "rawtypes" }) FilterContext fc = new FilterContext.FilterContextBuilder().asyncHandler(future.getAsyncHandler()).request(future.getRequest()) .ioException(e).build(); for (IOExceptionFilter asyncFilter : config.getIOExceptionFilters()) { 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 1f34c04e4e..5917da7b13 100644 --- a/src/main/java/com/ning/http/client/resumable/ResumableAsyncHandler.java +++ b/src/main/java/com/ning/http/client/resumable/ResumableAsyncHandler.java @@ -147,6 +147,7 @@ public AsyncHandler.STATE onBodyPartReceived(HttpResponseBodyPart bodyPart) thro return state; } + @SuppressWarnings("unchecked") @Override public T onCompleted() throws Exception { resumableProcessor.remove(url); @@ -207,6 +208,7 @@ public Request adjustRequestRange(Request request) { * @param resumableListener a {@link ResumableListener} * @return this */ + @SuppressWarnings("rawtypes") public ResumableAsyncHandler setResumableListener(ResumableListener resumableListener) { this.resumableListener = resumableListener; return 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 9422c0bd8d..6b985efb41 100644 --- a/src/main/java/com/ning/http/client/resumable/ResumableIOExceptionFilter.java +++ b/src/main/java/com/ning/http/client/resumable/ResumableIOExceptionFilter.java @@ -22,6 +22,7 @@ * a {@link ResumableAsyncHandler} */ public class ResumableIOExceptionFilter implements IOExceptionFilter { + @SuppressWarnings("rawtypes") public FilterContext filter(FilterContext ctx) throws FilterException { if (ctx.getIOException() != null && ctx.getAsyncHandler() instanceof ResumableAsyncHandler) { 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 e72ce81c46..25bb6c6b13 100644 --- a/src/main/java/com/ning/http/client/websocket/WebSocketUpgradeHandler.java +++ b/src/main/java/com/ning/http/client/websocket/WebSocketUpgradeHandler.java @@ -28,6 +28,7 @@ public class WebSocketUpgradeHandler implements UpgradeHandler, Async private WebSocket webSocket; private final ConcurrentLinkedQueue l; + // FIXME use? private final String protocol; private final long maxByteSize; private final long maxTextSize; diff --git a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java index cfe66f5e3a..128c99ed4e 100644 --- a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java +++ b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java @@ -83,6 +83,7 @@ public final static byte[] contentToByte(List bodyParts) t } } + @SuppressWarnings("resource") public final static InputStream contentToInputStream(List bodyParts) throws UnsupportedEncodingException { return bodyParts.isEmpty() ? new ByteArrayInputStream(EMPTY_BYTE_ARRAY) : new HttpResponseBodyPartsInputStream(bodyParts); } diff --git a/src/main/java/com/ning/http/util/ProxyHostnameChecker.java b/src/main/java/com/ning/http/util/ProxyHostnameChecker.java index a7d0914004..ea10fed195 100644 --- a/src/main/java/com/ning/http/util/ProxyHostnameChecker.java +++ b/src/main/java/com/ning/http/util/ProxyHostnameChecker.java @@ -33,6 +33,7 @@ public ProxyHostnameChecker() { private Object getHostnameChecker() { final ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); try { + @SuppressWarnings("unchecked") final Class hostnameCheckerClass = (Class) classLoader.loadClass("sun.security.util.HostnameChecker"); final Method instanceMethod = hostnameCheckerClass.getMethod("getInstance", Byte.TYPE); return instanceMethod.invoke(null, TYPE_TLS); From 014201425e2de2763ffb7d6e28c1bc31437c83c6 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 28 Jul 2014 11:51:41 +0200 Subject: [PATCH 493/701] Have Parts take a java.nio.Charset instead of a String, close #652 --- .../client/multipart/AbstractFilePart.java | 3 ++- .../http/client/multipart/ByteArrayPart.java | 9 ++++--- .../ning/http/client/multipart/FilePart.java | 9 ++++--- .../com/ning/http/client/multipart/Part.java | 3 ++- .../ning/http/client/multipart/PartBase.java | 25 ++++++++++--------- .../http/client/multipart/StringPart.java | 10 ++++---- .../apache/ApacheAsyncHttpProvider.java | 4 +-- .../client/async/AsyncProvidersBasicTest.java | 2 +- .../async/FastUnauthorizedUploadTest.java | 2 +- .../client/async/FilePartLargeFileTest.java | 7 +++--- .../client/async/MultipartUploadTest.java | 17 +++++++------ .../async/SimpleAsyncHttpClientTest.java | 7 +++--- .../client/multipart/MultipartBodyTest.java | 6 +++-- 13 files changed, 57 insertions(+), 47 deletions(-) diff --git a/src/main/java/com/ning/http/client/multipart/AbstractFilePart.java b/src/main/java/com/ning/http/client/multipart/AbstractFilePart.java index dbe2f7755d..83e2a46b92 100644 --- a/src/main/java/com/ning/http/client/multipart/AbstractFilePart.java +++ b/src/main/java/com/ning/http/client/multipart/AbstractFilePart.java @@ -16,6 +16,7 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.nio.charset.Charset; /** * This class is an adaptation of the Apache HttpClient implementation @@ -55,7 +56,7 @@ public abstract class AbstractFilePart extends PartBase { * @param charset * the charset encoding for this part */ - public AbstractFilePart(String name, String contentType, String charset, String contentId, String transferEncoding) { + public AbstractFilePart(String name, String contentType, Charset charset, String contentId, String transferEncoding) { super(name,// contentType == null ? DEFAULT_CONTENT_TYPE : contentType,// charset,// diff --git a/src/main/java/com/ning/http/client/multipart/ByteArrayPart.java b/src/main/java/com/ning/http/client/multipart/ByteArrayPart.java index 7f5933e40d..583fa48856 100644 --- a/src/main/java/com/ning/http/client/multipart/ByteArrayPart.java +++ b/src/main/java/com/ning/http/client/multipart/ByteArrayPart.java @@ -15,6 +15,7 @@ import java.io.IOException; import java.io.OutputStream; import java.nio.channels.WritableByteChannel; +import java.nio.charset.Charset; public class ByteArrayPart extends AbstractFilePart { @@ -28,19 +29,19 @@ public ByteArrayPart(String name, byte[] bytes, String contentType) { this(name, bytes, contentType, null); } - public ByteArrayPart(String name, byte[] bytes, String contentType, String charset) { + public ByteArrayPart(String name, byte[] bytes, String contentType, Charset charset) { this(name, bytes, contentType, charset, null); } - public ByteArrayPart(String name, byte[] bytes, String contentType, String charset, String fileName) { + public ByteArrayPart(String name, byte[] bytes, String contentType, Charset charset, String fileName) { this(name, bytes, contentType, charset, fileName, null); } - public ByteArrayPart(String name, byte[] bytes, String contentType, String charset, String fileName, String contentId) { + public ByteArrayPart(String name, byte[] bytes, String contentType, Charset charset, String fileName, String contentId) { this(name, bytes, contentType, charset, fileName, contentId, null); } - public ByteArrayPart(String name, byte[] bytes, String contentType, String charset, String fileName, String contentId, String transferEncoding) { + public ByteArrayPart(String name, byte[] bytes, String contentType, Charset charset, String fileName, String contentId, String transferEncoding) { super(name, contentType, charset, contentId, transferEncoding); if (bytes == null) throw new NullPointerException("bytes"); diff --git a/src/main/java/com/ning/http/client/multipart/FilePart.java b/src/main/java/com/ning/http/client/multipart/FilePart.java index 6932a28fa9..c857b47cb7 100644 --- a/src/main/java/com/ning/http/client/multipart/FilePart.java +++ b/src/main/java/com/ning/http/client/multipart/FilePart.java @@ -23,6 +23,7 @@ import java.io.RandomAccessFile; import java.nio.channels.FileChannel; import java.nio.channels.WritableByteChannel; +import java.nio.charset.Charset; public class FilePart extends AbstractFilePart { @@ -38,19 +39,19 @@ public FilePart(String name, File file, String contentType) { this(name, file, contentType, null); } - public FilePart(String name, File file, String contentType, String charset) { + public FilePart(String name, File file, String contentType, Charset charset) { this(name, file, contentType, charset, null); } - public FilePart(String name, File file, String contentType, String charset, String fileName) { + public FilePart(String name, File file, String contentType, Charset charset, String fileName) { this(name, file, contentType, charset, fileName, null); } - public FilePart(String name, File file, String contentType, String charset, String fileName, String contentId) { + public FilePart(String name, File file, String contentType, Charset charset, String fileName, String contentId) { this(name, file, contentType, charset, fileName, contentId, null); } - public FilePart(String name, File file, String contentType, String charset, String fileName, String contentId, String transferEncoding) { + public FilePart(String name, File file, String contentType, Charset charset, String fileName, String contentId, String transferEncoding) { super(name, contentType, charset, contentId, transferEncoding); if (file == null) throw new NullPointerException("file"); diff --git a/src/main/java/com/ning/http/client/multipart/Part.java b/src/main/java/com/ning/http/client/multipart/Part.java index 1e86eba420..9486a41824 100644 --- a/src/main/java/com/ning/http/client/multipart/Part.java +++ b/src/main/java/com/ning/http/client/multipart/Part.java @@ -17,6 +17,7 @@ import java.io.IOException; import java.io.OutputStream; import java.nio.channels.WritableByteChannel; +import java.nio.charset.Charset; public interface Part { @@ -89,7 +90,7 @@ public interface Part { * * @return the character encoding, or null to exclude the character encoding header */ - String getCharSet(); + Charset getCharset(); /** * Return the transfer encoding of this part. diff --git a/src/main/java/com/ning/http/client/multipart/PartBase.java b/src/main/java/com/ning/http/client/multipart/PartBase.java index c7805d8897..71da20c7e5 100644 --- a/src/main/java/com/ning/http/client/multipart/PartBase.java +++ b/src/main/java/com/ning/http/client/multipart/PartBase.java @@ -16,6 +16,7 @@ import java.io.IOException; import java.io.OutputStream; +import java.nio.charset.Charset; public abstract class PartBase implements Part { @@ -32,7 +33,7 @@ public abstract class PartBase implements Part { /** * The charset (part of Content-Type header) */ - private final String charSet; + private final Charset charset; /** * The Content-Transfer-Encoding header value. @@ -49,8 +50,8 @@ public abstract class PartBase implements Part { */ private String dispositionType; - public PartBase(String name, String contentType, String charSet, String contentId) { - this(name, contentType, charSet, contentId, null); + public PartBase(String name, String contentType, Charset charset, String contentId) { + this(name, contentType, charset, contentId, null); } /** @@ -58,14 +59,14 @@ public PartBase(String name, String contentType, String charSet, String contentI * * @param name The name of the part, or null * @param contentType The content type, or null - * @param charSet The character encoding, or null + * @param charset The character encoding, or null * @param contentId The content id, or null * @param transferEncoding The transfer encoding, or null */ - public PartBase(String name, String contentType, String charSet, String contentId, String transferEncoding) { + public PartBase(String name, String contentType, Charset charset, String contentId, String transferEncoding) { this.name = name; this.contentType = contentType; - this.charSet = charSet; + this.charset = charset; this.contentId = contentId; this.transferEncoding = transferEncoding; } @@ -93,10 +94,10 @@ protected void visitContentTypeHeader(PartVisitor visitor) throws IOException { visitor.withBytes(CRLF_BYTES); visitor.withBytes(CONTENT_TYPE_BYTES); visitor.withBytes(contentType.getBytes(US_ASCII)); - String charSet = getCharSet(); - if (charSet != null) { + Charset charset = getCharset(); + if (charset != null) { visitor.withBytes(CHARSET_BYTES); - visitor.withBytes(charSet.getBytes(US_ASCII)); + visitor.withBytes(charset.name().getBytes(US_ASCII)); } } } @@ -190,7 +191,7 @@ public String toString() { .append(getClass().getSimpleName())// .append(" name=").append(getName())// .append(" contentType=").append(getContentType())// - .append(" charset=").append(getCharSet())// + .append(" charset=").append(getCharset())// .append(" tranferEncoding=").append(getTransferEncoding())// .append(" contentId=").append(getContentId())// .append(" dispositionType=").append(getDispositionType())// @@ -208,8 +209,8 @@ public String getContentType() { } @Override - public String getCharSet() { - return this.charSet; + public Charset getCharset() { + return this.charset; } @Override diff --git a/src/main/java/com/ning/http/client/multipart/StringPart.java b/src/main/java/com/ning/http/client/multipart/StringPart.java index f3dfd9a4b3..d898b213ec 100644 --- a/src/main/java/com/ning/http/client/multipart/StringPart.java +++ b/src/main/java/com/ning/http/client/multipart/StringPart.java @@ -43,12 +43,12 @@ public class StringPart extends PartBase { private final byte[] content; private final String value; - public StringPart(String name, String value, String charset) { + public StringPart(String name, String value, Charset charset) { this(name, value, charset, null); } - private static Charset charsetOrDefault(String charset) { - return charset == null ? DEFAULT_CHARSET : Charset.forName(charset); + private static Charset charsetOrDefault(Charset charset) { + return charset == null ? DEFAULT_CHARSET : charset; } /** @@ -63,8 +63,8 @@ private static Charset charsetOrDefault(String charset) { * @param contentId * the content id */ - public StringPart(String name, String value, String charset, String contentId) { - super(name, DEFAULT_CONTENT_TYPE, charsetOrDefault(charset).name(), contentId, DEFAULT_TRANSFER_ENCODING); + public StringPart(String name, String value, Charset charset, String contentId) { + super(name, DEFAULT_CONTENT_TYPE, charsetOrDefault(charset), contentId, DEFAULT_TRANSFER_ENCODING); if (value == null) throw new NullPointerException("value"); 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 354f722f44..05a82e9792 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 @@ -689,14 +689,14 @@ private MultipartRequestEntity createMultipartRequestEntity(String charset, List parts[i] = new org.apache.commons.httpclient.methods.multipart.FilePart(part.getName(), ((FilePart) part).getFile(), ((FilePart) part).getContentType(), - ((FilePart) part).getCharSet()); + ((FilePart) part).getCharset().name()); } else if (part instanceof ByteArrayPart) { PartSource source = new ByteArrayPartSource(((ByteArrayPart) part).getFileName(), ((ByteArrayPart) part).getBytes()); parts[i] = new org.apache.commons.httpclient.methods.multipart.FilePart(part.getName(), source, ((ByteArrayPart) part).getContentType(), - ((ByteArrayPart) part).getCharSet()); + ((ByteArrayPart) part).getCharset().name()); } else if (part == null) { throw new NullPointerException("Part cannot be 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 1f2e1b789f..8be286b923 100755 --- a/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java +++ b/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java @@ -677,7 +677,7 @@ public void asyncDoPostMultiPartTest() throws Throwable { try { final CountDownLatch l = new CountDownLatch(1); - Part p = new StringPart("foo", "bar", StandardCharsets.UTF_8.name()); + Part p = new StringPart("foo", "bar", StandardCharsets.UTF_8); client.preparePost(getTargetUrl()).addBodyPart(p).execute(new AsyncCompletionHandlerAdapter() { diff --git a/src/test/java/com/ning/http/client/async/FastUnauthorizedUploadTest.java b/src/test/java/com/ning/http/client/async/FastUnauthorizedUploadTest.java index 984a8b7238..acbeb90e6f 100644 --- a/src/test/java/com/ning/http/client/async/FastUnauthorizedUploadTest.java +++ b/src/test/java/com/ning/http/client/async/FastUnauthorizedUploadTest.java @@ -57,7 +57,7 @@ public void testUnauthorizedWhileUploading() throws Exception { try { BoundRequestBuilder rb = client.preparePut(getTargetUrl()); - rb.addBodyPart(new FilePart("test", largeFile, "application/octet-stream", StandardCharsets.UTF_8.name())); + rb.addBodyPart(new FilePart("test", largeFile, "application/octet-stream", StandardCharsets.UTF_8)); Response response = rb.execute().get(); Assert.assertEquals(401, response.getStatusCode()); 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 b9ed713d9d..a9f748f147 100644 --- a/src/test/java/com/ning/http/client/async/FilePartLargeFileTest.java +++ b/src/test/java/com/ning/http/client/async/FilePartLargeFileTest.java @@ -24,6 +24,7 @@ import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.Response; import com.ning.http.client.multipart.FilePart; +import com.ning.http.util.StandardCharsets; import javax.servlet.ServletException; import javax.servlet.ServletInputStream; @@ -46,7 +47,7 @@ public void testPutImageFile() throws Exception { 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", StandardCharsets.UTF_8)); Response response = rb.execute().get(); Assert.assertEquals(200, response.getStatusCode()); @@ -57,7 +58,7 @@ public void testPutImageFile() throws Exception { @Test(groups = { "standalone", "default_provider" }, enabled = true) public void testPutLargeTextFile() throws Exception { - byte[] bytes = "RatherLargeFileRatherLargeFileRatherLargeFileRatherLargeFile".getBytes("UTF-16"); + byte[] bytes = "RatherLargeFileRatherLargeFileRatherLargeFileRatherLargeFile".getBytes(StandardCharsets.UTF_16); long repeats = (1024 * 1024 / bytes.length) + 1; File largeFile = createTempFile(bytes, (int) repeats); @@ -65,7 +66,7 @@ public void testPutLargeTextFile() throws Exception { 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", StandardCharsets.UTF_8)); Response response = rb.execute().get(); Assert.assertEquals(200, response.getStatusCode()); 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 d290795e5d..ea96b64412 100644 --- a/src/test/java/com/ning/http/client/async/MultipartUploadTest.java +++ b/src/test/java/com/ning/http/client/async/MultipartUploadTest.java @@ -12,6 +12,8 @@ */ package com.ning.http.client.async; +import static com.ning.http.util.StandardCharsets.*; + import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertTrue; @@ -41,7 +43,6 @@ import com.ning.http.client.multipart.FilePart; import com.ning.http.client.multipart.StringPart; import com.ning.http.util.AsyncHttpProviderUtils; -import com.ning.http.util.StandardCharsets; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; @@ -218,16 +219,16 @@ public void testSendingSmallFilesAndByteArray() { try { RequestBuilder builder = new RequestBuilder("POST"); builder.setUrl(servletEndpointRedirectUrl + "/upload/bob"); - builder.addBodyPart(new FilePart("file1", testResource1File, "text/plain", "UTF-8")); + builder.addBodyPart(new FilePart("file1", testResource1File, "text/plain", UTF_8)); builder.addBodyPart(new FilePart("file2", testResource2File, "application/x-gzip", null)); - builder.addBodyPart(new StringPart("Name", "Dominic", "UTF-8")); - builder.addBodyPart(new FilePart("file3", testResource3File, "text/plain", "UTF-8")); + builder.addBodyPart(new StringPart("Name", "Dominic", UTF_8)); + builder.addBodyPart(new FilePart("file3", testResource3File, "text/plain", UTF_8)); - builder.addBodyPart(new StringPart("Age", "3", AsyncHttpProviderUtils.DEFAULT_CHARSET.name())); - builder.addBodyPart(new StringPart("Height", "shrimplike", AsyncHttpProviderUtils.DEFAULT_CHARSET.name())); - builder.addBodyPart(new StringPart("Hair", "ridiculous", AsyncHttpProviderUtils.DEFAULT_CHARSET.name())); + builder.addBodyPart(new StringPart("Age", "3", AsyncHttpProviderUtils.DEFAULT_CHARSET)); + builder.addBodyPart(new StringPart("Height", "shrimplike", AsyncHttpProviderUtils.DEFAULT_CHARSET)); + builder.addBodyPart(new StringPart("Hair", "ridiculous", AsyncHttpProviderUtils.DEFAULT_CHARSET)); - builder.addBodyPart(new ByteArrayPart("file4", expectedContents.getBytes(StandardCharsets.UTF_8), "text/plain", StandardCharsets.UTF_8.name(), "bytearray.txt")); + builder.addBodyPart(new ByteArrayPart("file4", expectedContents.getBytes(UTF_8), "text/plain", UTF_8, "bytearray.txt")); com.ning.http.client.Request r = builder.build(); 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 026a87fd4f..4cb6e3973d 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,8 @@ */ package com.ning.http.client.async; +import static com.ning.http.util.StandardCharsets.UTF_8; + import static junit.framework.Assert.assertTrue; import static org.testng.Assert.assertEquals; import static org.testng.Assert.fail; @@ -30,7 +32,6 @@ import com.ning.http.client.simple.HeaderMap; import com.ning.http.client.simple.SimpleAHCTransferListener; import com.ning.http.client.uri.UriComponents; -import com.ning.http.util.StandardCharsets; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -266,7 +267,7 @@ public void testCloseMasterInvalidDerived() throws Exception { public void testMultiPartPut() throws Exception { SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setProviderClass(getProviderClass()).setUrl(getTargetUrl() + "/multipart").build(); try { - Response response = client.put(new ByteArrayPart("baPart", "testMultiPart".getBytes(StandardCharsets.UTF_8), "application/test", StandardCharsets.UTF_8.name(), "fileName")).get(); + Response response = client.put(new ByteArrayPart("baPart", "testMultiPart".getBytes(UTF_8), "application/test", UTF_8, "fileName")).get(); String body = response.getResponseBody(); String contentType = response.getHeader("X-Content-Type"); @@ -290,7 +291,7 @@ public void testMultiPartPut() throws Exception { public void testMultiPartPost() throws Exception { SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setProviderClass(getProviderClass()).setUrl(getTargetUrl() + "/multipart").build(); try { - Response response = client.post(new ByteArrayPart("baPart", "testMultiPart".getBytes(StandardCharsets.UTF_8), "application/test", StandardCharsets.UTF_8.name(), "fileName")).get(); + Response response = client.post(new ByteArrayPart("baPart", "testMultiPart".getBytes(UTF_8), "application/test", UTF_8, "fileName")).get(); String body = response.getResponseBody(); String contentType = response.getHeader("X-Content-Type"); diff --git a/src/test/java/com/ning/http/client/multipart/MultipartBodyTest.java b/src/test/java/com/ning/http/client/multipart/MultipartBodyTest.java index 8b7af839a4..61ff33bf71 100644 --- a/src/test/java/com/ning/http/client/multipart/MultipartBodyTest.java +++ b/src/test/java/com/ning/http/client/multipart/MultipartBodyTest.java @@ -12,6 +12,8 @@ */ package com.ning.http.client.multipart; +import static com.ning.http.util.StandardCharsets.UTF_8; + import org.testng.Assert; import org.testng.annotations.Test; @@ -38,10 +40,10 @@ public void testBasics() { parts.add(new FilePart("filePart", testFile)); // add a byte array - parts.add(new ByteArrayPart("baPart", "testMultiPart".getBytes(StandardCharsets.UTF_8), "application/test", StandardCharsets.UTF_8.name(), "fileName")); + parts.add(new ByteArrayPart("baPart", "testMultiPart".getBytes(UTF_8), "application/test", StandardCharsets.UTF_8, "fileName")); // add a string - parts.add(new StringPart("stringPart", "testString", "utf-8")); + parts.add(new StringPart("stringPart", "testString", UTF_8)); compareContentLength(parts); } From 80441ac634efd81efa38633164463eba1e0c2213 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 28 Jul 2014 12:16:07 +0200 Subject: [PATCH 494/701] NettyFileBody ignores offset parameter, close #653, close #650 --- .../client/providers/netty/request/body/NettyFileBody.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/request/body/NettyFileBody.java b/src/main/java/com/ning/http/client/providers/netty/request/body/NettyFileBody.java index 09c5b911ff..c342c694c7 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/body/NettyFileBody.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/body/NettyFileBody.java @@ -34,8 +34,6 @@ public class NettyFileBody implements NettyBody { private static final Logger LOGGER = LoggerFactory.getLogger(NettyFileBody.class); - public final static int MAX_BUFFERED_BYTES = 8192; - private final File file; private final long offset; private final long length; @@ -80,9 +78,9 @@ public void write(Channel channel, NettyResponseFuture future, AsyncHttpClien try { ChannelFuture writeFuture; if (ChannelManager.isSslHandlerConfigured(channel.getPipeline()) || nettyConfig.isDisableZeroCopy()) { - writeFuture = channel.write(new ChunkedFile(raf, 0, raf.length(), nettyConfig.getChunkedFileChunkSize())); + writeFuture = channel.write(new ChunkedFile(raf, offset, raf.length(), nettyConfig.getChunkedFileChunkSize())); } else { - final FileRegion region = new OptimizedFileRegion(raf, 0, raf.length()); + final FileRegion region = new OptimizedFileRegion(raf, offset, raf.length()); writeFuture = channel.write(region); } writeFuture.addListener(new ProgressListener(config, future.getAsyncHandler(), future, false) { From 5ac8204c12e37b019743b562656dd350d8e169a2 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 28 Jul 2014 13:29:43 +0200 Subject: [PATCH 495/701] Minor clean up --- .../netty/handler/WebSocketProtocol.java | 57 +++++++++---------- .../providers/netty/ws/NettyWebSocket.java | 16 +++--- 2 files changed, 36 insertions(+), 37 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/handler/WebSocketProtocol.java b/src/main/java/com/ning/http/client/providers/netty/handler/WebSocketProtocol.java index 3e341373a7..c88115b1ba 100644 --- a/src/main/java/com/ning/http/client/providers/netty/handler/WebSocketProtocol.java +++ b/src/main/java/com/ning/http/client/providers/netty/handler/WebSocketProtocol.java @@ -23,6 +23,7 @@ import org.jboss.netty.handler.codec.http.HttpResponse; 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.WebSocketFrame; import com.ning.http.client.AsyncHandler.STATE; @@ -134,36 +135,34 @@ public void handle(Channel channel, NettyResponseFuture future, Object e) thr Channels.setDiscard(channel); CloseWebSocketFrame closeFrame = CloseWebSocketFrame.class.cast(frame); webSocket.onClose(closeFrame.getStatusCode(), closeFrame.getReasonText()); - } else { - - if (frame.getBinaryData() != null) { - HttpChunk webSocketChunk = new HttpChunk() { - private ChannelBuffer content = frame.getBinaryData(); - - @Override - public boolean isLast() { - return false; - } - - @Override - public ChannelBuffer getContent() { - return content; - } - - @Override - public void setContent(ChannelBuffer content) { - throw new UnsupportedOperationException(); - } - }; - - NettyResponseBodyPart rp = new NettyResponseBodyPart(null, webSocketChunk, true); - handler.onBodyPartReceived(rp); - - if (frame instanceof BinaryWebSocketFrame) { - webSocket.onBinaryFragment(rp.getBodyPartBytes(), frame.isFinalFragment()); - } else { - webSocket.onTextFragment(frame.getBinaryData().toString(StandardCharsets.UTF_8), frame.isFinalFragment()); + + } else if (frame.getBinaryData() != null) { + HttpChunk webSocketChunk = new HttpChunk() { + private ChannelBuffer content = frame.getBinaryData(); + + @Override + public boolean isLast() { + return frame.isFinalFragment(); + } + + @Override + public ChannelBuffer getContent() { + return content; } + + @Override + public void setContent(ChannelBuffer content) { + throw new UnsupportedOperationException(); + } + }; + + NettyResponseBodyPart rp = new NettyResponseBodyPart(null, webSocketChunk, frame.isFinalFragment()); + handler.onBodyPartReceived(rp); + + if (frame instanceof BinaryWebSocketFrame) { + webSocket.onBinaryFragment(rp.getBodyPartBytes(), frame.isFinalFragment()); + } else { + webSocket.onTextFragment(frame.getBinaryData().toString(StandardCharsets.UTF_8), frame.isFinalFragment()); } } } else { diff --git a/src/main/java/com/ning/http/client/providers/netty/ws/NettyWebSocket.java b/src/main/java/com/ning/http/client/providers/netty/ws/NettyWebSocket.java index 2fd03e2cba..e1df876d5f 100644 --- a/src/main/java/com/ning/http/client/providers/netty/ws/NettyWebSocket.java +++ b/src/main/java/com/ning/http/client/providers/netty/ws/NettyWebSocket.java @@ -188,22 +188,22 @@ public void onTextFragment(String message, boolean last) { } } - for (WebSocketListener l : listeners) { - if (l instanceof WebSocketTextListener) { + for (WebSocketListener listener : listeners) { + if (listener instanceof WebSocketTextListener) { + WebSocketTextListener textlistener = (WebSocketTextListener) listener; try { if (!last) { - WebSocketTextListener.class.cast(l).onFragment(message, last); + textlistener.onFragment(message, last); } else { if (textBuffer.length() > 0) { - WebSocketTextListener.class.cast(l).onFragment(message, last); - - WebSocketTextListener.class.cast(l).onMessage(textBuffer.append(message).toString()); + textlistener.onFragment(message, last); + textlistener.onMessage(textBuffer.append(message).toString()); } else { - WebSocketTextListener.class.cast(l).onMessage(message); + textlistener.onMessage(message); } } } catch (Exception ex) { - l.onError(ex); + listener.onError(ex); } } } From 09a97fef3f56542d0064f4dd31d34f047f0a56b5 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 28 Jul 2014 13:30:11 +0200 Subject: [PATCH 496/701] unused import --- .../http/client/providers/netty/handler/WebSocketProtocol.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/handler/WebSocketProtocol.java b/src/main/java/com/ning/http/client/providers/netty/handler/WebSocketProtocol.java index c88115b1ba..3152a4febf 100644 --- a/src/main/java/com/ning/http/client/providers/netty/handler/WebSocketProtocol.java +++ b/src/main/java/com/ning/http/client/providers/netty/handler/WebSocketProtocol.java @@ -23,7 +23,6 @@ import org.jboss.netty.handler.codec.http.HttpResponse; 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.WebSocketFrame; import com.ning.http.client.AsyncHandler.STATE; From e33049520fce4dcb8cbe07e51aecefdd73f836e9 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 29 Jul 2014 11:54:09 +0200 Subject: [PATCH 497/701] minor clean up --- .../providers/netty/handler/WebSocketProtocol.java | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/handler/WebSocketProtocol.java b/src/main/java/com/ning/http/client/providers/netty/handler/WebSocketProtocol.java index 3152a4febf..8790fae39d 100644 --- a/src/main/java/com/ning/http/client/providers/netty/handler/WebSocketProtocol.java +++ b/src/main/java/com/ning/http/client/providers/netty/handler/WebSocketProtocol.java @@ -87,12 +87,10 @@ public void handle(Channel channel, NettyResponseFuture future, Object e) thr boolean validStatus = response.getStatus().equals(SWITCHING_PROTOCOLS); boolean validUpgrade = response.headers().get(HttpHeaders.Names.UPGRADE) != null; - String c = response.headers().get(HttpHeaders.Names.CONNECTION); - if (c == null) { - c = response.headers().get(HttpHeaders.Names.CONNECTION.toLowerCase(Locale.ENGLISH)); - } - - boolean validConnection = c != null && c.equalsIgnoreCase(HttpHeaders.Values.UPGRADE); + String connection = response.headers().get(HttpHeaders.Names.CONNECTION); + if (connection == null) + connection = response.headers().get(HttpHeaders.Names.CONNECTION.toLowerCase(Locale.ENGLISH)); + boolean validConnection = HttpHeaders.Values.UPGRADE.equalsIgnoreCase(connection); status = new NettyResponseStatus(future.getURI(), config, response); final boolean statusReceived = handler.onStatusReceived(status) == STATE.UPGRADE; From ac0cbd3f5140867ac6f8f02740d27fee02068e8e Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 29 Jul 2014 12:19:45 +0200 Subject: [PATCH 498/701] RandomAccessBody.transferTo count is actually unused (Long.MAX_VALUE) --- .../java/com/ning/http/client/RandomAccessBody.java | 4 +--- .../http/client/generators/FileBodyGenerator.java | 11 ++++------- .../com/ning/http/client/multipart/MultipartBody.java | 2 +- .../providers/netty/request/body/BodyFileRegion.java | 2 +- 4 files changed, 7 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/ning/http/client/RandomAccessBody.java b/src/main/java/com/ning/http/client/RandomAccessBody.java index 725b092db6..cfb1720284 100644 --- a/src/main/java/com/ning/http/client/RandomAccessBody.java +++ b/src/main/java/com/ning/http/client/RandomAccessBody.java @@ -25,11 +25,9 @@ public interface RandomAccessBody extends Body { * Transfers the specified chunk of bytes from this body to the specified channel. * * @param position The zero-based byte index from which to start the transfer, must not be negative. - * @param count The maximum number of bytes to transfer, must not be negative. * @param target The destination channel to transfer the body chunk to, must not be {@code null}. * @return The non-negative number of bytes actually transferred. * @throws IOException If the body chunk could not be transferred. */ - long transferTo(long position, long count, WritableByteChannel target) - throws IOException; + long transferTo(long position, WritableByteChannel target) throws IOException; } diff --git a/src/main/java/com/ning/http/client/generators/FileBodyGenerator.java b/src/main/java/com/ning/http/client/generators/FileBodyGenerator.java index 086a98b6db..4cd2afb8df 100644 --- a/src/main/java/com/ning/http/client/generators/FileBodyGenerator.java +++ b/src/main/java/com/ning/http/client/generators/FileBodyGenerator.java @@ -25,8 +25,8 @@ /** * Creates a request body from the contents of a file. */ -public class FileBodyGenerator - implements BodyGenerator { +// Not used by Netty +public class FileBodyGenerator implements BodyGenerator { private final File file; private final long regionSeek; @@ -104,12 +104,9 @@ public long read(ByteBuffer buffer) } @Override - public long transferTo(long position, long count, WritableByteChannel target) + public long transferTo(long position, WritableByteChannel target) throws IOException { - if (count > length) { - count = length; - } - return channel.transferTo(position, count, target); + return channel.transferTo(position, length, target); } @Override diff --git a/src/main/java/com/ning/http/client/multipart/MultipartBody.java b/src/main/java/com/ning/http/client/multipart/MultipartBody.java index 65ed480c5b..a2c9cbc629 100644 --- a/src/main/java/com/ning/http/client/multipart/MultipartBody.java +++ b/src/main/java/com/ning/http/client/multipart/MultipartBody.java @@ -70,7 +70,7 @@ public String getContentType() { } // RandomAccessBody API, suited for HTTP but not for HTTPS - public long transferTo(long position, long count, WritableByteChannel target) throws IOException { + public long transferTo(long position, WritableByteChannel target) throws IOException { long overallLength = 0; diff --git a/src/main/java/com/ning/http/client/providers/netty/request/body/BodyFileRegion.java b/src/main/java/com/ning/http/client/providers/netty/request/body/BodyFileRegion.java index d32131fca9..bdb73961a3 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/body/BodyFileRegion.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/body/BodyFileRegion.java @@ -43,7 +43,7 @@ public long getCount() { public long transferTo(WritableByteChannel target, long position) throws IOException { - return body.transferTo(position, Long.MAX_VALUE, target); + return body.transferTo(position, target); } public void releaseExternalResources() { From 29894b63f8f7c2e68973fb8e9bda42a1eab3ecbe Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 29 Jul 2014 12:19:53 +0200 Subject: [PATCH 499/701] comments --- .../com/ning/http/client/multipart/MultipartRequestEntity.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/ning/http/client/multipart/MultipartRequestEntity.java b/src/main/java/com/ning/http/client/multipart/MultipartRequestEntity.java index 94b99038a1..558daca891 100644 --- a/src/main/java/com/ning/http/client/multipart/MultipartRequestEntity.java +++ b/src/main/java/com/ning/http/client/multipart/MultipartRequestEntity.java @@ -30,6 +30,7 @@ * * @link http://hc.apache.org/httpclient-3.x/ */ +@Deprecated public class MultipartRequestEntity implements RequestEntity { /** From 76d7198d45c695da5199e6e31aacd664a3ed26c0 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 29 Jul 2014 12:21:46 +0200 Subject: [PATCH 500/701] Remove useless synchronized --- .../http/client/multipart/MultipartUtils.java | 78 +++++++++---------- 1 file changed, 38 insertions(+), 40 deletions(-) diff --git a/src/main/java/com/ning/http/client/multipart/MultipartUtils.java b/src/main/java/com/ning/http/client/multipart/MultipartUtils.java index b51a28ea20..07b0cc9a33 100644 --- a/src/main/java/com/ning/http/client/multipart/MultipartUtils.java +++ b/src/main/java/com/ning/http/client/multipart/MultipartUtils.java @@ -110,50 +110,48 @@ public static long writeBytesToChannel(WritableByteChannel target, byte[] bytes) int written = 0; int maxSpin = 0; - synchronized (bytes) { - ByteBuffer message = ByteBuffer.wrap(bytes); - - if (target instanceof SocketChannel) { - final Selector selector = Selector.open(); - try { - final SocketChannel channel = (SocketChannel) target; - channel.register(selector, SelectionKey.OP_WRITE); - - while (written < bytes.length) { - selector.select(1000); - maxSpin++; - final Set selectedKeys = selector.selectedKeys(); - - for (SelectionKey key : selectedKeys) { - if (key.isWritable()) { - written += target.write(message); - maxSpin = 0; - } - } - if (maxSpin >= 10) { - throw new IOException("Unable to write on channel " + target); + ByteBuffer message = ByteBuffer.wrap(bytes); + + if (target instanceof SocketChannel) { + final Selector selector = Selector.open(); + try { + final SocketChannel channel = (SocketChannel) target; + channel.register(selector, SelectionKey.OP_WRITE); + + while (written < bytes.length) { + selector.select(1000); + maxSpin++; + final Set selectedKeys = selector.selectedKeys(); + + for (SelectionKey key : selectedKeys) { + if (key.isWritable()) { + written += target.write(message); + maxSpin = 0; } } - } finally { - selector.close(); + if (maxSpin >= 10) { + throw new IOException("Unable to write on channel " + target); + } } - } else { - while ((target.isOpen()) && (written < bytes.length)) { - long nWrite = target.write(message); - written += nWrite; - if (nWrite == 0 && maxSpin++ < 10) { - LOGGER.info("Waiting for writing..."); - try { - bytes.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; + } finally { + selector.close(); + } + } else { + while ((target.isOpen()) && (written < bytes.length)) { + long nWrite = target.write(message); + written += nWrite; + if (nWrite == 0 && maxSpin++ < 10) { + LOGGER.info("Waiting for writing..."); + try { + bytes.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 967903d3893ef471d862c506bbf128704d933f43 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 29 Jul 2014 12:37:29 +0200 Subject: [PATCH 501/701] Only set Content-Length is strictly positive --- .../client/providers/netty/request/NettyRequestFactory.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestFactory.java b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestFactory.java index 145e6bf929..7ed0e0c16a 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestFactory.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestFactory.java @@ -271,7 +271,7 @@ public NettyRequest newNettyRequest(Request request, UriComponents uri, boolean } if (body != null) { - if (body.getContentLength() >= 0) + if (body.getContentLength() > 0) httpRequest.headers().set(HttpHeaders.Names.CONTENT_LENGTH, body.getContentLength()); else httpRequest.headers().set(HttpHeaders.Names.TRANSFER_ENCODING, HttpHeaders.Values.CHUNKED); From f6cedfb483c709bc2f48d96c4ae53a1b3a0ad349 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 29 Jul 2014 12:43:59 +0200 Subject: [PATCH 502/701] Move MultipartRequestEntity to jdk provider package --- .../providers/grizzly/FeedableBodyGenerator.java | 2 +- .../client/providers/jdk/JDKAsyncHttpProvider.java | 1 - .../jdk}/MultipartRequestEntity.java | 6 ++++-- .../netty/request/FeedableBodyGenerator.java | 2 +- .../ning/http/client/multipart/MultipartBodyTest.java | 11 ++++++----- 5 files changed, 12 insertions(+), 10 deletions(-) rename src/main/java/com/ning/http/client/{multipart => providers/jdk}/MultipartRequestEntity.java (95%) 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 208cd40b30..049c0558a0 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 @@ -243,7 +243,7 @@ public long read(final ByteBuffer buffer) throws IOException { } @Override - public void close() throws IOException { + public void close() { context.completeAndRecycle(); context = null; requestPacket = null; 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 2ad407f9d5..7570cb9c25 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 @@ -37,7 +37,6 @@ import com.ning.http.client.filter.IOExceptionFilter; import com.ning.http.client.filter.ResponseFilter; import com.ning.http.client.listener.TransferCompletionHandler; -import com.ning.http.client.multipart.MultipartRequestEntity; import com.ning.http.client.uri.UriComponents; import com.ning.http.util.AsyncHttpProviderUtils; import com.ning.http.util.AuthenticatorUtils; diff --git a/src/main/java/com/ning/http/client/multipart/MultipartRequestEntity.java b/src/main/java/com/ning/http/client/providers/jdk/MultipartRequestEntity.java similarity index 95% rename from src/main/java/com/ning/http/client/multipart/MultipartRequestEntity.java rename to src/main/java/com/ning/http/client/providers/jdk/MultipartRequestEntity.java index 558daca891..634eddfe05 100644 --- a/src/main/java/com/ning/http/client/multipart/MultipartRequestEntity.java +++ b/src/main/java/com/ning/http/client/providers/jdk/MultipartRequestEntity.java @@ -13,12 +13,15 @@ * License for the specific language governing permissions and limitations * under the License. */ -package com.ning.http.client.multipart; +package com.ning.http.client.providers.jdk; import static com.ning.http.util.MiscUtils.isNonEmpty; import static com.ning.http.util.StandardCharsets.US_ASCII; import com.ning.http.client.FluentCaseInsensitiveStringsMap; +import com.ning.http.client.multipart.MultipartUtils; +import com.ning.http.client.multipart.Part; +import com.ning.http.client.multipart.RequestEntity; import java.io.IOException; import java.io.OutputStream; @@ -30,7 +33,6 @@ * * @link http://hc.apache.org/httpclient-3.x/ */ -@Deprecated public class MultipartRequestEntity implements RequestEntity { /** diff --git a/src/main/java/com/ning/http/client/providers/netty/request/FeedableBodyGenerator.java b/src/main/java/com/ning/http/client/providers/netty/request/FeedableBodyGenerator.java index 31d6425b90..0bd84a182a 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/FeedableBodyGenerator.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/FeedableBodyGenerator.java @@ -103,7 +103,7 @@ public long read(final ByteBuffer buffer) throws IOException { } @Override - public void close() throws IOException { + public void close() { } } diff --git a/src/test/java/com/ning/http/client/multipart/MultipartBodyTest.java b/src/test/java/com/ning/http/client/multipart/MultipartBodyTest.java index 61ff33bf71..addc881f95 100644 --- a/src/test/java/com/ning/http/client/multipart/MultipartBodyTest.java +++ b/src/test/java/com/ning/http/client/multipart/MultipartBodyTest.java @@ -19,6 +19,10 @@ import com.ning.http.client.Body; import com.ning.http.client.FluentCaseInsensitiveStringsMap; +import com.ning.http.client.multipart.ByteArrayPart; +import com.ning.http.client.multipart.FilePart; +import com.ning.http.client.multipart.Part; +import com.ning.http.client.multipart.StringPart; import com.ning.http.util.StandardCharsets; import java.io.File; @@ -64,11 +68,8 @@ private static File getTestfile() { private static void compareContentLength(final List parts) { Assert.assertNotNull(parts); // get expected values - MultipartRequestEntity mre = new MultipartRequestEntity(parts, new FluentCaseInsensitiveStringsMap()); - final long expectedContentLength = mre.getContentLength(); - - // get real bytes - final Body multipartBody = new MultipartBody(parts, mre.getContentType(), expectedContentLength, mre.getMultipartBoundary()); + final Body multipartBody = MultipartUtils.newMultipartBody(parts, new FluentCaseInsensitiveStringsMap()); + final long expectedContentLength = multipartBody.getContentLength(); try { final ByteBuffer buffer = ByteBuffer.allocate(8192); boolean last = false; From 30c1c11ae8b87799b5efe6dcd69adaee479ceb09 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 29 Jul 2014 12:44:13 +0200 Subject: [PATCH 503/701] minor clean up --- .../ning/http/client/generators/ByteArrayBodyGenerator.java | 2 +- .../com/ning/http/client/generators/FileBodyGenerator.java | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/ning/http/client/generators/ByteArrayBodyGenerator.java b/src/main/java/com/ning/http/client/generators/ByteArrayBodyGenerator.java index 307404b87b..747718c186 100644 --- a/src/main/java/com/ning/http/client/generators/ByteArrayBodyGenerator.java +++ b/src/main/java/com/ning/http/client/generators/ByteArrayBodyGenerator.java @@ -58,7 +58,7 @@ public long read(ByteBuffer byteBuffer) throws IOException { } @Override - public void close() throws IOException { + public void close() { lastPosition = 0; eof = false; } diff --git a/src/main/java/com/ning/http/client/generators/FileBodyGenerator.java b/src/main/java/com/ning/http/client/generators/FileBodyGenerator.java index 4cd2afb8df..acb3fcb616 100644 --- a/src/main/java/com/ning/http/client/generators/FileBodyGenerator.java +++ b/src/main/java/com/ning/http/client/generators/FileBodyGenerator.java @@ -110,8 +110,7 @@ public long transferTo(long position, WritableByteChannel target) } @Override - public void close() - throws IOException { + public void close() throws IOException { file.close(); } } From d04a83a47c0b9d4dcb35b09bf6cd281d94e6f19c Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 29 Jul 2014 13:36:24 +0200 Subject: [PATCH 504/701] Make Body and BodyConsumer Closeable --- src/main/java/com/ning/http/client/Body.java | 10 ++-------- .../com/ning/http/client/BodyConsumer.java | 10 ++-------- .../http/client/SimpleAsyncHttpClient.java | 12 ++---------- .../ResumableRandomAccessFileListener.java | 11 +++-------- .../client/multipart/CounterPartVisitor.java | 6 ++---- .../apache/ApacheAsyncHttpProvider.java | 7 ++----- .../providers/jdk/JDKAsyncHttpProvider.java | 7 ++----- .../netty/request/body/BodyFileRegion.java | 12 ++++-------- .../netty/request/body/NettyBodyBody.java | 14 ++++---------- .../netty/request/body/NettyFileBody.java | 19 ++++--------------- .../request/body/NettyInputStreamBody.java | 8 +++----- .../request/body/OptimizedFileRegion.java | 19 ++++--------------- .../PropertiesBasedResumableProcessor.java | 10 ++++------ .../java/com/ning/http/util/MiscUtils.java | 9 +++++++++ 14 files changed, 47 insertions(+), 107 deletions(-) diff --git a/src/main/java/com/ning/http/client/Body.java b/src/main/java/com/ning/http/client/Body.java index b26be40790..e9634c9ef8 100644 --- a/src/main/java/com/ning/http/client/Body.java +++ b/src/main/java/com/ning/http/client/Body.java @@ -13,13 +13,14 @@ package com.ning.http.client; +import java.io.Closeable; import java.io.IOException; import java.nio.ByteBuffer; /** * A request body. */ -public interface Body { +public interface Body extends Closeable { /** * Gets the length of the body. @@ -36,11 +37,4 @@ public interface Body { * @throws IOException If the chunk could not be read. */ long read(ByteBuffer buffer) throws IOException; - - /** - * Releases any resources associated with this body. - * - * @throws IOException - */ - void close() throws IOException; } diff --git a/src/main/java/com/ning/http/client/BodyConsumer.java b/src/main/java/com/ning/http/client/BodyConsumer.java index c9e188b76e..486f3dd0c6 100644 --- a/src/main/java/com/ning/http/client/BodyConsumer.java +++ b/src/main/java/com/ning/http/client/BodyConsumer.java @@ -13,13 +13,14 @@ package com.ning.http.client; +import java.io.Closeable; import java.io.IOException; import java.nio.ByteBuffer; /** * A simple API to be used with the {@link SimpleAsyncHttpClient} class in order to process response's bytes. */ -public interface BodyConsumer { +public interface BodyConsumer extends Closeable { /** * Consume the received bytes. @@ -28,11 +29,4 @@ public interface BodyConsumer { * @throws IOException */ void consume(ByteBuffer byteBuffer) throws IOException; - - /** - * Invoked when all the response bytes has been processed. - * - * @throws IOException - */ - void close() throws IOException; } diff --git a/src/main/java/com/ning/http/client/SimpleAsyncHttpClient.java b/src/main/java/com/ning/http/client/SimpleAsyncHttpClient.java index d428f38628..c99a578cc9 100644 --- a/src/main/java/com/ning/http/client/SimpleAsyncHttpClient.java +++ b/src/main/java/com/ning/http/client/SimpleAsyncHttpClient.java @@ -12,8 +12,7 @@ */ package com.ning.http.client; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import static com.ning.http.util.MiscUtils.closeSilently; import com.ning.http.client.cookie.Cookie; import com.ning.http.client.multipart.Part; @@ -64,7 +63,6 @@ */ public class SimpleAsyncHttpClient { - private final static Logger logger = LoggerFactory.getLogger(SimpleAsyncHttpClient.class); private final AsyncHttpClientConfig config; private final RequestBuilder requestBuilder; private AsyncHttpClient asyncHttpClient; @@ -764,13 +762,7 @@ public Response onCompleted(Response response) throws Exception { } private void closeConsumer() { - try { - if (bodyConsumer != null) { - bodyConsumer.close(); - } - } catch (IOException ex) { - logger.warn("Unable to close a BodyConsumer {}", bodyConsumer); - } + closeSilently(bodyConsumer); } @Override diff --git a/src/main/java/com/ning/http/client/extra/ResumableRandomAccessFileListener.java b/src/main/java/com/ning/http/client/extra/ResumableRandomAccessFileListener.java index aa7bdbd1ca..9b2c0e169c 100644 --- a/src/main/java/com/ning/http/client/extra/ResumableRandomAccessFileListener.java +++ b/src/main/java/com/ning/http/client/extra/ResumableRandomAccessFileListener.java @@ -12,6 +12,8 @@ */ package com.ning.http.client.extra; +import static com.ning.http.util.MiscUtils.closeSilently; + import com.ning.http.client.resumable.ResumableListener; import java.io.IOException; @@ -43,20 +45,13 @@ public void onBytesReceived(ByteBuffer buffer) throws IOException { @Override public void onAllBytesReceived() { - if (file != null) { - try { - file.close(); - } catch (IOException e) { - ; - } - } + closeSilently(file); } public long length() { try { return file.length(); } catch (IOException e) { - ; } return 0; } diff --git a/src/main/java/com/ning/http/client/multipart/CounterPartVisitor.java b/src/main/java/com/ning/http/client/multipart/CounterPartVisitor.java index 6d903243a6..ee59e0d2ee 100644 --- a/src/main/java/com/ning/http/client/multipart/CounterPartVisitor.java +++ b/src/main/java/com/ning/http/client/multipart/CounterPartVisitor.java @@ -12,19 +12,17 @@ */ package com.ning.http.client.multipart; -import java.io.IOException; - public class CounterPartVisitor implements PartVisitor { private long count = 0L; @Override - public void withBytes(byte[] bytes) throws IOException { + public void withBytes(byte[] bytes) { count += bytes.length; } @Override - public void withByte(byte b) throws IOException { + public void withByte(byte b) { count++; } 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 05a82e9792..196f4db9e0 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 @@ -13,6 +13,7 @@ package com.ning.http.client.providers.apache; import static com.ning.http.util.AsyncHttpProviderUtils.DEFAULT_CHARSET; +import static com.ning.http.util.MiscUtils.closeSilently; import static com.ning.http.util.MiscUtils.isNonEmpty; import org.apache.commons.httpclient.CircularRedirectException; @@ -329,11 +330,7 @@ private HttpMethodBase createMethod(HttpClient client, Request request) throws I post.setRequestEntity(new ByteArrayRequestEntity(bytes)); } } finally { - try { - body.close(); - } catch (IOException e) { - logger.warn("Failed to close request body: {}", e.getMessage(), e); - } + closeSilently(body); } } 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 7570cb9c25..f1cf43e966 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 @@ -13,6 +13,7 @@ package com.ning.http.client.providers.jdk; import static com.ning.http.util.AsyncHttpProviderUtils.DEFAULT_CHARSET; +import static com.ning.http.util.MiscUtils.closeSilently; import static com.ning.http.util.MiscUtils.isNonEmpty; import org.slf4j.Logger; @@ -629,11 +630,7 @@ private void configure(UriComponents uri, HttpURLConnection urlConnection, Reque os.write(buffer.array(), buffer.arrayOffset(), buffer.position()); } } finally { - try { - body.close(); - } catch (IOException e) { - logger.warn("Failed to close request body: {}", e.getMessage(), e); - } + closeSilently(body); } } } diff --git a/src/main/java/com/ning/http/client/providers/netty/request/body/BodyFileRegion.java b/src/main/java/com/ning/http/client/providers/netty/request/body/BodyFileRegion.java index bdb73961a3..29812c407c 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/body/BodyFileRegion.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/body/BodyFileRegion.java @@ -13,6 +13,8 @@ */ package com.ning.http.client.providers.netty.request.body; +import static com.ning.http.util.MiscUtils.closeSilently; + import com.ning.http.client.RandomAccessBody; import org.jboss.netty.channel.FileRegion; @@ -22,8 +24,7 @@ /** * Adapts a {@link RandomAccessBody} to Netty's {@link FileRegion}. */ -public class BodyFileRegion - implements FileRegion { +public class BodyFileRegion implements FileRegion { private final RandomAccessBody body; @@ -47,11 +48,6 @@ public long transferTo(WritableByteChannel target, long position) } public void releaseExternalResources() { - try { - body.close(); - } catch (IOException e) { - // we tried - } + closeSilently(body); } - } diff --git a/src/main/java/com/ning/http/client/providers/netty/request/body/NettyBodyBody.java b/src/main/java/com/ning/http/client/providers/netty/request/body/NettyBodyBody.java index d074f64f62..a31ca32b1d 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/body/NettyBodyBody.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/body/NettyBodyBody.java @@ -13,11 +13,11 @@ */ package com.ning.http.client.providers.netty.request.body; +import static com.ning.http.util.MiscUtils.closeSilently; + import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.handler.stream.ChunkedWriteHandler; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.Body; @@ -34,8 +34,6 @@ public class NettyBodyBody implements NettyBody { - private static final Logger LOGGER = LoggerFactory.getLogger(NettyBodyBody.class); - private final Body body; private final NettyAsyncHttpProviderConfig nettyConfig; @@ -62,7 +60,7 @@ public String getContentType() { public void write(final Channel channel, NettyResponseFuture future, AsyncHttpClientConfig config) throws IOException { Object msg; - if (!ChannelManager.isSslHandlerConfigured(channel.getPipeline()) && body instanceof RandomAccessBody && !nettyConfig.isDisableZeroCopy()) { + if (body instanceof RandomAccessBody && !ChannelManager.isSslHandlerConfigured(channel.getPipeline()) && !nettyConfig.isDisableZeroCopy()) { msg = new BodyFileRegion((RandomAccessBody) body); } else { @@ -81,11 +79,7 @@ public void onContentAdded() { channel.write(msg).addListener(new ProgressListener(config, future.getAsyncHandler(), future, false) { public void operationComplete(ChannelFuture cf) { - try { - body.close(); - } catch (IOException e) { - LOGGER.warn("Failed to close request body: {}", e.getMessage(), e); - } + closeSilently(body); super.operationComplete(cf); } }); diff --git a/src/main/java/com/ning/http/client/providers/netty/request/body/NettyFileBody.java b/src/main/java/com/ning/http/client/providers/netty/request/body/NettyFileBody.java index c342c694c7..0e59279242 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/body/NettyFileBody.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/body/NettyFileBody.java @@ -13,12 +13,12 @@ */ package com.ning.http.client.providers.netty.request.body; +import static com.ning.http.util.MiscUtils.closeSilently; + import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.FileRegion; import org.jboss.netty.handler.stream.ChunkedFile; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.providers.netty.NettyAsyncHttpProviderConfig; @@ -32,8 +32,6 @@ public class NettyFileBody implements NettyBody { - private static final Logger LOGGER = LoggerFactory.getLogger(NettyFileBody.class); - private final File file; private final long offset; private final long length; @@ -85,21 +83,12 @@ public void write(Channel channel, NettyResponseFuture future, AsyncHttpClien } writeFuture.addListener(new ProgressListener(config, future.getAsyncHandler(), future, false) { public void operationComplete(ChannelFuture cf) { - try { - raf.close(); - } catch (IOException e) { - LOGGER.warn("Failed to close request body: {}", e.getMessage(), e); - } + closeSilently(raf); super.operationComplete(cf); } }); } catch (IOException ex) { - if (raf != null) { - try { - raf.close(); - } catch (IOException e) { - } - } + closeSilently(raf); throw ex; } } diff --git a/src/main/java/com/ning/http/client/providers/netty/request/body/NettyInputStreamBody.java b/src/main/java/com/ning/http/client/providers/netty/request/body/NettyInputStreamBody.java index eb00525a17..52ee0cbf79 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/body/NettyInputStreamBody.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/body/NettyInputStreamBody.java @@ -13,6 +13,8 @@ */ package com.ning.http.client.providers.netty.request.body; +import static com.ning.http.util.MiscUtils.closeSilently; + import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFuture; import org.slf4j.Logger; @@ -72,11 +74,7 @@ public void write(Channel channel, NettyResponseFuture future, AsyncHttpClien final Body body = generator.createBody(); channel.write(new BodyChunkedInput(body)).addListener(new ProgressListener(config, future.getAsyncHandler(), future, false) { public void operationComplete(ChannelFuture cf) { - try { - body.close(); - } catch (IOException e) { - LOGGER.warn("Failed to close request body: {}", e.getMessage(), e); - } + closeSilently(body); super.operationComplete(cf); } }); diff --git a/src/main/java/com/ning/http/client/providers/netty/request/body/OptimizedFileRegion.java b/src/main/java/com/ning/http/client/providers/netty/request/body/OptimizedFileRegion.java index c5ae973167..d929d24452 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/body/OptimizedFileRegion.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/body/OptimizedFileRegion.java @@ -13,9 +13,9 @@ */ package com.ning.http.client.providers.netty.request.body; +import static com.ning.http.util.MiscUtils.closeSilently; + import org.jboss.netty.channel.FileRegion; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import java.io.IOException; import java.io.RandomAccessFile; @@ -24,8 +24,6 @@ public class OptimizedFileRegion implements FileRegion { - private static final Logger LOGGER = LoggerFactory.getLogger(OptimizedFileRegion.class); - private final FileChannel file; private final RandomAccessFile raf; private final long position; @@ -65,16 +63,7 @@ public long transferTo(WritableByteChannel target, long position) throws IOExcep } public void releaseExternalResources() { - try { - file.close(); - } catch (IOException e) { - LOGGER.warn("Failed to close a file.", e); - } - - try { - raf.close(); - } catch (IOException e) { - LOGGER.warn("Failed to close a file.", e); - } + closeSilently(file); + closeSilently(raf); } } 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 bbf600692c..80fe979640 100644 --- a/src/main/java/com/ning/http/client/resumable/PropertiesBasedResumableProcessor.java +++ b/src/main/java/com/ning/http/client/resumable/PropertiesBasedResumableProcessor.java @@ -12,6 +12,8 @@ */ package com.ning.http.client.resumable; +import static com.ning.http.util.MiscUtils.closeSilently; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -73,12 +75,8 @@ public void save(Map map) { } catch (Throwable e) { log.warn(e.getMessage(), e); } finally { - if (os != null) { - try { - os.close(); - } catch (IOException ignored) { - } - } + if (os != null) + closeSilently(os); } } diff --git a/src/main/java/com/ning/http/util/MiscUtils.java b/src/main/java/com/ning/http/util/MiscUtils.java index f5839a0d0a..8093aa67c8 100644 --- a/src/main/java/com/ning/http/util/MiscUtils.java +++ b/src/main/java/com/ning/http/util/MiscUtils.java @@ -13,6 +13,8 @@ */ package com.ning.http.util; +import java.io.Closeable; +import java.io.IOException; import java.util.Collection; import java.util.Map; @@ -45,4 +47,11 @@ public static boolean getBoolean(String systemPropName, boolean defaultValue) { String systemPropValue = System.getProperty(systemPropName); return systemPropValue != null ? systemPropValue.equalsIgnoreCase("true") : defaultValue; } + + public static void closeSilently(Closeable closeable) { + try { + closeable.close(); + } catch (IOException e) { + } + } } From f6c94022a5db8387caa01e1990149428bdda7a65 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 29 Jul 2014 14:07:41 +0200 Subject: [PATCH 505/701] Minor clean up --- .../providers/netty/ws/NettyWebSocket.java | 53 +++++++++---------- 1 file changed, 24 insertions(+), 29 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/ws/NettyWebSocket.java b/src/main/java/com/ning/http/client/providers/netty/ws/NettyWebSocket.java index e1df876d5f..82111d6636 100644 --- a/src/main/java/com/ning/http/client/providers/netty/ws/NettyWebSocket.java +++ b/src/main/java/com/ning/http/client/providers/netty/ws/NettyWebSocket.java @@ -34,7 +34,8 @@ import static org.jboss.netty.buffer.ChannelBuffers.wrappedBuffer; public class NettyWebSocket implements WebSocket { - private final static Logger logger = LoggerFactory.getLogger(NettyWebSocket.class); + + private static final Logger LOGGER = LoggerFactory.getLogger(NettyWebSocket.class); private final Channel channel; private final ConcurrentLinkedQueue listeners = new ConcurrentLinkedQueue(); @@ -142,29 +143,28 @@ public void onBinaryFragment(byte[] message, boolean last) { if (byteBuffer.size() > maxBufferSize) { byteBuffer.reset(); - Exception e = new Exception("Exceeded Netty Web Socket maximum buffer size of " + getMaxBufferSize()); + Exception e = new Exception("Exceeded Netty Web Socket maximum buffer size of " + maxBufferSize); onError(e); - this.close(); + close(); return; } } - for (WebSocketListener l : listeners) { - if (l instanceof WebSocketByteListener) { + for (WebSocketListener listener : listeners) { + if (listener instanceof WebSocketByteListener) { + WebSocketByteListener byteListener = (WebSocketByteListener) listener; try { if (!last) { - WebSocketByteListener.class.cast(l).onFragment(message, last); + byteListener.onFragment(message, last); + } else if (byteBuffer.size() > 0) { + byteBuffer.write(message); + byteListener.onFragment(message, last); + byteListener.onMessage(byteBuffer.toByteArray()); } else { - if (byteBuffer.size() > 0) { - byteBuffer.write(message); - WebSocketByteListener.class.cast(l).onFragment(message, last); - WebSocketByteListener.class.cast(l).onMessage(byteBuffer.toByteArray()); - } else { - WebSocketByteListener.class.cast(l).onMessage(message); - } + byteListener.onMessage(message); } } catch (Exception ex) { - l.onError(ex); + listener.onError(ex); } } } @@ -181,9 +181,9 @@ public void onTextFragment(String message, boolean last) { if (textBuffer.length() > maxBufferSize) { textBuffer.setLength(0); - Exception e = new Exception("Exceeded Netty Web Socket maximum buffer size of " + getMaxBufferSize()); + Exception e = new Exception("Exceeded Netty Web Socket maximum buffer size of " + maxBufferSize); onError(e); - this.close(); + close(); return; } } @@ -194,13 +194,11 @@ public void onTextFragment(String message, boolean last) { try { if (!last) { textlistener.onFragment(message, last); + } else if (textBuffer.length() > 0) { + textlistener.onFragment(message, last); + textlistener.onMessage(textBuffer.append(message).toString()); } else { - if (textBuffer.length() > 0) { - textlistener.onFragment(message, last); - textlistener.onMessage(textBuffer.append(message).toString()); - } else { - textlistener.onMessage(message); - } + textlistener.onMessage(message); } } catch (Exception ex) { listener.onError(ex); @@ -214,13 +212,12 @@ public void onTextFragment(String message, boolean last) { } public void onError(Throwable t) { - for (WebSocketListener l : listeners) { + for (WebSocketListener listener : listeners) { try { - l.onError(t); + listener.onError(t); } catch (Throwable t2) { - logger.error("", t2); + LOGGER.error("", t2); } - } } @@ -243,8 +240,6 @@ public void onClose(int code, String reason) { @Override public String toString() { - return "NettyWebSocket{" + - "channel=" + channel + - '}'; + return "NettyWebSocket{channel=" + channel + '}'; } } From 8daab9e1f508933e789cc91ce42fa56b03e0c79d Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 29 Jul 2014 14:19:23 +0200 Subject: [PATCH 506/701] minor clean up --- .../providers/netty/ws/NettyWebSocket.java | 7 +- .../websocket/WebSocketUpgradeHandler.java | 81 +++++-------------- 2 files changed, 22 insertions(+), 66 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/ws/NettyWebSocket.java b/src/main/java/com/ning/http/client/providers/netty/ws/NettyWebSocket.java index 82111d6636..512f0b01b1 100644 --- a/src/main/java/com/ning/http/client/providers/netty/ws/NettyWebSocket.java +++ b/src/main/java/com/ning/http/client/providers/netty/ws/NettyWebSocket.java @@ -104,11 +104,8 @@ public int getMaxBufferSize() { return maxBufferSize; } - public void setMaxBufferSize(int bufferSize) { - maxBufferSize = bufferSize; - - if(maxBufferSize < 8192) - maxBufferSize = 8192; + public void setMaxBufferSize(int maxBufferSize) { + this.maxBufferSize = Math.max(maxBufferSize, 8192); } @Override 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 25bb6c6b13..ccd58dc599 100644 --- a/src/main/java/com/ning/http/client/websocket/WebSocketUpgradeHandler.java +++ b/src/main/java/com/ning/http/client/websocket/WebSocketUpgradeHandler.java @@ -27,20 +27,13 @@ public class WebSocketUpgradeHandler implements UpgradeHandler, AsyncHandler { private WebSocket webSocket; - private final ConcurrentLinkedQueue l; - // FIXME use? - private final String protocol; - private final long maxByteSize; - private final long maxTextSize; + private final ConcurrentLinkedQueue listeners; private final AtomicBoolean ok = new AtomicBoolean(false); private final AtomicBoolean onSuccessCalled = new AtomicBoolean(false); private int status; - protected WebSocketUpgradeHandler(Builder b) { - l = b.l; - protocol = b.protocol; - maxByteSize = b.maxByteSize; - maxTextSize = b.maxTextSize; + protected WebSocketUpgradeHandler(ConcurrentLinkedQueue listeners) { + this.listeners = listeners; } @Override @@ -80,8 +73,9 @@ public STATE onHeadersReceived(HttpResponseHeaders headers) throws Exception { public WebSocket onCompleted() throws Exception { if (status != 101) { - for (WebSocketListener w : l) { - w.onError(new IllegalStateException(String.format("Invalid Status Code %d", status))); + IllegalStateException e = new IllegalStateException("Invalid Status Code " + status); + for (WebSocketListener listener : listeners) { + listener.onError(e); } return null; } @@ -95,16 +89,16 @@ public WebSocket onCompleted() throws Exception { @Override public void onSuccess(WebSocket webSocket) { this.webSocket = webSocket; - for (WebSocketListener w : l) { - webSocket.addWebSocketListener(w); - w.onOpen(webSocket); + for (WebSocketListener listener : listeners) { + webSocket.addWebSocketListener(listener); + listener.onOpen(webSocket); } ok.set(true); } @Override public void onFailure(Throwable t) { - for (WebSocketListener w : l) { + for (WebSocketListener w : listeners) { if (!ok.get() && webSocket != null) { webSocket.addWebSocketListener(w); } @@ -116,13 +110,13 @@ public void onClose(WebSocket webSocket, int status, String reasonPhrase) { // Connect failure if (this.webSocket == null) this.webSocket = webSocket; - for (WebSocketListener w : l) { + for (WebSocketListener listener : listeners) { if (webSocket != null) { - webSocket.addWebSocketListener(w); + webSocket.addWebSocketListener(listener); } - w.onClose(webSocket); - if (w instanceof WebSocketCloseCodeReasonListener) { - WebSocketCloseCodeReasonListener.class.cast(w).onClose(webSocket, status, reasonPhrase); + listener.onClose(webSocket); + if (listener instanceof WebSocketCloseCodeReasonListener) { + WebSocketCloseCodeReasonListener.class.cast(listener).onClose(webSocket, status, reasonPhrase); } } } @@ -131,10 +125,8 @@ public void onClose(WebSocket webSocket, int status, String reasonPhrase) { * Build a {@link WebSocketUpgradeHandler} */ public final static class Builder { - private ConcurrentLinkedQueue l = new ConcurrentLinkedQueue(); - private String protocol = ""; - private long maxByteSize = 8192; - private long maxTextSize = 8192; + + private ConcurrentLinkedQueue listeners = new ConcurrentLinkedQueue(); /** * Add a {@link WebSocketListener} that will be added to the {@link WebSocket} @@ -143,7 +135,7 @@ public final static class Builder { * @return this */ public Builder addWebSocketListener(WebSocketListener listener) { - l.add(listener); + listeners.add(listener); return this; } @@ -154,40 +146,7 @@ public Builder addWebSocketListener(WebSocketListener listener) { * @return this */ public Builder removeWebSocketListener(WebSocketListener listener) { - l.remove(listener); - return this; - } - - /** - * Set the WebSocket protocol. - * - * @param protocol the WebSocket protocol. - * @return this - */ - public Builder setProtocol(String protocol) { - this.protocol = protocol; - return this; - } - - /** - * Set the max size of the WebSocket byte message that will be sent. - * - * @param maxByteSize max size of the WebSocket byte message - * @return this - */ - public Builder setMaxByteSize(long maxByteSize) { - this.maxByteSize = maxByteSize; - return this; - } - - /** - * Set the max size of the WebSocket text message that will be sent. - * - * @param maxTextSize max size of the WebSocket byte message - * @return this - */ - public Builder setMaxTextSize(long maxTextSize) { - this.maxTextSize = maxTextSize; + listeners.remove(listener); return this; } @@ -197,7 +156,7 @@ public Builder setMaxTextSize(long maxTextSize) { * @return a {@link WebSocketUpgradeHandler} */ public WebSocketUpgradeHandler build() { - return new WebSocketUpgradeHandler(this); + return new WebSocketUpgradeHandler(listeners); } } } From 557c765809da773975372e7f864932f4e50907b2 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 29 Jul 2014 14:42:12 +0200 Subject: [PATCH 507/701] WebSocketUpgradeHandler doesn't need to be threadsafe --- .../http/client/websocket/WebSocketUpgradeHandler.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 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 ccd58dc599..168977047e 100644 --- a/src/main/java/com/ning/http/client/websocket/WebSocketUpgradeHandler.java +++ b/src/main/java/com/ning/http/client/websocket/WebSocketUpgradeHandler.java @@ -18,7 +18,8 @@ import com.ning.http.client.HttpResponseStatus; import com.ning.http.client.UpgradeHandler; -import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.ArrayList; +import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; /** @@ -27,12 +28,12 @@ public class WebSocketUpgradeHandler implements UpgradeHandler, AsyncHandler { private WebSocket webSocket; - private final ConcurrentLinkedQueue listeners; + private final List listeners; private final AtomicBoolean ok = new AtomicBoolean(false); private final AtomicBoolean onSuccessCalled = new AtomicBoolean(false); private int status; - protected WebSocketUpgradeHandler(ConcurrentLinkedQueue listeners) { + protected WebSocketUpgradeHandler(List listeners) { this.listeners = listeners; } @@ -126,7 +127,7 @@ public void onClose(WebSocket webSocket, int status, String reasonPhrase) { */ public final static class Builder { - private ConcurrentLinkedQueue listeners = new ConcurrentLinkedQueue(); + private List listeners = new ArrayList(1); /** * Add a {@link WebSocketListener} that will be added to the {@link WebSocket} From 11b91731b3978f3c8fc86eb2b1a67016c518252b Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 30 Jul 2014 00:03:51 +0200 Subject: [PATCH 508/701] minor clean up --- .../websocket/WebSocketUpgradeHandler.java | 16 +++++----------- 1 file changed, 5 insertions(+), 11 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 168977047e..fbd18baec7 100644 --- a/src/main/java/com/ning/http/client/websocket/WebSocketUpgradeHandler.java +++ b/src/main/java/com/ning/http/client/websocket/WebSocketUpgradeHandler.java @@ -30,7 +30,7 @@ public class WebSocketUpgradeHandler implements UpgradeHandler, Async private WebSocket webSocket; private final List listeners; private final AtomicBoolean ok = new AtomicBoolean(false); - private final AtomicBoolean onSuccessCalled = new AtomicBoolean(false); + private boolean onSuccessCalled; private int status; protected WebSocketUpgradeHandler(List listeners) { @@ -43,11 +43,9 @@ public void onThrowable(Throwable t) { } public boolean touchSuccess() { - return onSuccessCalled.getAndSet(true); - } - - public void resetSuccess() { - onSuccessCalled.set(false); + boolean prev = onSuccessCalled; + onSuccessCalled = true; + return prev; } @Override @@ -58,11 +56,7 @@ public STATE onBodyPartReceived(HttpResponseBodyPart bodyPart) throws Exception @Override public STATE onStatusReceived(HttpResponseStatus responseStatus) throws Exception { status = responseStatus.getStatusCode(); - if (responseStatus.getStatusCode() == 101) { - return STATE.UPGRADE; - } else { - return STATE.ABORT; - } + return status == 101 ? STATE.UPGRADE : STATE.ABORT; } @Override From d7060cab8a1af4c4e6b5aeb79a37507d59031b8c Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 30 Jul 2014 01:57:47 +0200 Subject: [PATCH 509/701] Turn NettyWebSocket into an abstract class and introduce a Factory, close #656 --- .../netty/NettyAsyncHttpProviderConfig.java | 33 ++++- .../netty/handler/WebSocketProtocol.java | 7 +- .../netty/ws/DefaultNettyWebSocket.java | 123 ++++++++++++++++++ .../providers/netty/ws/NettyWebSocket.java | 115 +++------------- 4 files changed, 172 insertions(+), 106 deletions(-) create mode 100644 src/main/java/com/ning/http/client/providers/netty/ws/DefaultNettyWebSocket.java 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 20d6497094..848ea1fcba 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 @@ -13,12 +13,15 @@ */ package com.ning.http.client.providers.netty; +import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory; import org.jboss.netty.util.Timer; import com.ning.http.client.AsyncHttpProviderConfig; import com.ning.http.client.SSLEngineFactory; import com.ning.http.client.providers.netty.channel.pool.ChannelPool; +import com.ning.http.client.providers.netty.ws.DefaultNettyWebSocket; +import com.ning.http.client.providers.netty.ws.NettyWebSocket; import java.util.Map; import java.util.Set; @@ -120,7 +123,7 @@ public Set> propertiesSet() { private Timer nettyTimer; - private long handshakeTimeoutInMillis = 10000L; + private long handshakeTimeout = 10000L; private SSLEngineFactory sslEngineFactory; @@ -129,6 +132,8 @@ public Set> propertiesSet() { */ private int chunkedFileChunkSize = 8192; + private NettyWebSocketFactory nettyWebSocketFactory = new DefaultNettyWebSocketFactory(); + public boolean isUseDeadLockChecker() { return useDeadLockChecker; } @@ -194,11 +199,11 @@ public void setNettyTimer(Timer nettyTimer) { } public long getHandshakeTimeout() { - return handshakeTimeoutInMillis; + return handshakeTimeout; } - public void setHandshakeTimeoutInMillis(long handshakeTimeoutInMillis) { - this.handshakeTimeoutInMillis = handshakeTimeoutInMillis; + public void setHandshakeTimeout(long handshakeTimeout) { + this.handshakeTimeout = handshakeTimeout; } public ChannelPool getChannelPool() { @@ -224,4 +229,24 @@ public int getChunkedFileChunkSize() { public void setChunkedFileChunkSize(int chunkedFileChunkSize) { this.chunkedFileChunkSize = chunkedFileChunkSize; } + + public NettyWebSocketFactory getNettyWebSocketFactory() { + return nettyWebSocketFactory; + } + + public void setNettyWebSocketFactory(NettyWebSocketFactory nettyWebSocketFactory) { + this.nettyWebSocketFactory = nettyWebSocketFactory; + } + + public static interface NettyWebSocketFactory { + NettyWebSocket newNettyWebSocket(Channel channel); + } + + public class DefaultNettyWebSocketFactory implements NettyWebSocketFactory { + + @Override + public NettyWebSocket newNettyWebSocket(Channel channel) { + return new DefaultNettyWebSocket(channel); + } + } } diff --git a/src/main/java/com/ning/http/client/providers/netty/handler/WebSocketProtocol.java b/src/main/java/com/ning/http/client/providers/netty/handler/WebSocketProtocol.java index 8790fae39d..2059311ed0 100644 --- a/src/main/java/com/ning/http/client/providers/netty/handler/WebSocketProtocol.java +++ b/src/main/java/com/ning/http/client/providers/netty/handler/WebSocketProtocol.java @@ -41,7 +41,6 @@ import com.ning.http.client.providers.netty.response.NettyResponseStatus; import com.ning.http.client.providers.netty.ws.NettyWebSocket; import com.ning.http.client.websocket.WebSocketUpgradeHandler; -import com.ning.http.util.StandardCharsets; import java.io.IOException; import java.util.Locale; @@ -60,7 +59,7 @@ public WebSocketProtocol(ChannelManager channelManager,// private void invokeOnSucces(Channel channel, WebSocketUpgradeHandler h) { if (!h.touchSuccess()) { try { - h.onSuccess(new NettyWebSocket(channel)); + h.onSuccess(nettyConfig.getNettyWebSocketFactory().newNettyWebSocket(channel)); } catch (Exception ex) { logger.warn("onSuccess unexpected exception", ex); } @@ -157,9 +156,9 @@ public void setContent(ChannelBuffer content) { handler.onBodyPartReceived(rp); if (frame instanceof BinaryWebSocketFrame) { - webSocket.onBinaryFragment(rp.getBodyPartBytes(), frame.isFinalFragment()); + webSocket.onBinaryFragment(rp); } else { - webSocket.onTextFragment(frame.getBinaryData().toString(StandardCharsets.UTF_8), frame.isFinalFragment()); + webSocket.onTextFragment(rp); } } } else { diff --git a/src/main/java/com/ning/http/client/providers/netty/ws/DefaultNettyWebSocket.java b/src/main/java/com/ning/http/client/providers/netty/ws/DefaultNettyWebSocket.java new file mode 100644 index 0000000000..6a8a954c06 --- /dev/null +++ b/src/main/java/com/ning/http/client/providers/netty/ws/DefaultNettyWebSocket.java @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2014 AsyncHttpClient Project. 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.providers.netty.ws; + +import org.jboss.netty.channel.Channel; + +import com.ning.http.client.HttpResponseBodyPart; +import com.ning.http.client.websocket.WebSocketByteListener; +import com.ning.http.client.websocket.WebSocketListener; +import com.ning.http.client.websocket.WebSocketTextListener; +import com.ning.http.util.StandardCharsets; + +import java.io.ByteArrayOutputStream; +import java.util.concurrent.ConcurrentLinkedQueue; + +public class DefaultNettyWebSocket extends NettyWebSocket { + + private final StringBuilder textBuffer = new StringBuilder(); + private final ByteArrayOutputStream byteBuffer = new ByteArrayOutputStream(); + + public DefaultNettyWebSocket(Channel channel) { + super(channel, new ConcurrentLinkedQueue()); + } + + public void onBinaryFragment(HttpResponseBodyPart part) { + + boolean last = part.isLast(); + byte[] message = part.getBodyPartBytes(); + + if (!last) { + try { + byteBuffer.write(message); + } catch (Exception ex) { + byteBuffer.reset(); + onError(ex); + return; + } + + if (byteBuffer.size() > maxBufferSize) { + byteBuffer.reset(); + Exception e = new Exception("Exceeded Netty Web Socket maximum buffer size of " + maxBufferSize); + onError(e); + close(); + return; + } + } + + for (WebSocketListener listener : listeners) { + if (listener instanceof WebSocketByteListener) { + WebSocketByteListener byteListener = (WebSocketByteListener) listener; + try { + if (!last) { + byteListener.onFragment(message, last); + } else if (byteBuffer.size() > 0) { + byteBuffer.write(message); + byteListener.onFragment(message, last); + byteListener.onMessage(byteBuffer.toByteArray()); + } else { + byteListener.onMessage(message); + } + } catch (Exception ex) { + listener.onError(ex); + } + } + } + + if (last) { + byteBuffer.reset(); + } + } + + public void onTextFragment(HttpResponseBodyPart part) { + + boolean last = part.isLast(); + // FIXME this is so wrong! there's a chance the fragment is not valid UTF-8 because a char is truncated + String message = new String(part.getBodyPartBytes(), StandardCharsets.UTF_8); + + if (!last) { + textBuffer.append(message); + + if (textBuffer.length() > maxBufferSize) { + textBuffer.setLength(0); + Exception e = new Exception("Exceeded Netty Web Socket maximum buffer size of " + maxBufferSize); + onError(e); + close(); + return; + } + } + + for (WebSocketListener listener : listeners) { + if (listener instanceof WebSocketTextListener) { + WebSocketTextListener textlistener = (WebSocketTextListener) listener; + try { + if (!last) { + textlistener.onFragment(message, last); + } else if (textBuffer.length() > 0) { + textlistener.onFragment(message, last); + textlistener.onMessage(textBuffer.append(message).toString()); + } else { + textlistener.onMessage(message); + } + } catch (Exception ex) { + listener.onError(ex); + } + } + } + + if (last) { + textBuffer.setLength(0); + } + } +} diff --git a/src/main/java/com/ning/http/client/providers/netty/ws/NettyWebSocket.java b/src/main/java/com/ning/http/client/providers/netty/ws/NettyWebSocket.java index 512f0b01b1..960104eea3 100644 --- a/src/main/java/com/ning/http/client/providers/netty/ws/NettyWebSocket.java +++ b/src/main/java/com/ning/http/client/providers/netty/ws/NettyWebSocket.java @@ -13,11 +13,8 @@ */ package com.ning.http.client.providers.netty.ws; -import com.ning.http.client.websocket.WebSocket; -import com.ning.http.client.websocket.WebSocketByteListener; -import com.ning.http.client.websocket.WebSocketCloseCodeReasonListener; -import com.ning.http.client.websocket.WebSocketListener; -import com.ning.http.client.websocket.WebSocketTextListener; +import static org.jboss.netty.buffer.ChannelBuffers.wrappedBuffer; + import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFutureListener; import org.jboss.netty.handler.codec.http.websocketx.BinaryWebSocketFrame; @@ -28,25 +25,24 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.ByteArrayOutputStream; -import java.util.concurrent.ConcurrentLinkedQueue; +import com.ning.http.client.HttpResponseBodyPart; +import com.ning.http.client.websocket.WebSocket; +import com.ning.http.client.websocket.WebSocketCloseCodeReasonListener; +import com.ning.http.client.websocket.WebSocketListener; -import static org.jboss.netty.buffer.ChannelBuffers.wrappedBuffer; +import java.util.Collection; -public class NettyWebSocket implements WebSocket { +public abstract class NettyWebSocket implements WebSocket { private static final Logger LOGGER = LoggerFactory.getLogger(NettyWebSocket.class); - private final Channel channel; - private final ConcurrentLinkedQueue listeners = new ConcurrentLinkedQueue(); - - private final StringBuilder textBuffer = new StringBuilder(); - private final ByteArrayOutputStream byteBuffer = new ByteArrayOutputStream(); - - private int maxBufferSize = 128000000; + protected final Channel channel; + protected final Collection listeners; + protected int maxBufferSize = 128000000; - public NettyWebSocket(Channel channel) { + public NettyWebSocket(Channel channel, Collection listeners) { this.channel = channel; + this.listeners = listeners; } @Override @@ -127,87 +123,6 @@ public void close(int statusCode, String reason) { listeners.clear(); } - public void onBinaryFragment(byte[] message, boolean last) { - - if (!last) { - try { - byteBuffer.write(message); - } catch (Exception ex) { - byteBuffer.reset(); - onError(ex); - return; - } - - if (byteBuffer.size() > maxBufferSize) { - byteBuffer.reset(); - Exception e = new Exception("Exceeded Netty Web Socket maximum buffer size of " + maxBufferSize); - onError(e); - close(); - return; - } - } - - for (WebSocketListener listener : listeners) { - if (listener instanceof WebSocketByteListener) { - WebSocketByteListener byteListener = (WebSocketByteListener) listener; - try { - if (!last) { - byteListener.onFragment(message, last); - } else if (byteBuffer.size() > 0) { - byteBuffer.write(message); - byteListener.onFragment(message, last); - byteListener.onMessage(byteBuffer.toByteArray()); - } else { - byteListener.onMessage(message); - } - } catch (Exception ex) { - listener.onError(ex); - } - } - } - - if (last) { - byteBuffer.reset(); - } - } - - public void onTextFragment(String message, boolean last) { - - if (!last) { - textBuffer.append(message); - - if (textBuffer.length() > maxBufferSize) { - textBuffer.setLength(0); - Exception e = new Exception("Exceeded Netty Web Socket maximum buffer size of " + maxBufferSize); - onError(e); - close(); - return; - } - } - - for (WebSocketListener listener : listeners) { - if (listener instanceof WebSocketTextListener) { - WebSocketTextListener textlistener = (WebSocketTextListener) listener; - try { - if (!last) { - textlistener.onFragment(message, last); - } else if (textBuffer.length() > 0) { - textlistener.onFragment(message, last); - textlistener.onMessage(textBuffer.append(message).toString()); - } else { - textlistener.onMessage(message); - } - } catch (Exception ex) { - listener.onError(ex); - } - } - } - - if (last) { - textBuffer.setLength(0); - } - } - public void onError(Throwable t) { for (WebSocketListener listener : listeners) { try { @@ -239,4 +154,8 @@ public void onClose(int code, String reason) { public String toString() { return "NettyWebSocket{channel=" + channel + '}'; } + + public abstract void onBinaryFragment(HttpResponseBodyPart part); + + public abstract void onTextFragment(HttpResponseBodyPart part); } From e2eca0b8967b0e119d1b22d738b91fc3eaeca346 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 30 Jul 2014 11:20:36 +0200 Subject: [PATCH 510/701] Ensured Netty provider uses CONNECT when proxying ws, port #657 on 1.9 --- .../http/client/AsyncHttpClientConfig.java | 30 +++---- .../client/AsyncHttpClientConfigBean.java | 2 +- .../client/AsyncHttpClientConfigDefaults.java | 4 +- .../grizzly/GrizzlyAsyncHttpProvider.java | 2 +- .../netty/request/NettyRequestFactory.java | 2 +- .../netty/request/NettyRequestSender.java | 3 +- .../providers/netty/util/HttpUtils.java | 4 + .../client/websocket/ProxyTunnellingTest.java | 88 +++++++++++-------- 8 files changed, 79 insertions(+), 56 deletions(-) diff --git a/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java b/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java index 76c1c82643..68f5a09198 100644 --- a/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java @@ -66,7 +66,7 @@ public class AsyncHttpClientConfig { protected boolean strict302Handling; protected ProxyServerSelector proxyServerSelector; - protected boolean useRelativeURIsWithSSLProxies; + protected boolean useRelativeURIsWithConnectProxies; protected boolean compressionEnabled; protected String userAgent; @@ -103,7 +103,7 @@ private AsyncHttpClientConfig(int connectionTimeout,// boolean strict302Handling, // ExecutorService applicationThreadPool,// ProxyServerSelector proxyServerSelector, // - boolean useRelativeURIsWithSSLProxies, // + boolean useRelativeURIsWithConnectProxies, // boolean compressionEnabled, // String userAgent,// Realm realm,// @@ -134,7 +134,7 @@ private AsyncHttpClientConfig(int connectionTimeout,// this.removeQueryParamOnRedirect = removeQueryParamOnRedirect; this.strict302Handling = strict302Handling; this.proxyServerSelector = proxyServerSelector; - this.useRelativeURIsWithSSLProxies = useRelativeURIsWithSSLProxies; + this.useRelativeURIsWithConnectProxies = useRelativeURIsWithConnectProxies; this.compressionEnabled = compressionEnabled; this.userAgent = userAgent; this.applicationThreadPool = applicationThreadPool == null ? Executors.newCachedThreadPool() : applicationThreadPool; @@ -417,13 +417,13 @@ public boolean isStrict302Handling() { } /** - * @returntrue if AHC should use relative URIs instead of absolute ones when talking with a SSL proxy, - * otherwise false. + * @returntrue if AHC should use relative URIs instead of absolute ones when talking with a SSL proxy + * or WebSocket proxy, otherwise false. * - * @since 1.7.12 + * @since 1.8.13 */ - public boolean isUseRelativeURIsWithSSLProxies() { - return useRelativeURIsWithSSLProxies; + public boolean isUseRelativeURIsWithConnectProxies() { + return useRelativeURIsWithConnectProxies; } /** @@ -473,7 +473,7 @@ public static class Builder { private ProxyServerSelector proxyServerSelector = null; private boolean useProxySelector = defaultUseProxySelector(); private boolean useProxyProperties = defaultUseProxyProperties(); - private boolean useRelativeURIsWithSSLProxies = defaultUseRelativeURIsWithSSLProxies(); + private boolean useRelativeURIsWithConnectProxies = defaultUseRelativeURIsWithConnectProxies(); private boolean compressionEnabled = defaultCompressionEnabled(); private String userAgent = defaultUserAgent(); private ExecutorService applicationThreadPool; @@ -870,15 +870,15 @@ public Builder setStrict302Handling(final boolean strict302Handling) { } /** - * Configures this AHC instance to use relative URIs instead of absolute ones when talking with a SSL proxy. + * Configures this AHC instance to use relative URIs instead of absolute ones when talking with a SSL proxy or WebSocket proxy. * - * @param useRelativeURIsWithSSLProxies + * @param useRelativeURIsWithConnectProxies * @return this * - * @since 1.7.2 + * @since 1.8.13 */ - public Builder setUseRelativeURIsWithSSLProxies(boolean useRelativeURIsWithSSLProxies) { - this.useRelativeURIsWithSSLProxies = useRelativeURIsWithSSLProxies; + public Builder setUseRelativeURIsWithConnectProxies(boolean useRelativeURIsWithConnectProxies) { + this.useRelativeURIsWithConnectProxies = useRelativeURIsWithConnectProxies; return this; } @@ -995,7 +995,7 @@ else if (hostnameVerifier == null) strict302Handling, // applicationThreadPool, // proxyServerSelector, // - useRelativeURIsWithSSLProxies, // + useRelativeURIsWithConnectProxies, // compressionEnabled, // userAgent,// realm,// diff --git a/src/main/java/com/ning/http/client/AsyncHttpClientConfigBean.java b/src/main/java/com/ning/http/client/AsyncHttpClientConfigBean.java index 7d43520df5..35743b730e 100644 --- a/src/main/java/com/ning/http/client/AsyncHttpClientConfigBean.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClientConfigBean.java @@ -58,7 +58,7 @@ void configureDefaults() { compressionEnabled = defaultCompressionEnabled(); userAgent = defaultUserAgent(); allowPoolingConnections = defaultAllowPoolingConnections(); - useRelativeURIsWithSSLProxies = defaultUseRelativeURIsWithSSLProxies(); + useRelativeURIsWithConnectProxies = defaultUseRelativeURIsWithConnectProxies(); maxRequestRetry = defaultMaxRequestRetry(); ioThreadMultiplier = defaultIoThreadMultiplier(); allowPoolingSslConnections = defaultAllowPoolingSslConnections(); diff --git a/src/main/java/com/ning/http/client/AsyncHttpClientConfigDefaults.java b/src/main/java/com/ning/http/client/AsyncHttpClientConfigDefaults.java index 121792490e..1be6159cc1 100644 --- a/src/main/java/com/ning/http/client/AsyncHttpClientConfigDefaults.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClientConfigDefaults.java @@ -89,8 +89,8 @@ public static boolean defaultAllowPoolingConnections() { return getBoolean(ASYNC_CLIENT + "allowPoolingConnections", true); } - public static boolean defaultUseRelativeURIsWithSSLProxies() { - return getBoolean(ASYNC_CLIENT + "useRelativeURIsWithSSLProxies", true); + public static boolean defaultUseRelativeURIsWithConnectProxies() { + return getBoolean(ASYNC_CLIENT + "useRelativeURIsWithConnectProxies", true); } public static int defaultMaxRequestRetry() { 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 0012b1773b..cb083a254d 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 @@ -871,7 +871,7 @@ private boolean sendAsGrizzlyRequest(final Request request, httpCtx.establishingTunnel = true; builder.method(Method.CONNECT); builder.uri(AsyncHttpProviderUtils.getAuthority(uri)); - } else if (secure && config.isUseRelativeURIsWithSSLProxies()){ + } else if ((secure || httpCtx.isWSRequest) && config.isUseRelativeURIsWithConnectProxies()){ builder.uri(getNonEmptyPath(uri)); } else { builder.uri(uri.toUrl()); diff --git a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestFactory.java b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestFactory.java index 7ed0e0c16a..83bba90f00 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestFactory.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestFactory.java @@ -69,7 +69,7 @@ private String requestUri(UriComponents uri, ProxyServer proxyServer, HttpMethod if (method == HttpMethod.CONNECT) return getAuthority(uri); - else if (proxyServer != null && !(isSecure(uri) && config.isUseRelativeURIsWithSSLProxies())) + else if (proxyServer != null && !(useProxyConnect(uri) && config.isUseRelativeURIsWithConnectProxies())) return uri.toString(); else { diff --git a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java index 6132217325..54859f438e 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java @@ -14,6 +14,7 @@ import static com.ning.http.client.providers.netty.util.HttpUtils.WEBSOCKET; import static com.ning.http.client.providers.netty.util.HttpUtils.isSecure; +import static com.ning.http.client.providers.netty.util.HttpUtils.useProxyConnect; import static com.ning.http.util.AsyncHttpProviderUtils.getDefaultPort; import static com.ning.http.util.AsyncHttpProviderUtils.requestTimeout; import static com.ning.http.util.ProxyUtils.avoidProxy; @@ -103,7 +104,7 @@ public ListenableFuture sendRequest(final Request request,// && future.getNettyRequest().getHttpRequest().getMethod() == HttpMethod.CONNECT; boolean useProxy = proxyServer != null && !resultOfAConnect; - if (useProxy && isSecure(uri)) + if (useProxy && useProxyConnect(uri)) // SSL proxy, have to handle CONNECT if (future != null && future.isConnectAllowed()) // CONNECT forced diff --git a/src/main/java/com/ning/http/client/providers/netty/util/HttpUtils.java b/src/main/java/com/ning/http/client/providers/netty/util/HttpUtils.java index ec9ff1c0a9..663be5c39f 100644 --- a/src/main/java/com/ning/http/client/providers/netty/util/HttpUtils.java +++ b/src/main/java/com/ning/http/client/providers/netty/util/HttpUtils.java @@ -58,4 +58,8 @@ public static boolean isSecure(String scheme) { public static boolean isSecure(UriComponents uri) { return isSecure(uri.getScheme()); } + + public static boolean useProxyConnect(UriComponents uri) { + return isSecure(uri) || isWebSocket(uri.getScheme()); + } } diff --git a/src/test/java/com/ning/http/client/websocket/ProxyTunnellingTest.java b/src/test/java/com/ning/http/client/websocket/ProxyTunnellingTest.java index 79906e20fa..a83129ba61 100644 --- a/src/test/java/com/ning/http/client/websocket/ProxyTunnellingTest.java +++ b/src/test/java/com/ning/http/client/websocket/ProxyTunnellingTest.java @@ -14,20 +14,12 @@ import static org.testng.Assert.assertEquals; -import java.io.File; -import java.net.URL; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.atomic.AtomicReference; - -import javax.servlet.http.HttpServletRequest; - import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.handler.ConnectHandler; import org.eclipse.jetty.server.nio.SelectChannelConnector; import org.eclipse.jetty.server.ssl.SslSelectChannelConnector; -import org.testng.annotations.AfterClass; -import org.testng.annotations.BeforeClass; +import org.testng.annotations.AfterMethod; import org.testng.annotations.Test; import com.ning.http.client.AsyncHttpClient; @@ -35,6 +27,13 @@ import com.ning.http.client.ProxyServer; import com.ning.http.client.websocket.TextMessageTest.EchoTextWebSocket; +import javax.servlet.http.HttpServletRequest; + +import java.io.File; +import java.net.URL; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicReference; + /** * Proxy usage tests. */ @@ -43,39 +42,46 @@ public abstract class ProxyTunnellingTest extends AbstractBasicTest { int port2; private Server server2; - @BeforeClass(alwaysRun = true) public void setUpGlobal() throws Exception { - server2 = new Server(); + } + + private void setUpServers(Connector server2Connector) throws Exception { port1 = findFreePort(); port2 = findFreePort(); - Connector listener = new SelectChannelConnector(); - listener.setHost("127.0.0.1"); listener.setPort(port1); - addConnector(listener); + setHandler(new ConnectHandler()); + start(); - SslSelectChannelConnector connector = new SslSelectChannelConnector(); - connector.setHost("127.0.0.1"); - connector.setPort(port2); + server2 = new Server(); + server2Connector.setHost("127.0.0.1"); + server2Connector.setPort(port2); + + server2.addConnector(server2Connector); + + server2.setHandler(getWebSocketHandler()); + server2.start(); + log.info("Local HTTP server started successfully"); + + } + + private void setUpServer() throws Exception { + setUpServers(new SelectChannelConnector()); + } + + private void setUpSSlServer2() throws Exception { + SslSelectChannelConnector connector = new SslSelectChannelConnector(); ClassLoader cl = getClass().getClassLoader(); URL keystoreUrl = cl.getResource("ssltest-keystore.jks"); String keyStoreFile = new File(keystoreUrl.toURI()).getAbsolutePath(); connector.setKeystore(keyStoreFile); connector.setKeyPassword("changeit"); connector.setKeystoreType("JKS"); - - server2.addConnector(connector); - - setHandler(new ConnectHandler()); - start(); - - server2.setHandler(getWebSocketHandler()); - server2.start(); - log.info("Local HTTP server started successfully"); + setUpServers(connector); } @Override @@ -88,27 +94,38 @@ public org.eclipse.jetty.websocket.WebSocket doWebSocketConnect(HttpServletReque }; } - @AfterClass(alwaysRun = true) + @AfterMethod(alwaysRun = true) public void tearDownGlobal() throws Exception { stop(); - server2.stop(); + if (server2 != null) { + server2.stop(); + } + server2 = null; } - protected String getTargetUrl() { - return String.format("wss://127.0.0.1:%d/", port2); + @Test(timeOut = 60000) + public void echoWSText() throws Exception { + setUpServer(); + runTest("ws"); } @Test(timeOut = 60000) - public void echoText() throws Exception { + public void echoWSSText() throws Exception { + setUpSSlServer2(); + runTest("wss"); + } + + private void runTest(String protocol) throws Exception { + String targetUrl = String.format("%s://127.0.0.1:%d/", protocol, port2); - ProxyServer ps = new ProxyServer(ProxyServer.Protocol.HTTPS, "127.0.0.1", port1); + ProxyServer ps = new ProxyServer(ProxyServer.Protocol.HTTP, "127.0.0.1", port1); AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder().setProxyServer(ps).setAcceptAnyCertificate(true).build(); - AsyncHttpClient client = getAsyncHttpClient(config); + AsyncHttpClient asyncHttpClient = getAsyncHttpClient(config); try { final CountDownLatch latch = new CountDownLatch(1); final AtomicReference text = new AtomicReference(""); - WebSocket websocket = client.prepareGet(getTargetUrl()).execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(new WebSocketTextListener() { + WebSocket websocket = asyncHttpClient.prepareGet(targetUrl).execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(new WebSocketTextListener() { @Override public void onMessage(String message) { @@ -141,7 +158,8 @@ public void onError(Throwable t) { latch.await(); assertEquals(text.get(), "ECHO"); } finally { - client.close(); + asyncHttpClient.close(); } + } } From a6cd7c3d2e7182f57f2e5f61d7bf0642f7a0cf04 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 30 Jul 2014 11:23:26 +0200 Subject: [PATCH 511/701] Fix log --- .../providers/netty/request/body/NettyConnectListener.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/request/body/NettyConnectListener.java b/src/main/java/com/ning/http/client/providers/netty/request/body/NettyConnectListener.java index 098da30c50..7fb637b78e 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/body/NettyConnectListener.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/body/NettyConnectListener.java @@ -72,7 +72,7 @@ private void abortChannelPreemption(String poolKey) { private void writeRequest(Channel channel, String poolKey) { - LOGGER.debug("\nNon cached request \n{}\n\nusing Channel \n{}\n", future.getNettyRequest(), channel); + LOGGER.debug("\nRequest \n{}\n\nusing non cached Channel \n{}\n", future.getNettyRequest().getHttpRequest(), channel); if (future.isDone()) { abortChannelPreemption(poolKey); From 403f48633480216330461cc3a3192bdf2ad8fc6c Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 30 Jul 2014 11:26:36 +0200 Subject: [PATCH 512/701] Better log --- .../providers/netty/request/body/NettyConnectListener.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/request/body/NettyConnectListener.java b/src/main/java/com/ning/http/client/providers/netty/request/body/NettyConnectListener.java index 7fb637b78e..051603779c 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/body/NettyConnectListener.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/body/NettyConnectListener.java @@ -72,7 +72,7 @@ private void abortChannelPreemption(String poolKey) { private void writeRequest(Channel channel, String poolKey) { - LOGGER.debug("\nRequest \n{}\n\nusing non cached Channel \n{}\n", future.getNettyRequest().getHttpRequest(), channel); + LOGGER.debug("Request using non cached Channel '{}':\n{}\n", channel, future.getNettyRequest().getHttpRequest()); if (future.isDone()) { abortChannelPreemption(poolKey); From bfe31f0fb5ae0ef943d324177efd25398fe1f6d2 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 30 Jul 2014 11:44:09 +0200 Subject: [PATCH 513/701] Clean up default user agent --- .../apache/ApacheAsyncHttpProvider.java | 2 -- .../providers/jdk/JDKAsyncHttpProvider.java | 2 -- .../netty/request/NettyRequestFactory.java | 26 +++++++++++-------- .../http/util/AsyncHttpProviderUtils.java | 9 ------- 4 files changed, 15 insertions(+), 24 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 196f4db9e0..767125f1ef 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 @@ -385,8 +385,6 @@ private HttpMethodBase createMethod(HttpClient client, Request request) throws I method.setRequestHeader("User-Agent", request.getHeaders().getFirstValue("User-Agent")); } else if (config.getUserAgent() != null) { method.setRequestHeader("User-Agent", config.getUserAgent()); - } else { - method.setRequestHeader("User-Agent", AsyncHttpProviderUtils.constructUserAgent(ApacheAsyncHttpProvider.class, config)); } if (config.isCompressionEnabled()) { 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 f1cf43e966..ccc4a97d25 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 @@ -522,8 +522,6 @@ private void configure(UriComponents uri, HttpURLConnection urlConnection, Reque urlConnection.setRequestProperty("User-Agent", request.getHeaders().getFirstValue("User-Agent")); } else if (config.getUserAgent() != null) { urlConnection.setRequestProperty("User-Agent", config.getUserAgent()); - } else { - urlConnection.setRequestProperty("User-Agent", AsyncHttpProviderUtils.constructUserAgent(JDKAsyncHttpProvider.class, config)); } if (isNonEmpty(request.getCookies())) { diff --git a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestFactory.java b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestFactory.java index 83bba90f00..620c9a6f0c 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestFactory.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestFactory.java @@ -13,6 +13,19 @@ */ package com.ning.http.client.providers.netty.request; +import static com.ning.http.client.providers.netty.util.HttpUtils.isNTLM; +import static com.ning.http.client.providers.netty.util.HttpUtils.isSecure; +import static com.ning.http.client.providers.netty.util.HttpUtils.isWebSocket; +import static com.ning.http.client.providers.netty.util.HttpUtils.useProxyConnect; +import static com.ning.http.client.providers.netty.ws.WebSocketUtils.getKey; +import static com.ning.http.util.AsyncHttpProviderUtils.DEFAULT_CHARSET; +import static com.ning.http.util.AsyncHttpProviderUtils.getAuthority; +import static com.ning.http.util.AsyncHttpProviderUtils.getNonEmptyPath; +import static com.ning.http.util.AsyncHttpProviderUtils.keepAliveHeaderValue; +import static com.ning.http.util.AuthenticatorUtils.computeBasicAuthentication; +import static com.ning.http.util.AuthenticatorUtils.computeDigestAuthentication; +import static com.ning.http.util.MiscUtils.isNonEmpty; + import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.handler.codec.http.DefaultHttpRequest; import org.jboss.netty.handler.codec.http.HttpHeaders; @@ -30,7 +43,6 @@ import com.ning.http.client.generators.InputStreamBodyGenerator; import com.ning.http.client.ntlm.NTLMEngine; import com.ning.http.client.ntlm.NTLMEngineException; -import com.ning.http.client.providers.netty.NettyAsyncHttpProvider; import com.ning.http.client.providers.netty.NettyAsyncHttpProviderConfig; import com.ning.http.client.providers.netty.request.body.NettyBody; import com.ning.http.client.providers.netty.request.body.NettyBodyBody; @@ -39,12 +51,7 @@ import com.ning.http.client.providers.netty.request.body.NettyInputStreamBody; import com.ning.http.client.providers.netty.request.body.NettyMultipartBody; import com.ning.http.client.providers.netty.spnego.SpnegoEngine; -import static com.ning.http.client.providers.netty.util.HttpUtils.*; -import static com.ning.http.client.providers.netty.ws.WebSocketUtils.*; import com.ning.http.client.uri.UriComponents; -import static com.ning.http.util.AsyncHttpProviderUtils.*; -import static com.ning.http.util.AuthenticatorUtils.*; -import static com.ning.http.util.MiscUtils.*; import com.ning.http.util.UTF8UrlEncoder; import java.io.IOException; @@ -313,11 +320,8 @@ public NettyRequest newNettyRequest(Request request, UriComponents uri, boolean httpRequest.headers().set(HttpHeaders.Names.ACCEPT, "*/*"); // Add default user agent - if (!httpRequest.headers().contains(HttpHeaders.Names.USER_AGENT)) { - String userAgent = config.getUserAgent() != null ? config.getUserAgent() : constructUserAgent(NettyAsyncHttpProvider.class, - config); - httpRequest.headers().set(HttpHeaders.Names.USER_AGENT, userAgent); - } + if (!httpRequest.headers().contains(HttpHeaders.Names.USER_AGENT) && config.getUserAgent() != null) + httpRequest.headers().set(HttpHeaders.Names.USER_AGENT, config.getUserAgent()); return nettyRequest; } diff --git a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java index 128c99ed4e..e5cbd569cc 100644 --- a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java +++ b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java @@ -15,7 +15,6 @@ import static com.ning.http.util.MiscUtils.isNonEmpty; import com.ning.http.client.AsyncHttpClientConfig; -import com.ning.http.client.AsyncHttpProvider; import com.ning.http.client.HttpResponseBodyPart; import com.ning.http.client.HttpResponseBodyPartsInputStream; import com.ning.http.client.Param; @@ -131,14 +130,6 @@ private static byte[] doubleUp(byte[] b) { return b2; } - public static String constructUserAgent(Class httpProvider, AsyncHttpClientConfig config) { - return new StringBuilder("AHC (").append(httpProvider.getSimpleName())// - .append(" - ").append(System.getProperty("os.name"))// - .append(" - ").append(System.getProperty("os.version"))// - .append(" - ").append(System.getProperty("java.version"))// - .append(" - ").append(Runtime.getRuntime().availableProcessors()).append(" core(s))").toString(); - } - public static String parseCharset(String contentType) { for (String part : contentType.split(";")) { if (part.trim().startsWith("charset=")) { From b86c5e7f184e2d731198ffa7caccbd9fbf265961 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 30 Jul 2014 11:45:06 +0200 Subject: [PATCH 514/701] This library is NOT Ning --- .../com/ning/http/client/AsyncHttpClientConfigDefaults.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/ning/http/client/AsyncHttpClientConfigDefaults.java b/src/main/java/com/ning/http/client/AsyncHttpClientConfigDefaults.java index 1be6159cc1..147c26aef7 100644 --- a/src/main/java/com/ning/http/client/AsyncHttpClientConfigDefaults.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClientConfigDefaults.java @@ -66,7 +66,7 @@ public static boolean defaultCompressionEnabled() { } public static String defaultUserAgent() { - return System.getProperty(ASYNC_CLIENT + "userAgent", "NING/1.0"); + return System.getProperty(ASYNC_CLIENT + "userAgent", "AHC/1.0"); } public static int defaultIoThreadMultiplier() { From 10ce13c253314c60fb759cf6c67f3e897bdbcfb7 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 30 Jul 2014 13:22:00 +0200 Subject: [PATCH 515/701] Extract Fragment listening concern into dedicated interfaces, close #655 --- .../grizzly/GrizzlyAsyncHttpProvider.java | 8 - .../netty/NettyAsyncHttpProviderConfig.java | 3 +- .../netty/ws/DefaultNettyWebSocket.java | 123 ------------- .../providers/netty/ws/NettyWebSocket.java | 171 ++++++++++++++++-- .../websocket/DefaultWebSocketListener.java | 10 - .../WebSocketByteFragmentListener.java | 26 +++ .../websocket/WebSocketByteListener.java | 8 - .../WebSocketTextFragmentListener.java | 26 +++ .../websocket/WebSocketTextListener.java | 8 - .../client/websocket/ByteMessageTest.java | 24 +-- .../websocket/CloseCodeReasonMessageTest.java | 8 - .../client/websocket/ProxyTunnellingTest.java | 4 - .../client/websocket/TextMessageTest.java | 28 +-- 13 files changed, 210 insertions(+), 237 deletions(-) delete mode 100644 src/main/java/com/ning/http/client/providers/netty/ws/DefaultNettyWebSocket.java create mode 100644 src/main/java/com/ning/http/client/websocket/WebSocketByteFragmentListener.java create mode 100644 src/main/java/com/ning/http/client/websocket/WebSocketTextFragmentListener.java 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 cb083a254d..73dc8aee5d 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 @@ -2859,10 +2859,6 @@ public void onFragment(org.glassfish.grizzly.websockets.WebSocket webSocket, Str } } } - } else { - if (ahcListener instanceof WebSocketTextListener) { - WebSocketTextListener.class.cast(ahcListener).onFragment(s, last); - } } } catch (Throwable e) { ahcListener.onError(e); @@ -2883,10 +2879,6 @@ public void onFragment(org.glassfish.grizzly.websockets.WebSocket webSocket, byt } } } - } else { - if (ahcListener instanceof WebSocketByteListener) { - WebSocketByteListener.class.cast(ahcListener).onFragment(bytes, last); - } } } catch (Throwable e) { ahcListener.onError(e); 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 848ea1fcba..8e2d71d6ca 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 @@ -20,7 +20,6 @@ import com.ning.http.client.AsyncHttpProviderConfig; import com.ning.http.client.SSLEngineFactory; import com.ning.http.client.providers.netty.channel.pool.ChannelPool; -import com.ning.http.client.providers.netty.ws.DefaultNettyWebSocket; import com.ning.http.client.providers.netty.ws.NettyWebSocket; import java.util.Map; @@ -246,7 +245,7 @@ public class DefaultNettyWebSocketFactory implements NettyWebSocketFactory { @Override public NettyWebSocket newNettyWebSocket(Channel channel) { - return new DefaultNettyWebSocket(channel); + return new NettyWebSocket(channel); } } } diff --git a/src/main/java/com/ning/http/client/providers/netty/ws/DefaultNettyWebSocket.java b/src/main/java/com/ning/http/client/providers/netty/ws/DefaultNettyWebSocket.java deleted file mode 100644 index 6a8a954c06..0000000000 --- a/src/main/java/com/ning/http/client/providers/netty/ws/DefaultNettyWebSocket.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (c) 2014 AsyncHttpClient Project. 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.providers.netty.ws; - -import org.jboss.netty.channel.Channel; - -import com.ning.http.client.HttpResponseBodyPart; -import com.ning.http.client.websocket.WebSocketByteListener; -import com.ning.http.client.websocket.WebSocketListener; -import com.ning.http.client.websocket.WebSocketTextListener; -import com.ning.http.util.StandardCharsets; - -import java.io.ByteArrayOutputStream; -import java.util.concurrent.ConcurrentLinkedQueue; - -public class DefaultNettyWebSocket extends NettyWebSocket { - - private final StringBuilder textBuffer = new StringBuilder(); - private final ByteArrayOutputStream byteBuffer = new ByteArrayOutputStream(); - - public DefaultNettyWebSocket(Channel channel) { - super(channel, new ConcurrentLinkedQueue()); - } - - public void onBinaryFragment(HttpResponseBodyPart part) { - - boolean last = part.isLast(); - byte[] message = part.getBodyPartBytes(); - - if (!last) { - try { - byteBuffer.write(message); - } catch (Exception ex) { - byteBuffer.reset(); - onError(ex); - return; - } - - if (byteBuffer.size() > maxBufferSize) { - byteBuffer.reset(); - Exception e = new Exception("Exceeded Netty Web Socket maximum buffer size of " + maxBufferSize); - onError(e); - close(); - return; - } - } - - for (WebSocketListener listener : listeners) { - if (listener instanceof WebSocketByteListener) { - WebSocketByteListener byteListener = (WebSocketByteListener) listener; - try { - if (!last) { - byteListener.onFragment(message, last); - } else if (byteBuffer.size() > 0) { - byteBuffer.write(message); - byteListener.onFragment(message, last); - byteListener.onMessage(byteBuffer.toByteArray()); - } else { - byteListener.onMessage(message); - } - } catch (Exception ex) { - listener.onError(ex); - } - } - } - - if (last) { - byteBuffer.reset(); - } - } - - public void onTextFragment(HttpResponseBodyPart part) { - - boolean last = part.isLast(); - // FIXME this is so wrong! there's a chance the fragment is not valid UTF-8 because a char is truncated - String message = new String(part.getBodyPartBytes(), StandardCharsets.UTF_8); - - if (!last) { - textBuffer.append(message); - - if (textBuffer.length() > maxBufferSize) { - textBuffer.setLength(0); - Exception e = new Exception("Exceeded Netty Web Socket maximum buffer size of " + maxBufferSize); - onError(e); - close(); - return; - } - } - - for (WebSocketListener listener : listeners) { - if (listener instanceof WebSocketTextListener) { - WebSocketTextListener textlistener = (WebSocketTextListener) listener; - try { - if (!last) { - textlistener.onFragment(message, last); - } else if (textBuffer.length() > 0) { - textlistener.onFragment(message, last); - textlistener.onMessage(textBuffer.append(message).toString()); - } else { - textlistener.onMessage(message); - } - } catch (Exception ex) { - listener.onError(ex); - } - } - } - - if (last) { - textBuffer.setLength(0); - } - } -} diff --git a/src/main/java/com/ning/http/client/providers/netty/ws/NettyWebSocket.java b/src/main/java/com/ning/http/client/providers/netty/ws/NettyWebSocket.java index 960104eea3..199e2434e4 100644 --- a/src/main/java/com/ning/http/client/providers/netty/ws/NettyWebSocket.java +++ b/src/main/java/com/ning/http/client/providers/netty/ws/NettyWebSocket.java @@ -13,8 +13,12 @@ */ package com.ning.http.client.providers.netty.ws; +import static com.ning.http.client.providers.netty.util.ChannelBufferUtils.channelBuffer2bytes; +import static com.ning.http.util.StandardCharsets.UTF_8; import static org.jboss.netty.buffer.ChannelBuffers.wrappedBuffer; +import org.jboss.netty.buffer.ChannelBuffer; +import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFutureListener; import org.jboss.netty.handler.codec.http.websocketx.BinaryWebSocketFrame; @@ -26,19 +30,35 @@ import org.slf4j.LoggerFactory; import com.ning.http.client.HttpResponseBodyPart; +import com.ning.http.client.providers.netty.response.NettyResponseBodyPart; import com.ning.http.client.websocket.WebSocket; +import com.ning.http.client.websocket.WebSocketByteFragmentListener; +import com.ning.http.client.websocket.WebSocketByteListener; import com.ning.http.client.websocket.WebSocketCloseCodeReasonListener; import com.ning.http.client.websocket.WebSocketListener; +import com.ning.http.client.websocket.WebSocketTextFragmentListener; +import com.ning.http.client.websocket.WebSocketTextListener; +import java.util.ArrayList; import java.util.Collection; +import java.util.List; +import java.util.concurrent.ConcurrentLinkedQueue; -public abstract class NettyWebSocket implements WebSocket { +public class NettyWebSocket implements WebSocket { private static final Logger LOGGER = LoggerFactory.getLogger(NettyWebSocket.class); protected final Channel channel; protected final Collection listeners; protected int maxBufferSize = 128000000; + private int bufferSize; + private List _fragments; + private volatile boolean interestedInByteMessages; + private volatile boolean interestedInTextMessages; + + public NettyWebSocket(Channel channel) { + this(channel, new ConcurrentLinkedQueue()); + } public NettyWebSocket(Channel channel, Collection listeners) { this.channel = channel; @@ -84,26 +104,14 @@ public WebSocket sendPong(byte[] payload) { return this; } - @Override - public WebSocket addWebSocketListener(WebSocketListener l) { - listeners.add(l); - return this; - } - - @Override - public WebSocket removeWebSocketListener(WebSocketListener l) { - listeners.remove(l); - return this; - } - public int getMaxBufferSize() { - return maxBufferSize; + return maxBufferSize; } - + public void setMaxBufferSize(int maxBufferSize) { this.maxBufferSize = Math.max(maxBufferSize, 8192); } - + @Override public boolean isOpen() { return channel.isOpen(); @@ -154,8 +162,131 @@ public void onClose(int code, String reason) { public String toString() { return "NettyWebSocket{channel=" + channel + '}'; } - - public abstract void onBinaryFragment(HttpResponseBodyPart part); - - public abstract void onTextFragment(HttpResponseBodyPart part); + + private boolean hasWebSocketByteListener() { + for (WebSocketListener listener : listeners) { + if (listener instanceof WebSocketByteListener) + return true; + } + return false; + } + + private boolean hasWebSocketTextListener() { + for (WebSocketListener listener : listeners) { + if (listener instanceof WebSocketTextListener) + return true; + } + return false; + } + + @Override + public WebSocket addWebSocketListener(WebSocketListener l) { + listeners.add(l); + if (l instanceof WebSocketByteListener) + interestedInByteMessages = true; + else if (l instanceof WebSocketTextListener) + interestedInTextMessages = true; + return this; + } + + @Override + public WebSocket removeWebSocketListener(WebSocketListener l) { + listeners.remove(l); + + if (l instanceof WebSocketByteListener) + interestedInByteMessages = hasWebSocketByteListener(); + else if (l instanceof WebSocketTextListener) + interestedInTextMessages = hasWebSocketTextListener(); + + return this; + } + + private List fragments() { + if (_fragments == null) + _fragments = new ArrayList(2); + return _fragments; + } + + private void bufferFragment(ChannelBuffer buffer) { + bufferSize += buffer.readableBytes(); + if (bufferSize > maxBufferSize) { + onError(new Exception("Exceeded Netty Web Socket maximum buffer size of " + maxBufferSize)); + reset(); + close(); + } else { + fragments().add(buffer); + } + } + + private void reset() { + fragments().clear(); + bufferSize = 0; + } + + private void notifyByteListeners(ChannelBuffer channelBuffer) { + byte[] message = channelBuffer2bytes(channelBuffer); + for (WebSocketListener listener : listeners) { + if (listener instanceof WebSocketByteListener) + WebSocketByteListener.class.cast(listener).onMessage(message); + } + } + + private void notifyTextListeners(ChannelBuffer channelBuffer) { + String message = channelBuffer.toString(UTF_8); + for (WebSocketListener listener : listeners) { + if (listener instanceof WebSocketTextListener) + WebSocketTextListener.class.cast(listener).onMessage(message); + } + } + + public void onBinaryFragment(HttpResponseBodyPart part) { + + for (WebSocketListener listener : listeners) { + if (listener instanceof WebSocketByteFragmentListener) + WebSocketByteFragmentListener.class.cast(listener).onFragment(part); + } + + if (interestedInByteMessages) { + ChannelBuffer fragment = NettyResponseBodyPart.class.cast(part).getChannelBuffer(); + + if (part.isLast()) { + if (bufferSize == 0) { + notifyByteListeners(fragment); + + } else { + bufferFragment(fragment); + notifyByteListeners(ChannelBuffers.wrappedBuffer(fragments().toArray(new ChannelBuffer[fragments().size()]))); + } + + reset(); + + } else + bufferFragment(fragment); + } + } + + public void onTextFragment(HttpResponseBodyPart part) { + for (WebSocketListener listener : listeners) { + if (listener instanceof WebSocketTextFragmentListener) + WebSocketTextFragmentListener.class.cast(listener).onFragment(part); + } + + if (interestedInTextMessages) { + ChannelBuffer fragment = NettyResponseBodyPart.class.cast(part).getChannelBuffer(); + + if (part.isLast()) { + if (bufferSize == 0) { + notifyTextListeners(fragment); + + } else { + bufferFragment(fragment); + notifyTextListeners(ChannelBuffers.wrappedBuffer(fragments().toArray(new ChannelBuffer[fragments().size()]))); + } + + reset(); + + } else + bufferFragment(fragment); + } + } } 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 19797a349a..6ed9a3d2f1 100644 --- a/src/main/java/com/ning/http/client/websocket/DefaultWebSocketListener.java +++ b/src/main/java/com/ning/http/client/websocket/DefaultWebSocketListener.java @@ -30,11 +30,6 @@ public class DefaultWebSocketListener implements WebSocketByteListener, WebSock public void onMessage(byte[] message) { } - @Override - public void onFragment(byte[] fragment, boolean last) { - } - - // -------------------------------------- Methods from WebSocketPingListener @Override @@ -55,11 +50,6 @@ public void onPong(byte[] message) { @Override public void onMessage(String message) { } - - @Override - public void onFragment(String fragment, boolean last) { - } - // ------------------------------------------ Methods from WebSocketListener diff --git a/src/main/java/com/ning/http/client/websocket/WebSocketByteFragmentListener.java b/src/main/java/com/ning/http/client/websocket/WebSocketByteFragmentListener.java new file mode 100644 index 0000000000..463094f77a --- /dev/null +++ b/src/main/java/com/ning/http/client/websocket/WebSocketByteFragmentListener.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2014 AsyncHttpClient Project. 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.websocket; + +import com.ning.http.client.HttpResponseBodyPart; + +/** + * Invoked when WebSocket binary fragments are received. + * + * @param fragment text fragment + */ +public interface WebSocketByteFragmentListener extends WebSocketListener { + + void onFragment(HttpResponseBodyPart fragment); +} diff --git a/src/main/java/com/ning/http/client/websocket/WebSocketByteListener.java b/src/main/java/com/ning/http/client/websocket/WebSocketByteListener.java index 5a5c99f4d6..a0cf74a368 100644 --- a/src/main/java/com/ning/http/client/websocket/WebSocketByteListener.java +++ b/src/main/java/com/ning/http/client/websocket/WebSocketByteListener.java @@ -22,12 +22,4 @@ public interface WebSocketByteListener extends WebSocketListener { * @param message a byte array. */ void onMessage(byte[] message); - - /** - * Invoked when bytes of a fragmented message are available. - * - * @param fragment byte[] fragment. - * @param last if this fragment is the last in the series. - */ - void onFragment(byte[] fragment, boolean last); } diff --git a/src/main/java/com/ning/http/client/websocket/WebSocketTextFragmentListener.java b/src/main/java/com/ning/http/client/websocket/WebSocketTextFragmentListener.java new file mode 100644 index 0000000000..bcc26b74ef --- /dev/null +++ b/src/main/java/com/ning/http/client/websocket/WebSocketTextFragmentListener.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2014 AsyncHttpClient Project. 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.websocket; + +import com.ning.http.client.HttpResponseBodyPart; + +/** + * Invoked when WebSocket text fragments are received. + * + * @param fragment text fragment + */ +public interface WebSocketTextFragmentListener extends WebSocketListener { + + void onFragment(HttpResponseBodyPart fragment); +} diff --git a/src/main/java/com/ning/http/client/websocket/WebSocketTextListener.java b/src/main/java/com/ning/http/client/websocket/WebSocketTextListener.java index e5456cb112..b3c46678a4 100644 --- a/src/main/java/com/ning/http/client/websocket/WebSocketTextListener.java +++ b/src/main/java/com/ning/http/client/websocket/WebSocketTextListener.java @@ -22,12 +22,4 @@ public interface WebSocketTextListener extends WebSocketListener { * @param message a {@link String} message */ void onMessage(String message); - - /** - * Invoked when WebSocket text fragments are received. - * - * @param fragment text fragment - * @param last if this fragment is the last of the series. - */ - void onFragment(String fragment, boolean last); } 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 fa173a7143..71b590b02b 100644 --- a/src/test/java/com/ning/http/client/websocket/ByteMessageTest.java +++ b/src/test/java/com/ning/http/client/websocket/ByteMessageTest.java @@ -12,16 +12,18 @@ */ package com.ning.http.client.websocket; -import com.ning.http.client.AsyncHttpClient; +import static org.testng.Assert.assertEquals; + import org.testng.annotations.Test; +import com.ning.http.client.AsyncHttpClient; + import javax.servlet.http.HttpServletRequest; + import java.io.IOException; import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicReference; -import static org.testng.Assert.assertEquals; - public abstract class ByteMessageTest extends AbstractBasicTest { private final class EchoByteWebSocket implements org.eclipse.jetty.websocket.WebSocket, org.eclipse.jetty.websocket.WebSocket.OnBinaryMessage { @@ -92,10 +94,6 @@ public void onMessage(byte[] message) { text.set(message); latch.countDown(); } - - @Override - public void onFragment(byte[] fragment, boolean last) { - } }).build()).get(); websocket.sendMessage("ECHO".getBytes()); @@ -143,10 +141,6 @@ public void onMessage(byte[] message) { } latch.countDown(); } - - @Override - public void onFragment(byte[] fragment, boolean last) { - } }).build()).get(); websocket.sendMessage("ECHO".getBytes()).sendMessage("ECHO".getBytes()); @@ -195,10 +189,6 @@ public void onMessage(byte[] message) { } latch.countDown(); } - - @Override - public void onFragment(byte[] fragment, boolean last) { - } }).build()).get(); latch.await(); @@ -243,10 +233,6 @@ public void onMessage(byte[] message) { } latch.countDown(); } - - @Override - public void onFragment(byte[] fragment, boolean last) { - } }).build()).get(); websocket.stream("ECHO".getBytes(), false); websocket.stream("ECHO".getBytes(), true); 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 6b6792b3d5..a2c9b0f634 100644 --- a/src/test/java/com/ning/http/client/websocket/CloseCodeReasonMessageTest.java +++ b/src/test/java/com/ning/http/client/websocket/CloseCodeReasonMessageTest.java @@ -107,10 +107,6 @@ public void wrongStatusCode() throws Throwable { public void onMessage(String message) { } - @Override - public void onFragment(String fragment, boolean last) { - } - @Override public void onOpen(com.ning.http.client.websocket.WebSocket websocket) { } @@ -147,10 +143,6 @@ public void wrongProtocolCode() throws Throwable { public void onMessage(String message) { } - @Override - public void onFragment(String fragment, boolean last) { - } - @Override public void onOpen(com.ning.http.client.websocket.WebSocket websocket) { } diff --git a/src/test/java/com/ning/http/client/websocket/ProxyTunnellingTest.java b/src/test/java/com/ning/http/client/websocket/ProxyTunnellingTest.java index a83129ba61..032e086851 100644 --- a/src/test/java/com/ning/http/client/websocket/ProxyTunnellingTest.java +++ b/src/test/java/com/ning/http/client/websocket/ProxyTunnellingTest.java @@ -133,10 +133,6 @@ public void onMessage(String message) { latch.countDown(); } - @Override - public void onFragment(String fragment, boolean last) { - } - @Override public void onOpen(WebSocket websocket) { } 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 74d9b56bd3..c031567b4a 100644 --- a/src/test/java/com/ning/http/client/websocket/TextMessageTest.java +++ b/src/test/java/com/ning/http/client/websocket/TextMessageTest.java @@ -75,7 +75,7 @@ public void onOpen() throws Throwable { final CountDownLatch latch = new CountDownLatch(1); final AtomicReference text = new AtomicReference(""); - WebSocket websocket = client.prepareGet(getTargetUrl()).execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(new WebSocketListener() { + client.prepareGet(getTargetUrl()).execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(new WebSocketListener() { @Override public void onOpen(com.ning.http.client.websocket.WebSocket websocket) { @@ -216,10 +216,6 @@ public void onMessage(String message) { latch.countDown(); } - @Override - public void onFragment(String fragment, boolean last) { - } - @Override public void onOpen(com.ning.http.client.websocket.WebSocket websocket) { } @@ -260,10 +256,6 @@ public void onMessage(String message) { latch.countDown(); } - @Override - public void onFragment(String fragment, boolean last) { - } - @Override public void onOpen(com.ning.http.client.websocket.WebSocket websocket) { } @@ -286,10 +278,6 @@ public void onMessage(String message) { latch.countDown(); } - @Override - public void onFragment(String fragment, boolean last) { - } - @Override public void onOpen(com.ning.http.client.websocket.WebSocket websocket) { } @@ -330,12 +318,6 @@ public void onMessage(String 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"); @@ -374,10 +356,6 @@ public void onMessage(String message) { latch.countDown(); } - @Override - public void onFragment(String fragment, boolean last) { - } - @Override public void onOpen(com.ning.http.client.websocket.WebSocket websocket) { } @@ -420,10 +398,6 @@ public void onMessage(String message) { textLatch.countDown(); } - @Override - public void onFragment(String fragment, boolean last) { - } - @Override public void onOpen(com.ning.http.client.websocket.WebSocket websocket) { } From 561191b3f479c1341a6dff319a99daea0fd194d1 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 30 Jul 2014 13:59:44 +0200 Subject: [PATCH 516/701] minor clean up --- .../ning/http/client/providers/netty/ws/NettyWebSocket.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/ws/NettyWebSocket.java b/src/main/java/com/ning/http/client/providers/netty/ws/NettyWebSocket.java index 199e2434e4..325988752e 100644 --- a/src/main/java/com/ning/http/client/providers/netty/ws/NettyWebSocket.java +++ b/src/main/java/com/ning/http/client/providers/netty/ws/NettyWebSocket.java @@ -18,7 +18,6 @@ import static org.jboss.netty.buffer.ChannelBuffers.wrappedBuffer; import org.jboss.netty.buffer.ChannelBuffer; -import org.jboss.netty.buffer.ChannelBuffers; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFutureListener; import org.jboss.netty.handler.codec.http.websocketx.BinaryWebSocketFrame; @@ -255,7 +254,7 @@ public void onBinaryFragment(HttpResponseBodyPart part) { } else { bufferFragment(fragment); - notifyByteListeners(ChannelBuffers.wrappedBuffer(fragments().toArray(new ChannelBuffer[fragments().size()]))); + notifyByteListeners(wrappedBuffer(fragments().toArray(new ChannelBuffer[fragments().size()]))); } reset(); @@ -280,7 +279,7 @@ public void onTextFragment(HttpResponseBodyPart part) { } else { bufferFragment(fragment); - notifyTextListeners(ChannelBuffers.wrappedBuffer(fragments().toArray(new ChannelBuffer[fragments().size()]))); + notifyTextListeners(wrappedBuffer(fragments().toArray(new ChannelBuffer[fragments().size()]))); } reset(); From 37361603f9e8efb6e4d58a86283aa94df0e5776b Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 30 Jul 2014 14:24:28 +0200 Subject: [PATCH 517/701] [maven-release-plugin] prepare release async-http-client-1.9.0-BETA6 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 824c0acaff..d5eca99601 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.9.0-SNAPSHOT + 1.9.0-BETA6 jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From f67cbb58ff4498ad0b5c193349bd61dca36ac37e Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 30 Jul 2014 14:24:33 +0200 Subject: [PATCH 518/701] [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 d5eca99601..824c0acaff 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.9.0-BETA6 + 1.9.0-SNAPSHOT jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From 705abd2f2cb1c8dc0d2e210f4558762a981d383f Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 30 Jul 2014 15:57:45 +0200 Subject: [PATCH 519/701] Netty websocket streaming, close #518 --- .../client/providers/netty/ws/NettyWebSocket.java | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/ws/NettyWebSocket.java b/src/main/java/com/ning/http/client/providers/netty/ws/NettyWebSocket.java index 325988752e..1e645b5c17 100644 --- a/src/main/java/com/ning/http/client/providers/netty/ws/NettyWebSocket.java +++ b/src/main/java/com/ning/http/client/providers/netty/ws/NettyWebSocket.java @@ -72,12 +72,18 @@ public WebSocket sendMessage(byte[] message) { @Override public WebSocket stream(byte[] fragment, boolean last) { - throw new UnsupportedOperationException("Streaming currently only supported by the Grizzly provider."); + BinaryWebSocketFrame frame = new BinaryWebSocketFrame(wrappedBuffer(fragment)); + frame.setFinalFragment(last); + channel.write(frame); + return this; } @Override public WebSocket stream(byte[] fragment, int offset, int len, boolean last) { - throw new UnsupportedOperationException("Streaming currently only supported by the Grizzly provider."); + BinaryWebSocketFrame frame = new BinaryWebSocketFrame(wrappedBuffer(fragment, offset, len)); + frame.setFinalFragment(last); + channel.write(frame); + return this; } @Override @@ -88,7 +94,10 @@ public WebSocket sendTextMessage(String message) { @Override public WebSocket streamText(String fragment, boolean last) { - throw new UnsupportedOperationException("Streaming currently only supported by the Grizzly provider."); + TextWebSocketFrame frame = new TextWebSocketFrame(fragment); + frame.setFinalFragment(last); + channel.write(frame); + return this; } @Override From fedda6a59a211bbe52a803e16cd3ebd38c6c22c3 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 30 Jul 2014 16:28:56 +0200 Subject: [PATCH 520/701] Notify Pings and Pongs, close #517 --- .../netty/handler/WebSocketProtocol.java | 19 +++++++++++++------ .../providers/netty/ws/NettyWebSocket.java | 18 ++++++++++++++++++ 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/handler/WebSocketProtocol.java b/src/main/java/com/ning/http/client/providers/netty/handler/WebSocketProtocol.java index 2059311ed0..4d580543f4 100644 --- a/src/main/java/com/ning/http/client/providers/netty/handler/WebSocketProtocol.java +++ b/src/main/java/com/ning/http/client/providers/netty/handler/WebSocketProtocol.java @@ -23,6 +23,9 @@ import org.jboss.netty.handler.codec.http.HttpResponse; 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.jboss.netty.handler.codec.http.websocketx.WebSocketFrame; import com.ning.http.client.AsyncHandler.STATE; @@ -131,7 +134,7 @@ public void handle(Channel channel, NettyResponseFuture future, Object e) thr Channels.setDiscard(channel); CloseWebSocketFrame closeFrame = CloseWebSocketFrame.class.cast(frame); webSocket.onClose(closeFrame.getStatusCode(), closeFrame.getReasonText()); - + } else if (frame.getBinaryData() != null) { HttpChunk webSocketChunk = new HttpChunk() { private ChannelBuffer content = frame.getBinaryData(); @@ -152,13 +155,17 @@ public void setContent(ChannelBuffer content) { } }; - NettyResponseBodyPart rp = new NettyResponseBodyPart(null, webSocketChunk, frame.isFinalFragment()); - handler.onBodyPartReceived(rp); + NettyResponseBodyPart part = new NettyResponseBodyPart(null, webSocketChunk, frame.isFinalFragment()); + handler.onBodyPartReceived(part); if (frame instanceof BinaryWebSocketFrame) { - webSocket.onBinaryFragment(rp); - } else { - webSocket.onTextFragment(rp); + webSocket.onBinaryFragment(part); + } else if (frame instanceof TextWebSocketFrame) { + webSocket.onTextFragment(part); + } else if (frame instanceof PingWebSocketFrame) { + webSocket.onPing(part); + } else if (frame instanceof PongWebSocketFrame) { + webSocket.onPong(part); } } } else { diff --git a/src/main/java/com/ning/http/client/providers/netty/ws/NettyWebSocket.java b/src/main/java/com/ning/http/client/providers/netty/ws/NettyWebSocket.java index 1e645b5c17..afed8661c2 100644 --- a/src/main/java/com/ning/http/client/providers/netty/ws/NettyWebSocket.java +++ b/src/main/java/com/ning/http/client/providers/netty/ws/NettyWebSocket.java @@ -35,6 +35,8 @@ import com.ning.http.client.websocket.WebSocketByteListener; import com.ning.http.client.websocket.WebSocketCloseCodeReasonListener; import com.ning.http.client.websocket.WebSocketListener; +import com.ning.http.client.websocket.WebSocketPingListener; +import com.ning.http.client.websocket.WebSocketPongListener; import com.ning.http.client.websocket.WebSocketTextFragmentListener; import com.ning.http.client.websocket.WebSocketTextListener; @@ -297,4 +299,20 @@ public void onTextFragment(HttpResponseBodyPart part) { bufferFragment(fragment); } } + + public void onPing(HttpResponseBodyPart part) { + for (WebSocketListener listener : listeners) { + if (listener instanceof WebSocketPingListener) + // bytes are cached in the part + WebSocketPingListener.class.cast(listener).onPing(part.getBodyPartBytes()); + } + } + + public void onPong(HttpResponseBodyPart part) { + for (WebSocketListener listener : listeners) { + if (listener instanceof WebSocketPongListener) + // bytes are cached in the part + WebSocketPongListener.class.cast(listener).onPong(part.getBodyPartBytes()); + } + } } From a1237beb68c96312549fa1391920422ca050e9fd Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 30 Jul 2014 16:38:37 +0200 Subject: [PATCH 521/701] Have a config parameter for websocket max buffer size, close #658 --- .../netty/NettyAsyncHttpProviderConfig.java | 16 +++++++++++++--- .../netty/handler/WebSocketProtocol.java | 2 +- .../providers/netty/ws/NettyWebSocket.java | 18 ++++++------------ 3 files changed, 20 insertions(+), 16 deletions(-) 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 8e2d71d6ca..e308722e5e 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 @@ -133,6 +133,8 @@ public Set> propertiesSet() { private NettyWebSocketFactory nettyWebSocketFactory = new DefaultNettyWebSocketFactory(); + private int webSocketMaxBufferSize = 128000000; + public boolean isUseDeadLockChecker() { return useDeadLockChecker; } @@ -237,15 +239,23 @@ public void setNettyWebSocketFactory(NettyWebSocketFactory nettyWebSocketFactory this.nettyWebSocketFactory = nettyWebSocketFactory; } + public int getWebSocketMaxBufferSize() { + return webSocketMaxBufferSize; + } + + public void setWebSocketMaxBufferSize(int webSocketMaxBufferSize) { + this.webSocketMaxBufferSize = webSocketMaxBufferSize; + } + public static interface NettyWebSocketFactory { - NettyWebSocket newNettyWebSocket(Channel channel); + NettyWebSocket newNettyWebSocket(Channel channel, NettyAsyncHttpProviderConfig nettyConfig); } public class DefaultNettyWebSocketFactory implements NettyWebSocketFactory { @Override - public NettyWebSocket newNettyWebSocket(Channel channel) { - return new NettyWebSocket(channel); + public NettyWebSocket newNettyWebSocket(Channel channel, NettyAsyncHttpProviderConfig nettyConfig) { + return new NettyWebSocket(channel, nettyConfig); } } } diff --git a/src/main/java/com/ning/http/client/providers/netty/handler/WebSocketProtocol.java b/src/main/java/com/ning/http/client/providers/netty/handler/WebSocketProtocol.java index 4d580543f4..601d885137 100644 --- a/src/main/java/com/ning/http/client/providers/netty/handler/WebSocketProtocol.java +++ b/src/main/java/com/ning/http/client/providers/netty/handler/WebSocketProtocol.java @@ -62,7 +62,7 @@ public WebSocketProtocol(ChannelManager channelManager,// private void invokeOnSucces(Channel channel, WebSocketUpgradeHandler h) { if (!h.touchSuccess()) { try { - h.onSuccess(nettyConfig.getNettyWebSocketFactory().newNettyWebSocket(channel)); + h.onSuccess(nettyConfig.getNettyWebSocketFactory().newNettyWebSocket(channel, nettyConfig)); } catch (Exception ex) { logger.warn("onSuccess unexpected exception", ex); } diff --git a/src/main/java/com/ning/http/client/providers/netty/ws/NettyWebSocket.java b/src/main/java/com/ning/http/client/providers/netty/ws/NettyWebSocket.java index afed8661c2..d947e0bd82 100644 --- a/src/main/java/com/ning/http/client/providers/netty/ws/NettyWebSocket.java +++ b/src/main/java/com/ning/http/client/providers/netty/ws/NettyWebSocket.java @@ -29,6 +29,7 @@ import org.slf4j.LoggerFactory; import com.ning.http.client.HttpResponseBodyPart; +import com.ning.http.client.providers.netty.NettyAsyncHttpProviderConfig; import com.ning.http.client.providers.netty.response.NettyResponseBodyPart; import com.ning.http.client.websocket.WebSocket; import com.ning.http.client.websocket.WebSocketByteFragmentListener; @@ -51,19 +52,20 @@ public class NettyWebSocket implements WebSocket { protected final Channel channel; protected final Collection listeners; - protected int maxBufferSize = 128000000; + protected final int maxBufferSize; private int bufferSize; private List _fragments; private volatile boolean interestedInByteMessages; private volatile boolean interestedInTextMessages; - public NettyWebSocket(Channel channel) { - this(channel, new ConcurrentLinkedQueue()); + public NettyWebSocket(Channel channel, NettyAsyncHttpProviderConfig nettyConfig) { + this(channel, nettyConfig, new ConcurrentLinkedQueue()); } - public NettyWebSocket(Channel channel, Collection listeners) { + public NettyWebSocket(Channel channel, NettyAsyncHttpProviderConfig nettyConfig, Collection listeners) { this.channel = channel; this.listeners = listeners; + maxBufferSize = nettyConfig.getWebSocketMaxBufferSize(); } @Override @@ -114,14 +116,6 @@ public WebSocket sendPong(byte[] payload) { return this; } - public int getMaxBufferSize() { - return maxBufferSize; - } - - public void setMaxBufferSize(int maxBufferSize) { - this.maxBufferSize = Math.max(maxBufferSize, 8192); - } - @Override public boolean isOpen() { return channel.isOpen(); From b455a94db6b64a0ff2a53c23d29a0ae462dc8f6c Mon Sep 17 00:00:00 2001 From: oleksiys Date: Fri, 1 Aug 2014 15:54:37 -0700 Subject: [PATCH 522/701] [1.9.x] + don't add another Host header if it's already set --- .../grizzly/GrizzlyAsyncHttpProvider.java | 17 ++++++++++------- 1 file changed, 10 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 73dc8aee5d..8a0f729265 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 @@ -853,14 +853,17 @@ private boolean sendAsGrizzlyRequest(final Request request, boolean secure = "https".equals(uri.getScheme()); builder.method(method); builder.protocol(Protocol.HTTP_1_1); - String host = request.getVirtualHost(); - if (host != null) { - builder.header(Header.Host, host); - } else { - if (uri.getPort() == -1) { - builder.header(Header.Host, uri.getHost()); + + if (!request.getHeaders().containsKey(Header.Host.toString())) { + String host = request.getVirtualHost(); + if (host != null) { + builder.header(Header.Host, host); } else { - builder.header(Header.Host, uri.getHost() + ':' + uri.getPort()); + if (uri.getPort() == -1) { + builder.header(Header.Host, uri.getHost()); + } else { + builder.header(Header.Host, uri.getHost() + ':' + uri.getPort()); + } } } final ProxyServer proxy = ProxyUtils.getProxyServer(config, request); From a63b4f67b882a381e69ac8b98d4b692aa526cee2 Mon Sep 17 00:00:00 2001 From: Pierre DAL-PRA Date: Thu, 7 Aug 2014 19:26:16 +0200 Subject: [PATCH 523/701] Do not block the WebSocket from receiving bytes or text fragments --- .../http/client/providers/netty/ws/NettyWebSocket.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/ws/NettyWebSocket.java b/src/main/java/com/ning/http/client/providers/netty/ws/NettyWebSocket.java index d947e0bd82..bda897561b 100644 --- a/src/main/java/com/ning/http/client/providers/netty/ws/NettyWebSocket.java +++ b/src/main/java/com/ning/http/client/providers/netty/ws/NettyWebSocket.java @@ -186,10 +186,8 @@ private boolean hasWebSocketTextListener() { @Override public WebSocket addWebSocketListener(WebSocketListener l) { listeners.add(l); - if (l instanceof WebSocketByteListener) - interestedInByteMessages = true; - else if (l instanceof WebSocketTextListener) - interestedInTextMessages = true; + interestedInByteMessages = interestedInByteMessages || l instanceof WebSocketByteListener; + interestedInTextMessages = interestedInTextMessages || l instanceof WebSocketTextListener; return this; } @@ -199,7 +197,7 @@ public WebSocket removeWebSocketListener(WebSocketListener l) { if (l instanceof WebSocketByteListener) interestedInByteMessages = hasWebSocketByteListener(); - else if (l instanceof WebSocketTextListener) + if (l instanceof WebSocketTextListener) interestedInTextMessages = hasWebSocketTextListener(); return this; From 626e2731f88d4935bad89e3c354fd0d4cb9f0555 Mon Sep 17 00:00:00 2001 From: Pierre DAL-PRA Date: Thu, 7 Aug 2014 22:16:00 +0200 Subject: [PATCH 524/701] Fix MiscUtils: closeSilently should check for nullity --- src/main/java/com/ning/http/util/MiscUtils.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/ning/http/util/MiscUtils.java b/src/main/java/com/ning/http/util/MiscUtils.java index 8093aa67c8..1874e1832b 100644 --- a/src/main/java/com/ning/http/util/MiscUtils.java +++ b/src/main/java/com/ning/http/util/MiscUtils.java @@ -49,9 +49,12 @@ public static boolean getBoolean(String systemPropName, boolean defaultValue) { } public static void closeSilently(Closeable closeable) { - try { - closeable.close(); - } catch (IOException e) { + if(closeable != null) { + try { + closeable.close(); + } catch (IOException ioe) { + // Ignored + } } } } From 9a051b78a750dfe263497bf63e52533aff492e72 Mon Sep 17 00:00:00 2001 From: Pierre DAL-PRA Date: Thu, 7 Aug 2014 22:20:07 +0200 Subject: [PATCH 525/701] Upgrade Netty 3.9.3 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 824c0acaff..e835d77ca7 100644 --- a/pom.xml +++ b/pom.xml @@ -565,7 +565,7 @@ http://oss.sonatype.org/content/repositories/snapshots true - 3.9.2.Final + 3.9.3.Final 2.3.16 1.6 1.6 From 20baaa64111dc30caafb1f9ead33e917ae56a573 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Sat, 23 Aug 2014 13:29:23 +0200 Subject: [PATCH 526/701] 0 content-length means empty file, not chunked --- .../client/providers/netty/request/NettyRequestFactory.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestFactory.java b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestFactory.java index 620c9a6f0c..988b7dbae0 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestFactory.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestFactory.java @@ -278,10 +278,10 @@ public NettyRequest newNettyRequest(Request request, UriComponents uri, boolean } if (body != null) { - if (body.getContentLength() > 0) - httpRequest.headers().set(HttpHeaders.Names.CONTENT_LENGTH, body.getContentLength()); - else + if (body.getContentLength() < 0) httpRequest.headers().set(HttpHeaders.Names.TRANSFER_ENCODING, HttpHeaders.Values.CHUNKED); + else + httpRequest.headers().set(HttpHeaders.Names.CONTENT_LENGTH, body.getContentLength()); if (body.getContentType() != null) httpRequest.headers().set(HttpHeaders.Names.CONTENT_TYPE, body.getContentType()); From 47c55ba03259e3c2fd7b6eff30ad1737b9fb0036 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Sat, 23 Aug 2014 13:31:23 +0200 Subject: [PATCH 527/701] Don't use replace but addAfter+remove so that first frame is not lost, close #471 --- .../client/providers/netty/channel/ChannelManager.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java b/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java index 030d95d630..b3a1edd15f 100644 --- a/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java +++ b/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java @@ -387,8 +387,10 @@ public void upgradeProtocol(ChannelPipeline pipeline, String scheme, String host else pipeline.addFirst(HTTP_HANDLER, newHttpClientCodec()); - if (isWebSocket(scheme)) - pipeline.replace(HTTP_PROCESSOR, WS_PROCESSOR, wsProcessor); + if (isWebSocket(scheme)) { + pipeline.addAfter(HTTP_PROCESSOR, WS_PROCESSOR, wsProcessor); + pipeline.remove(HTTP_PROCESSOR); + } } public String getPoolKey(NettyResponseFuture future) { @@ -413,7 +415,8 @@ public ClientBootstrap getBootstrap(String scheme, boolean useProxy, boolean use } public void upgradePipelineForWebSockets(ChannelPipeline pipeline) { - pipeline.replace(HTTP_HANDLER, WS_ENCODER_HANDLER, new WebSocket08FrameEncoder(true)); + pipeline.addAfter(HTTP_HANDLER, WS_ENCODER_HANDLER, new WebSocket08FrameEncoder(true)); + pipeline.remove(HTTP_HANDLER); pipeline.addBefore(WS_PROCESSOR, WS_DECODER_HANDLER, new WebSocket08FrameDecoder(false, false, 10 * 1024)); } From a9ac9b29dcb1edcbcaa2fdecd713031fa4d05ea4 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Sat, 23 Aug 2014 13:31:58 +0200 Subject: [PATCH 528/701] minor clean up --- .../netty/request/NettyRequestFactory.java | 34 ++++++++++--------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestFactory.java b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestFactory.java index 988b7dbae0..cfaa005728 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestFactory.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestFactory.java @@ -264,64 +264,66 @@ public NettyRequest newNettyRequest(Request request, UriComponents uri, boolean nettyRequest = new NettyRequest(httpRequest, body); } + HttpHeaders headers = httpRequest.headers(); + if (method != HttpMethod.CONNECT) { // assign headers as configured on request for (Entry> header : request.getHeaders()) { - httpRequest.headers().set(header.getKey(), header.getValue()); + headers.set(header.getKey(), header.getValue()); } if (isNonEmpty(request.getCookies())) - httpRequest.headers().set(HttpHeaders.Names.COOKIE, CookieEncoder.encode(request.getCookies())); + headers.set(HttpHeaders.Names.COOKIE, CookieEncoder.encode(request.getCookies())); if (config.isCompressionEnabled()) - httpRequest.headers().set(HttpHeaders.Names.ACCEPT_ENCODING, GZIP_DEFLATE); + headers.set(HttpHeaders.Names.ACCEPT_ENCODING, GZIP_DEFLATE); } if (body != null) { if (body.getContentLength() < 0) - httpRequest.headers().set(HttpHeaders.Names.TRANSFER_ENCODING, HttpHeaders.Values.CHUNKED); + headers.set(HttpHeaders.Names.TRANSFER_ENCODING, HttpHeaders.Values.CHUNKED); else - httpRequest.headers().set(HttpHeaders.Names.CONTENT_LENGTH, body.getContentLength()); + headers.set(HttpHeaders.Names.CONTENT_LENGTH, body.getContentLength()); if (body.getContentType() != null) - httpRequest.headers().set(HttpHeaders.Names.CONTENT_TYPE, body.getContentType()); + headers.set(HttpHeaders.Names.CONTENT_TYPE, body.getContentType()); } // connection header and friends boolean webSocket = isWebSocket(uri.getScheme()); if (method != HttpMethod.CONNECT && webSocket) { String origin = "http://" + uri.getHost() + ":" + (uri.getPort() == -1 ? isSecure(uri.getScheme()) ? 443 : 80 : uri.getPort()); - httpRequest.headers().set(HttpHeaders.Names.UPGRADE, HttpHeaders.Values.WEBSOCKET)// + headers.set(HttpHeaders.Names.UPGRADE, HttpHeaders.Values.WEBSOCKET)// .set(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.UPGRADE)// .set(HttpHeaders.Names.ORIGIN, origin)// .set(HttpHeaders.Names.SEC_WEBSOCKET_KEY, getKey())// .set(HttpHeaders.Names.SEC_WEBSOCKET_VERSION, "13"); - } else if (!httpRequest.headers().contains(HttpHeaders.Names.CONNECTION)) { - httpRequest.headers().set(HttpHeaders.Names.CONNECTION, keepAliveHeaderValue(config)); + } else if (!headers.contains(HttpHeaders.Names.CONNECTION)) { + headers.set(HttpHeaders.Names.CONNECTION, keepAliveHeaderValue(config)); } String hostHeader = hostHeader(request, uri); if (hostHeader != null) - httpRequest.headers().set(HttpHeaders.Names.HOST, hostHeader); + headers.set(HttpHeaders.Names.HOST, hostHeader); Realm realm = request.getRealm() != null ? request.getRealm() : config.getRealm(); String authorizationHeader = authorizationHeader(request, uri, proxyServer, realm); if (authorizationHeader != null) // don't override authorization but append - httpRequest.headers().add(HttpHeaders.Names.AUTHORIZATION, authorizationHeader); + headers.add(HttpHeaders.Names.AUTHORIZATION, authorizationHeader); String proxyAuthorizationHeader = proxyAuthorizationHeader(request, proxyServer, method); if (proxyAuthorizationHeader != null) - httpRequest.headers().set(HttpHeaders.Names.PROXY_AUTHORIZATION, proxyAuthorizationHeader); + headers.set(HttpHeaders.Names.PROXY_AUTHORIZATION, proxyAuthorizationHeader); // Add default accept headers - if (!httpRequest.headers().contains(HttpHeaders.Names.ACCEPT)) - httpRequest.headers().set(HttpHeaders.Names.ACCEPT, "*/*"); + if (!headers.contains(HttpHeaders.Names.ACCEPT)) + headers.set(HttpHeaders.Names.ACCEPT, "*/*"); // Add default user agent - if (!httpRequest.headers().contains(HttpHeaders.Names.USER_AGENT) && config.getUserAgent() != null) - httpRequest.headers().set(HttpHeaders.Names.USER_AGENT, config.getUserAgent()); + if (!headers.contains(HttpHeaders.Names.USER_AGENT) && config.getUserAgent() != null) + headers.set(HttpHeaders.Names.USER_AGENT, config.getUserAgent()); return nettyRequest; } From 56d4f197ea1ed32ad4e4017aad0d583a7b8bf73d Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Sat, 23 Aug 2014 13:33:03 +0200 Subject: [PATCH 529/701] append char instead of String --- .../client/providers/netty/request/NettyRequestFactory.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestFactory.java b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestFactory.java index cfaa005728..cd813ed131 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestFactory.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestFactory.java @@ -189,9 +189,9 @@ private byte[] computeBodyFromParams(List params, Charset bodyCharset) { StringBuilder sb = new StringBuilder(); for (Param param : params) { UTF8UrlEncoder.appendEncoded(sb, param.getName()); - sb.append("="); + sb.append('='); UTF8UrlEncoder.appendEncoded(sb, param.getValue()); - sb.append("&"); + sb.append('&'); } sb.setLength(sb.length() - 1); return sb.toString().getBytes(bodyCharset); From 6fb0966b1c6485c83200b004e36d9dfd2df8d597 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Sat, 23 Aug 2014 13:58:42 +0200 Subject: [PATCH 530/701] Target JDK7, use getHostString instead of getHostName, close #672 --- pom.xml | 8 ++++---- .../client/providers/netty/channel/SslInitializer.java | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pom.xml b/pom.xml index e835d77ca7..8a64df6dc6 100644 --- a/pom.xml +++ b/pom.xml @@ -262,13 +262,13 @@ org.codehaus.mojo.signature - java16 + java17 1.0 - check-java-1.6-compat + check-java-1.7-compat process-classes check @@ -567,8 +567,8 @@ true 3.9.3.Final 2.3.16 - 1.6 - 1.6 + 1.7 + 1.7 2.12 diff --git a/src/main/java/com/ning/http/client/providers/netty/channel/SslInitializer.java b/src/main/java/com/ning/http/client/providers/netty/channel/SslInitializer.java index 47027fbdd6..c290d87be7 100644 --- a/src/main/java/com/ning/http/client/providers/netty/channel/SslInitializer.java +++ b/src/main/java/com/ning/http/client/providers/netty/channel/SslInitializer.java @@ -38,7 +38,7 @@ public SslInitializer(ChannelManager channelManager) { public void connectRequested(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception { InetSocketAddress remoteInetSocketAddress = (InetSocketAddress) e.getValue(); - String peerHost = remoteInetSocketAddress.getHostName(); + String peerHost = remoteInetSocketAddress.getHostString(); int peerPort = remoteInetSocketAddress.getPort(); SslHandler sslHandler = channelManager.createSslHandler(peerHost, peerPort); From 2d5e9226727a4018d973230e3b5d6d29d9877f65 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Sat, 23 Aug 2014 14:15:32 +0200 Subject: [PATCH 531/701] Wrong javadoc, close #666 --- src/main/java/com/ning/http/client/Request.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/com/ning/http/client/Request.java b/src/main/java/com/ning/http/client/Request.java index e517cb479a..9158ff9275 100644 --- a/src/main/java/com/ning/http/client/Request.java +++ b/src/main/java/com/ning/http/client/Request.java @@ -34,7 +34,6 @@ * .setPassword(admin) * .setRealmName("MyRealm") * .setScheme(Realm.AuthScheme.DIGEST).build()); - * r.execute(); * */ public interface Request { From a5d66dce0e07def9bd301c0291e993015668830d Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Sat, 23 Aug 2014 14:58:02 +0200 Subject: [PATCH 532/701] Add handler callbacks, close #673 --- .../http/client/AsyncHandlerExtensions.java | 26 ++++++++++++++++--- .../grizzly/GrizzlyAsyncHttpProvider.java | 2 +- .../netty/request/NettyRequestSender.java | 22 +++++++++++----- .../request/body/NettyConnectListener.java | 4 +++ 4 files changed, 42 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/ning/http/client/AsyncHandlerExtensions.java b/src/main/java/com/ning/http/client/AsyncHandlerExtensions.java index c8ddbdf761..f4d06f3316 100644 --- a/src/main/java/com/ning/http/client/AsyncHandlerExtensions.java +++ b/src/main/java/com/ning/http/client/AsyncHandlerExtensions.java @@ -19,7 +19,6 @@ * * More additional hooks might come, such as: *
      - *
    • onConnected()
    • *
    • onConnectionClosed()
    • *
    • onBytesSent(long numberOfBytes)
    • *
    • onBytesReceived(long numberOfBytes)
    • @@ -28,12 +27,31 @@ public interface AsyncHandlerExtensions { /** - * Notify the callback when a request is being written on the wire. + * Notify the callback when trying to open a new connection. + */ + void onOpenConnection(); + + /** + * Notify the callback when a new connection was successfully opened. + */ + void onConnectionOpen(); + + /** + * Notify the callback when trying to fetch a connection from the pool. + */ + void onPoolConnection(); + + /** + * Notify the callback when a new connection was successfully fetched from the pool. + */ + void onConnectionPooled(); + + /** + * Notify the callback when a request is about to be written on the wire. * If the original request causes multiple requests to be sent, for example, because of authorization or retry, * it will be notified multiple times. - * Currently only supported by the Netty provider. */ - void onRequestSent(); + void onSendRequest(); /** * Notify the callback every time a request is being retried. 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 8a0f729265..0f0ebaca81 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 @@ -1174,7 +1174,7 @@ protected void onHttpHeadersEncoded(HttpHeader httpHeader, FilterChainContext ct ((TransferCompletionHandler) handler).onHeaderWriteCompleted(); } if (handler instanceof AsyncHandlerExtensions) { - ((AsyncHandlerExtensions) handler).onRequestSent(); + ((AsyncHandlerExtensions) handler).onSendRequest(); } } diff --git a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java index 54859f438e..73fd919a42 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java @@ -162,8 +162,7 @@ private ListenableFuture sendRequestThroughSslProxy(// newFuture = newNettyRequestAndResponseFuture(request, asyncHandler, future, uri, proxyServer, false); if (Channels.isChannelValid(channel)) - // if the channel is still active, we can use it, otherwise try - // gain + // if the channel is still active, we can use it, otherwise try gain return sendRequestWithCachedChannel(request, uri, proxyServer, newFuture, asyncHandler, channel); else // pool is empty @@ -194,12 +193,15 @@ private Channel getCachedChannel(NettyResponseFuture future, UriComponents ur if (future != null && future.reuseChannel() && Channels.isChannelValid(future.channel())) return future.channel(); else - return pollAndVerifyCachedChannel(uri, proxyServer, poolKeyGen); + return pollAndVerifyCachedChannel(uri, proxyServer, poolKeyGen, future.getAsyncHandler()); } private ListenableFuture sendRequestWithCachedChannel(Request request, UriComponents uri, ProxyServer proxy, NettyResponseFuture future, AsyncHandler asyncHandler, Channel channel) throws IOException { + if (asyncHandler instanceof AsyncHandlerExtensions) + AsyncHandlerExtensions.class.cast(asyncHandler).onConnectionPooled(); + future.setState(NettyResponseFuture.STATE.POOLED); future.attachChannel(channel, false); @@ -258,6 +260,9 @@ private ListenableFuture sendRequestWithNewChannel(// } try { + if (asyncHandler instanceof AsyncHandlerExtensions) + AsyncHandlerExtensions.class.cast(asyncHandler).onOpenConnection(); + ChannelFuture channelFuture = connect(request, uri, proxy, useProxy, bootstrap); channelFuture.addListener(new NettyConnectListener(config, future, this, channelManager, channelPreempted, poolKey)); @@ -306,9 +311,8 @@ public void writeRequest(NettyResponseFuture future, Channel channel) { if (!future.isHeadersAlreadyWrittenOnContinue()) { try { - if (future.getAsyncHandler() instanceof AsyncHandlerExtensions) { - AsyncHandlerExtensions.class.cast(future.getAsyncHandler()).onRequestSent(); - } + if (future.getAsyncHandler() instanceof AsyncHandlerExtensions) + AsyncHandlerExtensions.class.cast(future.getAsyncHandler()).onSendRequest(); channel.write(httpRequest).addListener(new ProgressListener(config, future.getAsyncHandler(), future, true)); } catch (Throwable cause) { // FIXME why not notify? @@ -481,7 +485,11 @@ private boolean validateWebSocketRequest(Request request, AsyncHandler asyncH return request.getMethod().equals(HttpMethod.GET.getName()) && asyncHandler instanceof WebSocketUpgradeHandler; } - public Channel pollAndVerifyCachedChannel(UriComponents uri, ProxyServer proxy, ConnectionPoolKeyStrategy connectionPoolKeyStrategy) { + public Channel pollAndVerifyCachedChannel(UriComponents uri, ProxyServer proxy, ConnectionPoolKeyStrategy connectionPoolKeyStrategy, AsyncHandler asyncHandler) { + + if (asyncHandler instanceof AsyncHandlerExtensions) + AsyncHandlerExtensions.class.cast(asyncHandler).onPoolConnection(); + final Channel channel = channelManager.poll(connectionPoolKeyStrategy.getKey(uri, proxy)); if (channel != null) { diff --git a/src/main/java/com/ning/http/client/providers/netty/request/body/NettyConnectListener.java b/src/main/java/com/ning/http/client/providers/netty/request/body/NettyConnectListener.java index 051603779c..20c0a34237 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/body/NettyConnectListener.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/body/NettyConnectListener.java @@ -20,6 +20,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.ning.http.client.AsyncHandlerExtensions; import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.providers.netty.channel.ChannelManager; import com.ning.http.client.providers.netty.channel.Channels; @@ -79,6 +80,9 @@ private void writeRequest(Channel channel, String poolKey) { return; } + if (future.getAsyncHandler() instanceof AsyncHandlerExtensions) + AsyncHandlerExtensions.class.cast(future.getAsyncHandler()).onConnectionOpen(); + channelManager.registerOpenChannel(channel); future.attachChannel(channel, false); requestSender.writeRequest(future, channel); From 2e8b098b0e21471d2a3dd1b887ea8eac88fc09e1 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Sat, 23 Aug 2014 15:28:16 +0200 Subject: [PATCH 533/701] Handle Continuation frames, close #674 --- .../http/client/providers/netty/channel/ChannelManager.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java b/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java index b3a1edd15f..c66bef5d7a 100644 --- a/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java +++ b/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java @@ -31,6 +31,7 @@ import org.jboss.netty.handler.codec.http.HttpContentDecompressor; 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.WebSocketFrameAggregator; import org.jboss.netty.handler.ssl.SslHandler; import org.jboss.netty.handler.stream.ChunkedWriteHandler; import org.jboss.netty.util.Timer; @@ -75,6 +76,7 @@ public class ChannelManager { public static final String INFLATER_HANDLER = "inflater"; public static final String CHUNKED_WRITER_HANDLER = "chunkedWriter"; public static final String WS_DECODER_HANDLER = "ws-decoder"; + public static final String WS_FRAME_AGGREGATOR = "ws-aggregator"; public static final String WS_ENCODER_HANDLER = "ws-encoder"; private final AsyncHttpClientConfig config; @@ -418,6 +420,7 @@ public void upgradePipelineForWebSockets(ChannelPipeline pipeline) { pipeline.addAfter(HTTP_HANDLER, WS_ENCODER_HANDLER, new WebSocket08FrameEncoder(true)); pipeline.remove(HTTP_HANDLER); pipeline.addBefore(WS_PROCESSOR, WS_DECODER_HANDLER, new WebSocket08FrameDecoder(false, false, 10 * 1024)); + pipeline.addAfter(WS_DECODER_HANDLER, WS_FRAME_AGGREGATOR, new WebSocketFrameAggregator(10 * 1024)); } public final Callback newDrainCallback(final NettyResponseFuture future, final Channel channel, final boolean keepAlive, From ba442118ca22cc450d24ec5a85105039a7b8ca19 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Sat, 23 Aug 2014 15:39:36 +0200 Subject: [PATCH 534/701] Introduce a config parameter for websocket max frame size, close #675 --- .../providers/netty/NettyAsyncHttpProviderConfig.java | 10 ++++++++++ .../client/providers/netty/channel/ChannelManager.java | 4 ++-- 2 files changed, 12 insertions(+), 2 deletions(-) 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 e308722e5e..f2cfcb3430 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 @@ -135,6 +135,8 @@ public Set> propertiesSet() { private int webSocketMaxBufferSize = 128000000; + private int webSocketMaxFrameSize = 10 * 1024; + public boolean isUseDeadLockChecker() { return useDeadLockChecker; } @@ -246,6 +248,14 @@ public int getWebSocketMaxBufferSize() { public void setWebSocketMaxBufferSize(int webSocketMaxBufferSize) { this.webSocketMaxBufferSize = webSocketMaxBufferSize; } + + public int getWebSocketMaxFrameSize() { + return webSocketMaxFrameSize; + } + + public void setWebSocketMaxFrameSize(int webSocketMaxFrameSize) { + this.webSocketMaxFrameSize = webSocketMaxFrameSize; + } public static interface NettyWebSocketFactory { NettyWebSocket newNettyWebSocket(Channel channel, NettyAsyncHttpProviderConfig nettyConfig); diff --git a/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java b/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java index c66bef5d7a..ab0140d89e 100644 --- a/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java +++ b/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java @@ -419,8 +419,8 @@ public ClientBootstrap getBootstrap(String scheme, boolean useProxy, boolean use public void upgradePipelineForWebSockets(ChannelPipeline pipeline) { pipeline.addAfter(HTTP_HANDLER, WS_ENCODER_HANDLER, new WebSocket08FrameEncoder(true)); pipeline.remove(HTTP_HANDLER); - pipeline.addBefore(WS_PROCESSOR, WS_DECODER_HANDLER, new WebSocket08FrameDecoder(false, false, 10 * 1024)); - pipeline.addAfter(WS_DECODER_HANDLER, WS_FRAME_AGGREGATOR, new WebSocketFrameAggregator(10 * 1024)); + pipeline.addBefore(WS_PROCESSOR, WS_DECODER_HANDLER, new WebSocket08FrameDecoder(false, false, nettyConfig.getWebSocketMaxFrameSize())); + pipeline.addAfter(WS_DECODER_HANDLER, WS_FRAME_AGGREGATOR, new WebSocketFrameAggregator(nettyConfig.getWebSocketMaxBufferSize())); } public final Callback newDrainCallback(final NettyResponseFuture future, final Channel channel, final boolean keepAlive, From fe71206e9e85c32c65e1c712e165939d98264f93 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Sat, 23 Aug 2014 23:52:56 +0200 Subject: [PATCH 535/701] future can be null, directly pass the handler --- .../providers/netty/request/NettyRequestSender.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java index 73fd919a42..9d9c937630 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java @@ -132,7 +132,7 @@ private ListenableFuture sendRequestWithCertainForceConnect(// boolean forceConnect) throws IOException { NettyResponseFuture newFuture = newNettyRequestAndResponseFuture(request, asyncHandler, future, uri, proxyServer, forceConnect); - Channel channel = getCachedChannel(future, uri, request.getConnectionPoolKeyStrategy(), proxyServer); + Channel channel = getCachedChannel(future, uri, request.getConnectionPoolKeyStrategy(), proxyServer, asyncHandler); if (Channels.isChannelValid(channel)) return sendRequestWithCachedChannel(request, uri, proxyServer, newFuture, asyncHandler, channel); @@ -156,7 +156,7 @@ private ListenableFuture sendRequestThroughSslProxy(// NettyResponseFuture newFuture = null; for (int i = 0; i < 3; i++) { - Channel channel = getCachedChannel(future, uri, request.getConnectionPoolKeyStrategy(), proxyServer); + Channel channel = getCachedChannel(future, uri, request.getConnectionPoolKeyStrategy(), proxyServer, asyncHandler); if (Channels.isChannelValid(channel)) if (newFuture == null) newFuture = newNettyRequestAndResponseFuture(request, asyncHandler, future, uri, proxyServer, false); @@ -188,12 +188,12 @@ private NettyResponseFuture newNettyRequestAndResponseFuture(final Reques } private Channel getCachedChannel(NettyResponseFuture future, UriComponents uri, ConnectionPoolKeyStrategy poolKeyGen, - ProxyServer proxyServer) { + ProxyServer proxyServer, AsyncHandler asyncHandler) { if (future != null && future.reuseChannel() && Channels.isChannelValid(future.channel())) return future.channel(); else - return pollAndVerifyCachedChannel(uri, proxyServer, poolKeyGen, future.getAsyncHandler()); + return pollAndVerifyCachedChannel(uri, proxyServer, poolKeyGen, asyncHandler); } private ListenableFuture sendRequestWithCachedChannel(Request request, UriComponents uri, ProxyServer proxy, From bdc1ce575741b5c90eb604bb417d16e09d659ed3 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Sun, 24 Aug 2014 00:01:23 +0200 Subject: [PATCH 536/701] [maven-release-plugin] prepare release async-http-client-1.9.0-BETA7 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 8a64df6dc6..bb23f90708 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.9.0-SNAPSHOT + 1.9.0-BETA7 jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From acb49bdff502970b4c9e9835ddeda24f4683eaa0 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Sun, 24 Aug 2014 00:01:27 +0200 Subject: [PATCH 537/701] [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 bb23f90708..8a64df6dc6 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.9.0-BETA7 + 1.9.0-SNAPSHOT jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From 30973921b2666b7938521c9b7c153fcc4a21d236 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 25 Aug 2014 12:45:12 +0200 Subject: [PATCH 538/701] IdleChannelDetector should remove empty queues, close #676 --- .../netty/channel/pool/DefaultChannelPool.java | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/channel/pool/DefaultChannelPool.java b/src/main/java/com/ning/http/client/providers/netty/channel/pool/DefaultChannelPool.java index 225b4260e7..5d1e3981cd 100644 --- a/src/main/java/com/ning/http/client/providers/netty/channel/pool/DefaultChannelPool.java +++ b/src/main/java/com/ning/http/client/providers/netty/channel/pool/DefaultChannelPool.java @@ -29,6 +29,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.TimeUnit; @@ -194,15 +195,21 @@ public void run(Timeout timeout) throws Exception { int closedCount = 0; int totalCount = 0; - for (ConcurrentLinkedQueue pool : poolsPerKey.values()) { + for (Map.Entry> entry : poolsPerKey.entrySet()) { + + String poolKey = entry.getKey(); + ConcurrentLinkedQueue pool = entry.getValue(); + // store in intermediate unsynchronized lists to minimize the impact on the ConcurrentLinkedQueue if (LOGGER.isDebugEnabled()) totalCount += pool.size(); List closedChannels = closeChannels(expiredChannels(pool, start)); + pool.removeAll(closedChannels); - int poolClosedCount = closedChannels.size(); - closedCount += poolClosedCount; + closedCount += closedChannels.size(); + if (pool.isEmpty()) + poolsPerKey.remove(poolKey); } long duration = millisTime() - start; From 0aa1ca0f4b066855e14d8b89ce9cf795dd6bd516 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 25 Aug 2014 13:47:45 +0200 Subject: [PATCH 539/701] Add UriComponents.toRelativeUrl, close #677 --- .../com/ning/http/client/uri/UriComponents.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/main/java/com/ning/http/client/uri/UriComponents.java b/src/main/java/com/ning/http/client/uri/UriComponents.java index 84202d6efd..40916490e6 100644 --- a/src/main/java/com/ning/http/client/uri/UriComponents.java +++ b/src/main/java/com/ning/http/client/uri/UriComponents.java @@ -13,6 +13,8 @@ */ package com.ning.http.client.uri; +import com.ning.http.util.MiscUtils; + import java.net.URI; import java.net.URISyntaxException; @@ -105,6 +107,18 @@ public String toUrl() { return sb.toString(); } + public String toRelativeUrl() { + StringBuilder sb = new StringBuilder(); + if (MiscUtils.isNonEmpty(path)) + sb.append(path); + else + sb.append('/'); + if (query != null) + sb.append('?').append(query); + + return sb.toString(); + } + @Override public String toString() { // for now, but might change From ad96be09d3a6012e01915490e623165a18101b98 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 25 Aug 2014 16:05:51 +0200 Subject: [PATCH 540/701] [maven-release-plugin] prepare release async-http-client-1.9.0-BETA8 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 8a64df6dc6..81c4bd3d7e 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.9.0-SNAPSHOT + 1.9.0-BETA8 jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From d0776dc1054af6ef2b59eb8595f45f85f27ff6a8 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 25 Aug 2014 16:05:55 +0200 Subject: [PATCH 541/701] [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 81c4bd3d7e..8a64df6dc6 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.9.0-BETA8 + 1.9.0-SNAPSHOT jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From 7716af5f6b107523ec4a6b079b7d9457030caf41 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 25 Aug 2014 21:46:15 +0200 Subject: [PATCH 542/701] Fix NPE caused by #676, close #678 --- .../netty/channel/pool/DefaultChannelPool.java | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/channel/pool/DefaultChannelPool.java b/src/main/java/com/ning/http/client/providers/netty/channel/pool/DefaultChannelPool.java index 5d1e3981cd..7964bab403 100644 --- a/src/main/java/com/ning/http/client/providers/netty/channel/pool/DefaultChannelPool.java +++ b/src/main/java/com/ning/http/client/providers/netty/channel/pool/DefaultChannelPool.java @@ -29,7 +29,6 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; -import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.TimeUnit; @@ -195,10 +194,7 @@ public void run(Timeout timeout) throws Exception { int closedCount = 0; int totalCount = 0; - for (Map.Entry> entry : poolsPerKey.entrySet()) { - - String poolKey = entry.getKey(); - ConcurrentLinkedQueue pool = entry.getValue(); + for (ConcurrentLinkedQueue pool : poolsPerKey.values()) { // store in intermediate unsynchronized lists to minimize the impact on the ConcurrentLinkedQueue if (LOGGER.isDebugEnabled()) @@ -206,10 +202,13 @@ public void run(Timeout timeout) throws Exception { List closedChannels = closeChannels(expiredChannels(pool, start)); - pool.removeAll(closedChannels); - closedCount += closedChannels.size(); - if (pool.isEmpty()) - poolsPerKey.remove(poolKey); + if (!closedChannels.isEmpty()) { + for (IdleChannel closedChannel : closedChannels) + channelId2Creation.remove(closedChannel.channel.getId()); + + pool.removeAll(closedChannels); + closedCount += closedChannels.size(); + } } long duration = millisTime() - start; From c14ade2da712bce3a6928f6c110bf44e6586e5d0 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 25 Aug 2014 21:53:57 +0200 Subject: [PATCH 543/701] [maven-release-plugin] prepare release async-http-client-1.9.0-BETA9 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 8a64df6dc6..fa911b2e66 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.9.0-SNAPSHOT + 1.9.0-BETA9 jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From 5bfa8b6482514f3bda467435f699d81d198c8138 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 25 Aug 2014 21:54:01 +0200 Subject: [PATCH 544/701] [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 fa911b2e66..8a64df6dc6 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.9.0-BETA9 + 1.9.0-SNAPSHOT jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From 80d0853af7a91ffcdb234865cdd1667c9b873bb2 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 26 Aug 2014 15:16:39 +0200 Subject: [PATCH 545/701] UriComponent doesn't properly handle ./ relative urls, close #680 --- src/main/java/com/ning/http/client/uri/UriComponentsParser.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/ning/http/client/uri/UriComponentsParser.java b/src/main/java/com/ning/http/client/uri/UriComponentsParser.java index 54daefeeab..930b893592 100644 --- a/src/main/java/com/ning/http/client/uri/UriComponentsParser.java +++ b/src/main/java/com/ning/http/client/uri/UriComponentsParser.java @@ -201,7 +201,7 @@ private void computeRegularHostPort() { // /./ private void removeEmbeddedDot() { - path = path.replace("/./", ""); + path = path.replace("/./", "/"); } // /../ From 5f53e1c6cb5caa53e02e27356e3cace5700398c5 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 27 Aug 2014 12:26:52 +0200 Subject: [PATCH 546/701] Fix ChannelManager.closeChannel NPE, close #681 --- .../http/client/providers/netty/channel/ChannelManager.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java b/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java index ab0140d89e..a1d1a8d751 100644 --- a/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java +++ b/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java @@ -315,13 +315,13 @@ public void close() { } public void closeChannel(Channel channel) { - removeAll(channel); - Channels.setDiscard(channel); - // The channel may have already been removed if a timeout occurred, and this method may be called just after. + // The channel may have already been removed from the future if a timeout occurred, and this method may be called just after. if (channel != null) { LOGGER.debug("Closing Channel {} ", channel); try { + removeAll(channel); + Channels.setDiscard(channel); channel.close(); } catch (Throwable t) { LOGGER.debug("Error closing a connection", t); From b19102defcaaff9d67398cb5e43fec2f16305770 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 27 Aug 2014 12:41:59 +0200 Subject: [PATCH 547/701] Change Protocol method to directly use a NettyResponseFuture --- .../providers/netty/handler/HttpProtocol.java | 4 +-- .../providers/netty/handler/Processor.java | 5 ++-- .../providers/netty/handler/Protocol.java | 4 +-- .../netty/handler/WebSocketProtocol.java | 25 ++++++------------- 4 files changed, 13 insertions(+), 25 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/handler/HttpProtocol.java b/src/main/java/com/ning/http/client/providers/netty/handler/HttpProtocol.java index 706b4a1b98..0da6010e62 100644 --- a/src/main/java/com/ning/http/client/providers/netty/handler/HttpProtocol.java +++ b/src/main/java/com/ning/http/client/providers/netty/handler/HttpProtocol.java @@ -474,9 +474,9 @@ public void handle(final Channel channel, final NettyResponseFuture future, f } } - public void onError(Channel channel, Throwable e) { + public void onError(NettyResponseFuture future, Throwable e) { } - public void onClose(Channel channel) { + public void onClose(NettyResponseFuture future) { } } diff --git a/src/main/java/com/ning/http/client/providers/netty/handler/Processor.java b/src/main/java/com/ning/http/client/providers/netty/handler/Processor.java index 03f19d4a4d..56515fa711 100644 --- a/src/main/java/com/ning/http/client/providers/netty/handler/Processor.java +++ b/src/main/java/com/ning/http/client/providers/netty/handler/Processor.java @@ -133,7 +133,7 @@ public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws && requestSender.applyIoExceptionFiltersAndReplayRequest(future, CHANNEL_CLOSED_EXCEPTION, channel)) return; - protocol.onClose(channel); + protocol.onClose(future); if (future == null || future.isDone()) channelManager.closeChannel(channel); @@ -193,12 +193,11 @@ public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws try { LOGGER.debug("Was unable to recover Future: {}", future); requestSender.abort(future, cause); + protocol.onError(future, e.getCause()); } catch (Throwable t) { LOGGER.error(t.getMessage(), t); } - protocol.onError(channel, e.getCause()); - channelManager.closeChannel(channel); ctx.sendUpstream(e); } diff --git a/src/main/java/com/ning/http/client/providers/netty/handler/Protocol.java b/src/main/java/com/ning/http/client/providers/netty/handler/Protocol.java index e03e2b1d60..822795720e 100644 --- a/src/main/java/com/ning/http/client/providers/netty/handler/Protocol.java +++ b/src/main/java/com/ning/http/client/providers/netty/handler/Protocol.java @@ -87,9 +87,9 @@ public Protocol(ChannelManager channelManager, AsyncHttpClientConfig config, Net public abstract void handle(Channel channel, NettyResponseFuture future, Object message) throws Exception; - public abstract void onError(Channel channel, Throwable e); + public abstract void onError(NettyResponseFuture future, Throwable e); - public abstract void onClose(Channel channel); + public abstract void onClose(NettyResponseFuture future); protected boolean exitAfterHandlingRedirect(// Channel channel,// diff --git a/src/main/java/com/ning/http/client/providers/netty/handler/WebSocketProtocol.java b/src/main/java/com/ning/http/client/providers/netty/handler/WebSocketProtocol.java index 601d885137..b6ada05d31 100644 --- a/src/main/java/com/ning/http/client/providers/netty/handler/WebSocketProtocol.java +++ b/src/main/java/com/ning/http/client/providers/netty/handler/WebSocketProtocol.java @@ -33,7 +33,6 @@ import com.ning.http.client.HttpResponseHeaders; import com.ning.http.client.HttpResponseStatus; import com.ning.http.client.Request; -import com.ning.http.client.providers.netty.DiscardEvent; import com.ning.http.client.providers.netty.NettyAsyncHttpProviderConfig; import com.ning.http.client.providers.netty.channel.ChannelManager; import com.ning.http.client.providers.netty.channel.Channels; @@ -177,16 +176,11 @@ public void setContent(ChannelBuffer content) { } @Override - public void onError(Channel channel, Throwable e) { - try { - Object attribute = Channels.getAttribute(channel); - logger.warn("onError {}", e); - if (!(attribute instanceof NettyResponseFuture)) { - return; - } + public void onError(NettyResponseFuture future, Throwable e) { + logger.warn("onError {}", e); - NettyResponseFuture nettyResponse = (NettyResponseFuture) attribute; - WebSocketUpgradeHandler h = WebSocketUpgradeHandler.class.cast(nettyResponse.getAsyncHandler()); + try { + WebSocketUpgradeHandler h = (WebSocketUpgradeHandler) future.getAsyncHandler(); NettyWebSocket webSocket = NettyWebSocket.class.cast(h.onCompleted()); if (webSocket != null) { @@ -199,20 +193,15 @@ public void onError(Channel channel, Throwable e) { } @Override - public void onClose(Channel channel) { + public void onClose(NettyResponseFuture future) { logger.trace("onClose {}"); - Object attribute = Channels.getAttribute(channel); - if (!(attribute instanceof NettyResponseFuture)) - return; try { - NettyResponseFuture nettyResponse = NettyResponseFuture.class.cast(attribute); - WebSocketUpgradeHandler h = WebSocketUpgradeHandler.class.cast(nettyResponse.getAsyncHandler()); + WebSocketUpgradeHandler h = (WebSocketUpgradeHandler) future.getAsyncHandler(); NettyWebSocket webSocket = NettyWebSocket.class.cast(h.onCompleted()); - // FIXME How could this test not succeed, we just checked above that attribute is a NettyResponseFuture???? logger.trace("Connection was closed abnormally (that is, with no close frame being sent)."); - if (attribute != DiscardEvent.INSTANCE && webSocket != null) + if (webSocket != null) webSocket.close(1006, "Connection was closed abnormally (that is, with no close frame being sent)."); } catch (Throwable t) { logger.error("onError", t); From c1d8e1af8ded940be1c841d5d1d3320948e4abea Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 27 Aug 2014 12:50:56 +0200 Subject: [PATCH 548/701] Actually, the channel is never null --- .../netty/channel/ChannelManager.java | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java b/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java index a1d1a8d751..9be11a691e 100644 --- a/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java +++ b/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java @@ -317,17 +317,15 @@ public void close() { public void closeChannel(Channel channel) { // The channel may have already been removed from the future if a timeout occurred, and this method may be called just after. - if (channel != null) { - LOGGER.debug("Closing Channel {} ", channel); - try { - removeAll(channel); - Channels.setDiscard(channel); - channel.close(); - } catch (Throwable t) { - LOGGER.debug("Error closing a connection", t); - } - openChannels.remove(channel); + LOGGER.debug("Closing Channel {} ", channel); + try { + removeAll(channel); + Channels.setDiscard(channel); + channel.close(); + } catch (Throwable t) { + LOGGER.debug("Error closing a connection", t); } + openChannels.remove(channel); } public void abortChannelPreemption(String poolKey) { From 3c4e252a93c98af9ed2cd981c1ae91e66d9a9cf1 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 27 Aug 2014 12:54:15 +0200 Subject: [PATCH 549/701] comments --- .../ning/http/client/providers/netty/handler/HttpProtocol.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/handler/HttpProtocol.java b/src/main/java/com/ning/http/client/providers/netty/handler/HttpProtocol.java index 0da6010e62..f56ff1bc25 100644 --- a/src/main/java/com/ning/http/client/providers/netty/handler/HttpProtocol.java +++ b/src/main/java/com/ning/http/client/providers/netty/handler/HttpProtocol.java @@ -442,8 +442,9 @@ public void handle(final Channel channel, final NettyResponseFuture future, f future.touch(); - // The connect timeout occurred. + // future is already done because of an exception or a timeout if (future.isDone()) { + // FIXME isn't the channel already properly closed? channelManager.closeChannel(channel); return; } From 0900f0d8e57011a9a94849924160fcb1997fd3c4 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 27 Aug 2014 12:54:25 +0200 Subject: [PATCH 550/701] The future isn't null here --- .../com/ning/http/client/providers/netty/handler/Processor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/handler/Processor.java b/src/main/java/com/ning/http/client/providers/netty/handler/Processor.java index 56515fa711..84a3e1318a 100644 --- a/src/main/java/com/ning/http/client/providers/netty/handler/Processor.java +++ b/src/main/java/com/ning/http/client/providers/netty/handler/Processor.java @@ -135,7 +135,7 @@ public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws protocol.onClose(future); - if (future == null || future.isDone()) + if (future.isDone()) channelManager.closeChannel(channel); else if (!requestSender.retry(future, ctx.getChannel())) From 3489bcf6885eec3db378d8b7e531aec98976a0f9 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 27 Aug 2014 13:07:39 +0200 Subject: [PATCH 551/701] NettyRequestSender.retry: future isn't null --- .../client/providers/netty/handler/Processor.java | 2 +- .../providers/netty/request/NettyRequestSender.java | 13 +++---------- .../netty/request/body/NettyConnectListener.java | 2 +- 3 files changed, 5 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/handler/Processor.java b/src/main/java/com/ning/http/client/providers/netty/handler/Processor.java index 84a3e1318a..7583115178 100644 --- a/src/main/java/com/ning/http/client/providers/netty/handler/Processor.java +++ b/src/main/java/com/ning/http/client/providers/netty/handler/Processor.java @@ -138,7 +138,7 @@ public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws if (future.isDone()) channelManager.closeChannel(channel); - else if (!requestSender.retry(future, ctx.getChannel())) + else if (!requestSender.retry(future)) requestSender.abort(future, REMOTELY_CLOSED_EXCEPTION); } } diff --git a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java index 9d9c937630..483c942ad2 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java @@ -408,12 +408,11 @@ public void abort(NettyResponseFuture future, Throwable t) { if (!future.isDone()) { LOGGER.debug("Aborting Future {}\n", future); LOGGER.debug(t.getMessage(), t); + future.abort(t); } - - future.abort(t); } - public boolean retry(NettyResponseFuture future, Channel channel) { + public boolean retry(NettyResponseFuture future) { if (isClosed()) return false; @@ -421,13 +420,7 @@ public boolean retry(NettyResponseFuture future, Channel channel) { // FIXME this was done in AHC2, is this a bug? // channelManager.removeAll(channel); - if (future == null) { - Object attribute = Channels.getAttribute(channel); - if (attribute instanceof NettyResponseFuture) - future = (NettyResponseFuture) attribute; - } - - if (future != null && future.canBeReplayed()) { + if (future.canBeReplayed()) { future.setState(NettyResponseFuture.STATE.RECONNECTED); LOGGER.debug("Trying to recover request {}\n", future.getNettyRequest().getHttpRequest()); diff --git a/src/main/java/com/ning/http/client/providers/netty/request/body/NettyConnectListener.java b/src/main/java/com/ning/http/client/providers/netty/request/body/NettyConnectListener.java index 20c0a34237..dfb2ac609e 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/body/NettyConnectListener.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/body/NettyConnectListener.java @@ -133,7 +133,7 @@ public void operationComplete(ChannelFuture handshakeFuture) throws Exception { && cause != null && (cause instanceof ClosedChannelException || future.getState() != NettyResponseFuture.STATE.NEW || StackTraceInspector.abortOnDisconnectException(cause))) { - if (!requestSender.retry(future, channel)) + if (!requestSender.retry(future)) return; } From 5c63a97cd0ca691c92e495fa37ae5d5b1e8f304b Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 27 Aug 2014 13:32:28 +0200 Subject: [PATCH 552/701] Clean up TimeoutTasks content when cancelling, close #682 --- .../http/client/providers/netty/handler/Processor.java | 1 + .../netty/request/timeout/TimeoutTimerTask.java | 10 +++++++++- .../netty/request/timeout/TimeoutsHolder.java | 2 ++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/handler/Processor.java b/src/main/java/com/ning/http/client/providers/netty/handler/Processor.java index 7583115178..d4549178dd 100644 --- a/src/main/java/com/ning/http/client/providers/netty/handler/Processor.java +++ b/src/main/java/com/ning/http/client/providers/netty/handler/Processor.java @@ -178,6 +178,7 @@ public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws } } + // FIXME how does recovery occur?! if (StackTraceInspector.abortOnReadOrWriteException(cause)) { LOGGER.debug("Trying to recover from dead Channel: {}", channel); return; diff --git a/src/main/java/com/ning/http/client/providers/netty/request/timeout/TimeoutTimerTask.java b/src/main/java/com/ning/http/client/providers/netty/request/timeout/TimeoutTimerTask.java index bebd559616..ba2f99cd57 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/timeout/TimeoutTimerTask.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/timeout/TimeoutTimerTask.java @@ -25,7 +25,7 @@ public abstract class TimeoutTimerTask implements TimerTask { private static final Logger LOGGER = LoggerFactory.getLogger(TimeoutTimerTask.class); - protected final NettyResponseFuture nettyResponseFuture; + protected volatile NettyResponseFuture nettyResponseFuture; protected final NettyRequestSender requestSender; protected final TimeoutsHolder timeoutsHolder; @@ -39,4 +39,12 @@ protected void expire(String message, long time) { LOGGER.debug("{} for {} after {} ms", message, nettyResponseFuture, time); requestSender.abort(nettyResponseFuture, new TimeoutException(message)); } + + /** + * When the timeout is cancelled, it could still be referenced for quite some time in the Timer. + * Holding a reference to the future might mean holding a reference to the channel, and heavy objects such as SslEngines + */ + public void clean() { + nettyResponseFuture = null; + } } diff --git a/src/main/java/com/ning/http/client/providers/netty/request/timeout/TimeoutsHolder.java b/src/main/java/com/ning/http/client/providers/netty/request/timeout/TimeoutsHolder.java index e062c45207..bacee0566e 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/timeout/TimeoutsHolder.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/timeout/TimeoutsHolder.java @@ -26,10 +26,12 @@ public void cancel() { if (cancelled.compareAndSet(false, true)) { if (requestTimeout != null) { requestTimeout.cancel(); + RequestTimeoutTimerTask.class.cast(requestTimeout.getTask()).clean(); requestTimeout = null; } if (readTimeout != null) { readTimeout.cancel(); + ReadTimeoutTimerTask.class.cast(readTimeout.getTask()).clean(); readTimeout = null; } } From a2c19ed29326cb366c91340d3e82e3a848b7693f Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 27 Aug 2014 14:21:51 +0200 Subject: [PATCH 553/701] you never know... --- .../providers/netty/request/timeout/ReadTimeoutTimerTask.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/com/ning/http/client/providers/netty/request/timeout/ReadTimeoutTimerTask.java b/src/main/java/com/ning/http/client/providers/netty/request/timeout/ReadTimeoutTimerTask.java index bdfa842b23..6fb1c96b7a 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/timeout/ReadTimeoutTimerTask.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/timeout/ReadTimeoutTimerTask.java @@ -61,5 +61,7 @@ public void run(Timeout timeout) throws Exception { // otherwise, no need to reschedule: requestTimeout will happen sooner timeoutsHolder.readTimeout = null; } + + clean(); } } From a74e1da41e9a041790d034f4114ed14e7ab6e206 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 27 Aug 2014 14:29:06 +0200 Subject: [PATCH 554/701] dead code --- .../client/providers/netty/future/NettyResponseFuture.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/future/NettyResponseFuture.java b/src/main/java/com/ning/http/client/providers/netty/future/NettyResponseFuture.java index 818fd5d5d6..f7fc1efe9e 100755 --- a/src/main/java/com/ning/http/client/providers/netty/future/NettyResponseFuture.java +++ b/src/main/java/com/ning/http/client/providers/netty/future/NettyResponseFuture.java @@ -388,10 +388,6 @@ public boolean isDontWriteBodyBecauseExpectContinue() { return dontWriteBodyBecauseExpectContinue; } - public void attachChannel(Channel channel) { - this.channel = channel; - } - public void setReuseChannel(boolean reuseChannel) { this.reuseChannel = reuseChannel; } From d645f92616fad67bd3ee628f8f786a748b10fb27 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 27 Aug 2014 14:32:52 +0200 Subject: [PATCH 555/701] Move NettyConnectListener to proper package --- .../netty/request/{body => }/NettyConnectListener.java | 3 +-- .../client/providers/netty/request/NettyRequestSender.java | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) rename src/main/java/com/ning/http/client/providers/netty/request/{body => }/NettyConnectListener.java (98%) diff --git a/src/main/java/com/ning/http/client/providers/netty/request/body/NettyConnectListener.java b/src/main/java/com/ning/http/client/providers/netty/request/NettyConnectListener.java similarity index 98% rename from src/main/java/com/ning/http/client/providers/netty/request/body/NettyConnectListener.java rename to src/main/java/com/ning/http/client/providers/netty/request/NettyConnectListener.java index dfb2ac609e..45fe22fd81 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/body/NettyConnectListener.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/NettyConnectListener.java @@ -11,7 +11,7 @@ * "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.providers.netty.request.body; +package com.ning.http.client.providers.netty.request; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFuture; @@ -26,7 +26,6 @@ import com.ning.http.client.providers.netty.channel.Channels; import com.ning.http.client.providers.netty.future.NettyResponseFuture; import com.ning.http.client.providers.netty.future.StackTraceInspector; -import com.ning.http.client.providers.netty.request.NettyRequestSender; import com.ning.http.util.Base64; import javax.net.ssl.HostnameVerifier; diff --git a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java index 483c942ad2..aa6eba9323 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java @@ -48,7 +48,6 @@ import com.ning.http.client.providers.netty.channel.ChannelManager; import com.ning.http.client.providers.netty.channel.Channels; import com.ning.http.client.providers.netty.future.NettyResponseFuture; -import com.ning.http.client.providers.netty.request.body.NettyConnectListener; import com.ning.http.client.providers.netty.request.timeout.ReadTimeoutTimerTask; import com.ning.http.client.providers.netty.request.timeout.RequestTimeoutTimerTask; import com.ning.http.client.providers.netty.request.timeout.TimeoutsHolder; From 756ed8110312ace62f2934550cd8301920ede2d5 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 27 Aug 2014 14:34:09 +0200 Subject: [PATCH 556/701] Move FeedableBodyGenerator to proper package --- .../netty/request/{ => body}/FeedableBodyGenerator.java | 2 +- .../client/providers/netty/request/body/NettyBodyBody.java | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) rename src/main/java/com/ning/http/client/providers/netty/request/{ => body}/FeedableBodyGenerator.java (98%) diff --git a/src/main/java/com/ning/http/client/providers/netty/request/FeedableBodyGenerator.java b/src/main/java/com/ning/http/client/providers/netty/request/body/FeedableBodyGenerator.java similarity index 98% rename from src/main/java/com/ning/http/client/providers/netty/request/FeedableBodyGenerator.java rename to src/main/java/com/ning/http/client/providers/netty/request/body/FeedableBodyGenerator.java index 0bd84a182a..14c9320c93 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/FeedableBodyGenerator.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/body/FeedableBodyGenerator.java @@ -11,7 +11,7 @@ * "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.providers.netty.request; +package com.ning.http.client.providers.netty.request.body; import com.ning.http.client.Body; import com.ning.http.client.BodyGenerator; diff --git a/src/main/java/com/ning/http/client/providers/netty/request/body/NettyBodyBody.java b/src/main/java/com/ning/http/client/providers/netty/request/body/NettyBodyBody.java index a31ca32b1d..3c63f6c847 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/body/NettyBodyBody.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/body/NettyBodyBody.java @@ -26,8 +26,7 @@ import com.ning.http.client.providers.netty.NettyAsyncHttpProviderConfig; import com.ning.http.client.providers.netty.channel.ChannelManager; import com.ning.http.client.providers.netty.future.NettyResponseFuture; -import com.ning.http.client.providers.netty.request.FeedableBodyGenerator; -import com.ning.http.client.providers.netty.request.FeedableBodyGenerator.FeedListener; +import com.ning.http.client.providers.netty.request.body.FeedableBodyGenerator.FeedListener; import com.ning.http.client.providers.netty.request.ProgressListener; import java.io.IOException; From 5e3b688de2c8e204abf7fa87276b32f4d59d55a7 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 27 Aug 2014 14:52:25 +0200 Subject: [PATCH 557/701] minor clean up --- .../http/client/providers/netty/handler/Processor.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/handler/Processor.java b/src/main/java/com/ning/http/client/providers/netty/handler/Processor.java index d4549178dd..d5879ee01b 100644 --- a/src/main/java/com/ning/http/client/providers/netty/handler/Processor.java +++ b/src/main/java/com/ning/http/client/providers/netty/handler/Processor.java @@ -164,18 +164,17 @@ public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws if (cause instanceof IOException) { // FIXME why drop the original exception and throw a new one? - if (!config.getIOExceptionFilters().isEmpty()) - if (requestSender.applyIoExceptionFiltersAndReplayRequest(future, CHANNEL_CLOSED_EXCEPTION, channel)) - return; - else { + if (!config.getIOExceptionFilters().isEmpty()) { + if (!requestSender.applyIoExceptionFiltersAndReplayRequest(future, CHANNEL_CLOSED_EXCEPTION, channel)) { // Close the channel so the recovering can occurs. try { channel.close(); } catch (Throwable t) { // Swallow. } - return; } + return; + } } // FIXME how does recovery occur?! From 3876f639bbddcc7d36cf7bd7f9ebb5a200a5b156 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 27 Aug 2014 17:03:48 +0200 Subject: [PATCH 558/701] Properly clean up timeouts --- .../providers/netty/handler/HttpProtocol.java | 23 ++++++---- .../providers/netty/handler/Processor.java | 4 +- .../providers/netty/handler/Protocol.java | 2 +- .../netty/handler/WebSocketProtocol.java | 4 +- .../netty/request/NettyRequestSender.java | 44 ++++++++----------- .../request/timeout/ReadTimeoutTimerTask.java | 13 ++++-- .../timeout/RequestTimeoutTimerTask.java | 12 +++-- .../request/timeout/TimeoutTimerTask.java | 10 ++++- 8 files changed, 66 insertions(+), 46 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/handler/HttpProtocol.java b/src/main/java/com/ning/http/client/providers/netty/handler/HttpProtocol.java index f56ff1bc25..8e92b16042 100644 --- a/src/main/java/com/ning/http/client/providers/netty/handler/HttpProtocol.java +++ b/src/main/java/com/ning/http/client/providers/netty/handler/HttpProtocol.java @@ -65,8 +65,14 @@ private Realm.RealmBuilder newRealmBuilder(Realm realm) { return realm != null ? new Realm.RealmBuilder().clone(realm) : new Realm.RealmBuilder(); } - private Realm kerberosChallenge(List proxyAuth, Request request, ProxyServer proxyServer, - FluentCaseInsensitiveStringsMap headers, Realm realm, NettyResponseFuture future, boolean proxyInd) + private Realm kerberosChallenge(Channel channel,// + List proxyAuth,// + Request request,// + ProxyServer proxyServer,// + FluentCaseInsensitiveStringsMap headers,// + Realm realm,// + NettyResponseFuture future,// + boolean proxyInd) throws NTLMEngineException { UriComponents uri = request.getURI(); @@ -87,7 +93,7 @@ private Realm kerberosChallenge(List proxyAuth, Request request, ProxySe if (isNTLM(proxyAuth)) { return ntlmChallenge(proxyAuth, request, proxyServer, headers, realm, future, proxyInd); } - requestSender.abort(future, throwable); + requestSender.abort(channel, future, throwable); return null; } } @@ -217,7 +223,7 @@ private boolean exitAfterHandling401(// newRealm = ntlmChallenge(wwwAuthHeaders, request, proxyServer, requestHeaders, realm, future, false); } else if (negociate) { // SPNEGO KERBEROS - newRealm = kerberosChallenge(wwwAuthHeaders, request, proxyServer, requestHeaders, realm, future, false); + newRealm = kerberosChallenge(channel, wwwAuthHeaders, request, proxyServer, requestHeaders, realm, future, false); if (newRealm == null) return true; @@ -270,6 +276,7 @@ private boolean exitAfterHandling100(final Channel channel, final NettyResponseF } private boolean exitAfterHandling407(// + Channel channel,// NettyResponseFuture future,// HttpResponse response,// Request request,// @@ -293,7 +300,7 @@ private boolean exitAfterHandling407(// newRealm = ntlmProxyChallenge(proxyAuthHeaders, request, proxyServer, requestHeaders, realm, future, true); // SPNEGO KERBEROS } else if (negociate) { - newRealm = kerberosChallenge(proxyAuthHeaders, request, proxyServer, requestHeaders, realm, future, true); + newRealm = kerberosChallenge(channel, proxyAuthHeaders, request, proxyServer, requestHeaders, realm, future, true); if (newRealm == null) return true; } else { @@ -340,7 +347,7 @@ private boolean exitAfterHandlingConnect(// channelManager.upgradeProtocol(channel.getPipeline(), scheme, host, port); } catch (Throwable ex) { - requestSender.abort(future, ex); + requestSender.abort(channel, future, ex); } future.setReuseChannel(true); @@ -407,7 +414,7 @@ private boolean handleHttpResponse(final HttpResponse response,// return exitAfterProcessingFilters(channel, future, handler, status, responseHeaders) || exitAfterHandling401(channel, future, response, request, statusCode, realm, proxyServer) || // - exitAfterHandling407(future, response, request, statusCode, realm, proxyServer) || // + exitAfterHandling407(channel, future, response, request, statusCode, realm, proxyServer) || // exitAfterHandling100(channel, future, statusCode) || // exitAfterHandlingRedirect(channel, future, response, request, statusCode) || // exitAfterHandlingConnect(channel, future, request, proxyServer, statusCode, httpRequest) || // @@ -465,7 +472,7 @@ public void handle(final Channel channel, final NettyResponseFuture future, f } try { - requestSender.abort(future, t); + requestSender.abort(channel, future, t); } catch (Exception abortException) { logger.debug("Abort failed", abortException); } finally { diff --git a/src/main/java/com/ning/http/client/providers/netty/handler/Processor.java b/src/main/java/com/ning/http/client/providers/netty/handler/Processor.java index d5879ee01b..d8cd101865 100644 --- a/src/main/java/com/ning/http/client/providers/netty/handler/Processor.java +++ b/src/main/java/com/ning/http/client/providers/netty/handler/Processor.java @@ -139,7 +139,7 @@ public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws channelManager.closeChannel(channel); else if (!requestSender.retry(future)) - requestSender.abort(future, REMOTELY_CLOSED_EXCEPTION); + requestSender.abort(channel, future, REMOTELY_CLOSED_EXCEPTION); } } @@ -192,7 +192,7 @@ public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws if (future != null) try { LOGGER.debug("Was unable to recover Future: {}", future); - requestSender.abort(future, cause); + requestSender.abort(channel, future, cause); protocol.onError(future, e.getCause()); } catch (Throwable t) { LOGGER.error(t.getMessage(), t); diff --git a/src/main/java/com/ning/http/client/providers/netty/handler/Protocol.java b/src/main/java/com/ning/http/client/providers/netty/handler/Protocol.java index 822795720e..00728c06a8 100644 --- a/src/main/java/com/ning/http/client/providers/netty/handler/Protocol.java +++ b/src/main/java/com/ning/http/client/providers/netty/handler/Protocol.java @@ -182,7 +182,7 @@ protected boolean exitAfterProcessingFilters(// throw new NullPointerException("FilterContext is null"); } } catch (FilterException efe) { - requestSender.abort(future, efe); + requestSender.abort(channel, future, efe); } } diff --git a/src/main/java/com/ning/http/client/providers/netty/handler/WebSocketProtocol.java b/src/main/java/com/ning/http/client/providers/netty/handler/WebSocketProtocol.java index b6ada05d31..6548363c79 100644 --- a/src/main/java/com/ning/http/client/providers/netty/handler/WebSocketProtocol.java +++ b/src/main/java/com/ning/http/client/providers/netty/handler/WebSocketProtocol.java @@ -107,14 +107,14 @@ public void handle(Channel channel, NettyResponseFuture future, Object e) thr final boolean headerOK = handler.onHeadersReceived(responseHeaders) == STATE.CONTINUE; if (!headerOK || !validStatus || !validUpgrade || !validConnection) { - requestSender.abort(future, new IOException("Invalid handshake response")); + requestSender.abort(channel, future, new IOException("Invalid handshake response")); return; } String accept = response.headers().get(HttpHeaders.Names.SEC_WEBSOCKET_ACCEPT); String key = getAcceptKey(future.getNettyRequest().getHttpRequest().headers().get(HttpHeaders.Names.SEC_WEBSOCKET_KEY)); if (accept == null || !accept.equals(key)) { - requestSender.abort(future, new IOException(String.format("Invalid challenge. Actual: %s. Expected: %s", accept, key))); + requestSender.abort(channel, future, new IOException(String.format("Invalid challenge. Actual: %s. Expected: %s", accept, key))); } channelManager.upgradePipelineForWebSockets(channel.getPipeline()); diff --git a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java index aa6eba9323..5c66ce5b79 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java @@ -57,7 +57,6 @@ import java.io.IOException; import java.net.InetSocketAddress; import java.util.Map; -import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; @@ -269,7 +268,7 @@ private ListenableFuture sendRequestWithNewChannel(// if (channelPreempted) channelManager.abortChannelPreemption(poolKey); - abort(future, t.getCause() == null ? t : t.getCause()); + abort(null, future, t.getCause() == null ? t : t.getCause()); } return future; @@ -371,36 +370,31 @@ private void configureTransferAdapter(AsyncHandler handler, HttpRequest httpR private void scheduleTimeouts(NettyResponseFuture nettyResponseFuture) { - try { - nettyResponseFuture.touch(); - int requestTimeoutInMs = requestTimeout(config, nettyResponseFuture.getRequest()); - TimeoutsHolder timeoutsHolder = new TimeoutsHolder(); - if (requestTimeoutInMs != -1) { - Timeout requestTimeout = newTimeout(new RequestTimeoutTimerTask(nettyResponseFuture, this, timeoutsHolder, - requestTimeoutInMs), requestTimeoutInMs); - timeoutsHolder.requestTimeout = requestTimeout; - } + nettyResponseFuture.touch(); + int requestTimeoutInMs = requestTimeout(config, nettyResponseFuture.getRequest()); + TimeoutsHolder timeoutsHolder = new TimeoutsHolder(); + if (requestTimeoutInMs != -1) { + Timeout requestTimeout = newTimeout(new RequestTimeoutTimerTask(nettyResponseFuture, this, timeoutsHolder, + requestTimeoutInMs), requestTimeoutInMs); + timeoutsHolder.requestTimeout = requestTimeout; + } - int readTimeout = config.getReadTimeout(); - if (readTimeout != -1 && readTimeout < requestTimeoutInMs) { - // no need for a idleConnectionTimeout that's less than the - // requestTimeoutInMs - Timeout idleConnectionTimeout = newTimeout(new ReadTimeoutTimerTask(nettyResponseFuture, this, timeoutsHolder, - requestTimeoutInMs, readTimeout), readTimeout); - timeoutsHolder.readTimeout = idleConnectionTimeout; - } - nettyResponseFuture.setTimeoutsHolder(timeoutsHolder); - } catch (RejectedExecutionException ex) { - abort(nettyResponseFuture, ex); + int readTimeout = config.getReadTimeout(); + if (readTimeout != -1 && readTimeout < requestTimeoutInMs) { + // no need for a idleConnectionTimeout that's less than the + // requestTimeoutInMs + Timeout idleConnectionTimeout = newTimeout(new ReadTimeoutTimerTask(nettyResponseFuture, this, timeoutsHolder, + requestTimeoutInMs, readTimeout), readTimeout); + timeoutsHolder.readTimeout = idleConnectionTimeout; } + nettyResponseFuture.setTimeoutsHolder(timeoutsHolder); } public Timeout newTimeout(TimerTask task, long delay) { return nettyTimer.newTimeout(task, delay, TimeUnit.MILLISECONDS); } - public void abort(NettyResponseFuture future, Throwable t) { - Channel channel = future.channel(); + public void abort(Channel channel, NettyResponseFuture future, Throwable t) { if (channel != null) channelManager.closeChannel(channel); @@ -458,7 +452,7 @@ public boolean applyIoExceptionFiltersAndReplayRequest(NettyResponseFuture fu throw new NullPointerException("FilterContext is null"); } } catch (FilterException efe) { - abort(future, efe); + abort(channel, future, efe); } } diff --git a/src/main/java/com/ning/http/client/providers/netty/request/timeout/ReadTimeoutTimerTask.java b/src/main/java/com/ning/http/client/providers/netty/request/timeout/ReadTimeoutTimerTask.java index 6fb1c96b7a..d314298921 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/timeout/ReadTimeoutTimerTask.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/timeout/ReadTimeoutTimerTask.java @@ -37,7 +37,10 @@ public ReadTimeoutTimerTask(// public void run(Timeout timeout) throws Exception { - if (requestSender.isClosed() || nettyResponseFuture.isDone()) { + if (done.getAndSet(true) || requestSender.isClosed()) + return; + + if (nettyResponseFuture.isDone()) { timeoutsHolder.cancel(); return; } @@ -49,12 +52,15 @@ public void run(Timeout timeout) throws Exception { if (durationBeforeCurrentReadTimeout <= 0L) { // idleConnectionTimeout reached - String message = "Read timeout to " + nettyResponseFuture.getChannelRemoteAddress() + " of " + readTimeout + " ms"; + String message = "Read timeout to " + remoteAddress + " of " + readTimeout + " ms"; long durationSinceLastTouch = now - nettyResponseFuture.getLastTouch(); expire(message, durationSinceLastTouch); + // cancel request timeout sibling + timeoutsHolder.cancel(); } else if (currentReadTimeoutInstant < requestTimeoutInstant) { // reschedule + done.set(false); timeoutsHolder.readTimeout = requestSender.newTimeout(this, durationBeforeCurrentReadTimeout); } else { @@ -62,6 +68,7 @@ public void run(Timeout timeout) throws Exception { timeoutsHolder.readTimeout = null; } - clean(); + // this task should be evacuated from the timer but who knows + nettyResponseFuture = null; } } diff --git a/src/main/java/com/ning/http/client/providers/netty/request/timeout/RequestTimeoutTimerTask.java b/src/main/java/com/ning/http/client/providers/netty/request/timeout/RequestTimeoutTimerTask.java index 8129dce9b6..c7ea6490be 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/timeout/RequestTimeoutTimerTask.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/timeout/RequestTimeoutTimerTask.java @@ -34,14 +34,20 @@ public RequestTimeoutTimerTask(// public void run(Timeout timeout) throws Exception { - // in any case, cancel possible idleConnectionTimeout + if (done.getAndSet(true) || requestSender.isClosed()) + return; + + // in any case, cancel possible idleConnectionTimeout sibling timeoutsHolder.cancel(); - if (requestSender.isClosed() || nettyResponseFuture.isDone()) + if (nettyResponseFuture.isDone()) return; - String message = "Request timed out to " + nettyResponseFuture.getChannelRemoteAddress() + " of " + requestTimeout + " ms"; + String message = "Request timed out to " + remoteAddress + " of " + requestTimeout + " ms"; long age = millisTime() - nettyResponseFuture.getStart(); expire(message, age); + + // this task should be evacuated from the timer but who knows + nettyResponseFuture = null; } } diff --git a/src/main/java/com/ning/http/client/providers/netty/request/timeout/TimeoutTimerTask.java b/src/main/java/com/ning/http/client/providers/netty/request/timeout/TimeoutTimerTask.java index ba2f99cd57..9ecf7476e0 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/timeout/TimeoutTimerTask.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/timeout/TimeoutTimerTask.java @@ -20,24 +20,29 @@ import com.ning.http.client.providers.netty.request.NettyRequestSender; import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicBoolean; public abstract class TimeoutTimerTask implements TimerTask { private static final Logger LOGGER = LoggerFactory.getLogger(TimeoutTimerTask.class); + protected final AtomicBoolean done = new AtomicBoolean(); protected volatile NettyResponseFuture nettyResponseFuture; protected final NettyRequestSender requestSender; protected final TimeoutsHolder timeoutsHolder; + protected final String remoteAddress; public TimeoutTimerTask(NettyResponseFuture nettyResponseFuture, NettyRequestSender requestSender, TimeoutsHolder timeoutsHolder) { this.nettyResponseFuture = nettyResponseFuture; this.requestSender = requestSender; this.timeoutsHolder = timeoutsHolder; + // saving remote address as the channel might be removed from the future when an exception occurs + remoteAddress = nettyResponseFuture.getChannelRemoteAddress().toString(); } protected void expire(String message, long time) { LOGGER.debug("{} for {} after {} ms", message, nettyResponseFuture, time); - requestSender.abort(nettyResponseFuture, new TimeoutException(message)); + requestSender.abort(nettyResponseFuture.channel(), nettyResponseFuture, new TimeoutException(message)); } /** @@ -45,6 +50,7 @@ protected void expire(String message, long time) { * Holding a reference to the future might mean holding a reference to the channel, and heavy objects such as SslEngines */ public void clean() { - nettyResponseFuture = null; + if (done.compareAndSet(false, true)) + nettyResponseFuture = null; } } From e8e440ff6e658a44447efe6096f1e51719e934b9 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 27 Aug 2014 17:10:40 +0200 Subject: [PATCH 559/701] [maven-release-plugin] prepare release async-http-client-1.9.0-BETA10 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 8a64df6dc6..487b7b08c1 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.9.0-SNAPSHOT + 1.9.0-BETA10 jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From 79746bee17570feb33bf2d84468bf9540a625ee6 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 27 Aug 2014 17:10:45 +0200 Subject: [PATCH 560/701] [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 487b7b08c1..8a64df6dc6 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.9.0-BETA10 + 1.9.0-SNAPSHOT jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From 9936f0ffa43ca518ab1cbbe2e6c0b7c632e0f61b Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 1 Sep 2014 13:51:56 +0200 Subject: [PATCH 561/701] Honor Accept-Encoding if it was set in the request, close #686 --- .../providers/netty/request/NettyRequestFactory.java | 8 ++++++-- .../providers/netty/request/NettyRequestSender.java | 1 - 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestFactory.java b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestFactory.java index cd813ed131..f3b2227d61 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestFactory.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestFactory.java @@ -275,8 +275,12 @@ public NettyRequest newNettyRequest(Request request, UriComponents uri, boolean if (isNonEmpty(request.getCookies())) headers.set(HttpHeaders.Names.COOKIE, CookieEncoder.encode(request.getCookies())); - if (config.isCompressionEnabled()) - headers.set(HttpHeaders.Names.ACCEPT_ENCODING, GZIP_DEFLATE); + if (config.isCompressionEnabled()) { + if (!headers.contains(HttpHeaders.Names.ACCEPT_ENCODING)) + headers.set(HttpHeaders.Names.ACCEPT_ENCODING, GZIP_DEFLATE); + } else { + headers.remove(HttpHeaders.Names.ACCEPT_ENCODING); + } } if (body != null) { diff --git a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java index 5c66ce5b79..dce601bdd6 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java @@ -63,7 +63,6 @@ public final class NettyRequestSender { private static final Logger LOGGER = LoggerFactory.getLogger(NettyRequestSender.class); - public static final String GZIP_DEFLATE = HttpHeaders.Values.GZIP + "," + HttpHeaders.Values.DEFLATE; private final AsyncHttpClientConfig config; private final ChannelManager channelManager; From fc1f05fc2e4d8af86be60b80058dabfbfa313f18 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 2 Sep 2014 13:03:09 +0200 Subject: [PATCH 562/701] Have one common way of closing channels: silentlyCloseChannel --- .../netty/channel/ChannelManager.java | 2 +- .../providers/netty/channel/Channels.java | 15 ++++- .../netty/channel/CleanupChannelGroup.java | 2 +- .../channel/pool/DefaultChannelPool.java | 12 ++-- .../netty/future/NettyResponseFuture.java | 9 +-- .../providers/netty/handler/Processor.java | 16 ++--- .../netty/request/NettyRequestSender.java | 12 +--- .../netty/request/ProgressListener.java | 65 +++++++++---------- 8 files changed, 58 insertions(+), 75 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java b/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java index 9be11a691e..db15d3e084 100644 --- a/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java +++ b/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java @@ -321,7 +321,7 @@ public void closeChannel(Channel channel) { try { removeAll(channel); Channels.setDiscard(channel); - channel.close(); + Channels.silentlyCloseChannel(channel); } catch (Throwable t) { LOGGER.debug("Error closing a connection", t); } diff --git a/src/main/java/com/ning/http/client/providers/netty/channel/Channels.java b/src/main/java/com/ning/http/client/providers/netty/channel/Channels.java index 378b668e93..07c08e8499 100644 --- a/src/main/java/com/ning/http/client/providers/netty/channel/Channels.java +++ b/src/main/java/com/ning/http/client/providers/netty/channel/Channels.java @@ -14,11 +14,15 @@ package com.ning.http.client.providers.netty.channel; import org.jboss.netty.channel.Channel; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import com.ning.http.client.providers.netty.DiscardEvent; public final class Channels { + private static final Logger LOGGER = LoggerFactory.getLogger(Channels.class); + private Channels() { } @@ -35,6 +39,15 @@ public static void setDiscard(Channel channel) { } public static boolean isChannelValid(Channel channel) { - return channel != null && channel.isOpen() && channel.isConnected(); + return channel != null && channel.isConnected(); + } + + public static void silentlyCloseChannel(Channel channel) { + try { + if (channel != null && channel.isOpen()) + channel.close(); + } catch (Throwable t) { + LOGGER.debug("Failed to close channel", t); + } } } diff --git a/src/main/java/com/ning/http/client/providers/netty/channel/CleanupChannelGroup.java b/src/main/java/com/ning/http/client/providers/netty/channel/CleanupChannelGroup.java index 09114c3893..083ce8faa0 100644 --- a/src/main/java/com/ning/http/client/providers/netty/channel/CleanupChannelGroup.java +++ b/src/main/java/com/ning/http/client/providers/netty/channel/CleanupChannelGroup.java @@ -83,7 +83,7 @@ public boolean add(Channel channel) { try { if (this.closed.get()) { // Immediately close channel, as close() was already called. - channel.close(); + Channels.silentlyCloseChannel(channel); return false; } diff --git a/src/main/java/com/ning/http/client/providers/netty/channel/pool/DefaultChannelPool.java b/src/main/java/com/ning/http/client/providers/netty/channel/pool/DefaultChannelPool.java index 7964bab403..740e67e906 100644 --- a/src/main/java/com/ning/http/client/providers/netty/channel/pool/DefaultChannelPool.java +++ b/src/main/java/com/ning/http/client/providers/netty/channel/pool/DefaultChannelPool.java @@ -299,13 +299,9 @@ public void destroy() { } private void close(Channel channel) { - try { - // FIXME pity to have to do this here - Channels.setDiscard(channel); - channelId2Creation.remove(channel.getId()); - channel.close(); - } catch (Throwable t) { - // noop - } + // FIXME pity to have to do this here + Channels.setDiscard(channel); + channelId2Creation.remove(channel.getId()); + Channels.silentlyCloseChannel(channel); } } diff --git a/src/main/java/com/ning/http/client/providers/netty/future/NettyResponseFuture.java b/src/main/java/com/ning/http/client/providers/netty/future/NettyResponseFuture.java index f7fc1efe9e..12e732a261 100755 --- a/src/main/java/com/ning/http/client/providers/netty/future/NettyResponseFuture.java +++ b/src/main/java/com/ning/http/client/providers/netty/future/NettyResponseFuture.java @@ -131,12 +131,9 @@ public boolean cancel(boolean force) { if (isCancelled.getAndSet(true)) return false; - try { - Channels.setDiscard(channel); - channel.close(); - } catch (Throwable t) { - // Ignore - } + Channels.setDiscard(channel); + Channels.silentlyCloseChannel(channel); + if (!onThrowableCalled.getAndSet(true)) { try { asyncHandler.onThrowable(new CancellationException()); diff --git a/src/main/java/com/ning/http/client/providers/netty/handler/Processor.java b/src/main/java/com/ning/http/client/providers/netty/handler/Processor.java index d8cd101865..a9367c890e 100644 --- a/src/main/java/com/ning/http/client/providers/netty/handler/Processor.java +++ b/src/main/java/com/ning/http/client/providers/netty/handler/Processor.java @@ -94,11 +94,8 @@ public void messageReceived(final ChannelHandlerContext ctx, MessageEvent e) thr } else if (attribute != DiscardEvent.INSTANCE) { // unhandled message - try { - ctx.getChannel().close(); - } catch (Throwable t) { - LOGGER.trace("Closing an orphan channel {}", ctx.getChannel()); - } + LOGGER.trace("Closing an orphan channel {}", channel); + Channels.silentlyCloseChannel(channel); } } @@ -165,14 +162,9 @@ public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws // FIXME why drop the original exception and throw a new one? if (!config.getIOExceptionFilters().isEmpty()) { - if (!requestSender.applyIoExceptionFiltersAndReplayRequest(future, CHANNEL_CLOSED_EXCEPTION, channel)) { + if (!requestSender.applyIoExceptionFiltersAndReplayRequest(future, CHANNEL_CLOSED_EXCEPTION, channel)) // Close the channel so the recovering can occurs. - try { - channel.close(); - } catch (Throwable t) { - // Swallow. - } - } + Channels.silentlyCloseChannel(channel); return; } } diff --git a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java index dce601bdd6..6b2b9f1369 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java @@ -314,11 +314,7 @@ public void writeRequest(NettyResponseFuture future, Channel channel) { } catch (Throwable cause) { // FIXME why not notify? LOGGER.debug(cause.getMessage(), cause); - try { - channel.close(); - } catch (RuntimeException ex) { - LOGGER.debug(ex.getMessage(), ex); - } + Channels.silentlyCloseChannel(channel); return; } } @@ -328,11 +324,7 @@ public void writeRequest(NettyResponseFuture future, Channel channel) { nettyRequest.getBody().write(channel, future, config); } catch (Throwable ioe) { - try { - channel.close(); - } catch (RuntimeException ex) { - LOGGER.debug(ex.getMessage(), ex); - } + Channels.silentlyCloseChannel(channel); } scheduleTimeouts(future); diff --git a/src/main/java/com/ning/http/client/providers/netty/request/ProgressListener.java b/src/main/java/com/ning/http/client/providers/netty/request/ProgressListener.java index 32d3c1c61d..555154cd22 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/ProgressListener.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/ProgressListener.java @@ -13,6 +13,7 @@ */ package com.ning.http.client.providers.netty.request; +import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelFutureProgressListener; import org.slf4j.Logger; @@ -22,6 +23,7 @@ import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.ProgressAsyncHandler; import com.ning.http.client.Realm; +import com.ning.http.client.providers.netty.channel.Channels; import com.ning.http.client.providers.netty.future.NettyResponseFuture; import com.ning.http.client.providers.netty.future.StackTraceInspector; @@ -46,53 +48,44 @@ public ProgressListener(AsyncHttpClientConfig config,// this.notifyHeaders = notifyHeaders; } - public void operationComplete(ChannelFuture cf) { - // The write operation failed. If the channel was cached, it means it got asynchronously closed. - // Let's retry a second time. - Throwable cause = cf.getCause(); + private boolean abortOnThrowable(Throwable cause, Channel channel) { if (cause != null && future.getState() != NettyResponseFuture.STATE.NEW) { - if (cause instanceof IllegalStateException) { LOGGER.debug(cause.getMessage(), cause); - try { - cf.getChannel().close(); - } catch (RuntimeException ex) { - LOGGER.debug(ex.getMessage(), ex); - } - return; - } - - if (cause instanceof ClosedChannelException || StackTraceInspector.abortOnReadOrWriteException(cause)) { + Channels.silentlyCloseChannel(channel); - if (LOGGER.isDebugEnabled()) { - LOGGER.debug(cf.getCause() == null ? "" : cf.getCause().getMessage(), cf.getCause()); - } + } else if (cause instanceof ClosedChannelException || StackTraceInspector.abortOnReadOrWriteException(cause)) { + LOGGER.debug(cause == null ? "" : cause.getMessage(), cause); + Channels.silentlyCloseChannel(channel); - try { - cf.getChannel().close(); - } catch (RuntimeException ex) { - LOGGER.debug(ex.getMessage(), ex); - } - return; } else { future.abort(cause); } - return; + return true; } - future.touch(); + return false; + } + + public void operationComplete(ChannelFuture cf) { + // The write operation failed. If the channel was cached, it means it got asynchronously closed. + // Let's retry a second time. + if (!abortOnThrowable(cf.getCause(), cf.getChannel())) { - /** - * 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() : config.getRealm(); - boolean startPublishing = future.isInAuth() || realm == null || realm.getUsePreemptiveAuth(); + future.touch(); - if (startPublishing && asyncHandler instanceof ProgressAsyncHandler) { - if (notifyHeaders) { - ProgressAsyncHandler.class.cast(asyncHandler).onHeaderWriteCompleted(); - } else { - ProgressAsyncHandler.class.cast(asyncHandler).onContentWriteCompleted(); + /** + * 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() : config.getRealm(); + boolean startPublishing = future.isInAuth() || realm == null || realm.getUsePreemptiveAuth(); + + if (startPublishing && asyncHandler instanceof ProgressAsyncHandler) { + if (notifyHeaders) { + ProgressAsyncHandler.class.cast(asyncHandler).onHeaderWriteCompleted(); + } else { + ProgressAsyncHandler.class.cast(asyncHandler).onContentWriteCompleted(); + } } } } From 8f53b1f3e5377cceaeade1a6159b6aec848be033 Mon Sep 17 00:00:00 2001 From: Gerd Riesselmann Date: Thu, 21 Aug 2014 22:42:45 +0200 Subject: [PATCH 563/701] Rename replace() to replaceWith() since Java 1.8 introduces Map.replace() which collides --- .../ning/http/client/FluentCaseInsensitiveStringsMap.java | 8 ++++---- src/main/java/com/ning/http/client/FluentStringsMap.java | 8 ++++---- .../java/com/ning/http/client/RequestBuilderBase.java | 2 +- .../client/async/FluentCaseInsensitiveStringsMapTest.java | 4 ++-- .../com/ning/http/client/async/FluentStringsMapTest.java | 4 ++-- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/ning/http/client/FluentCaseInsensitiveStringsMap.java b/src/main/java/com/ning/http/client/FluentCaseInsensitiveStringsMap.java index bc6e6c715f..a6bd64bf87 100644 --- a/src/main/java/com/ning/http/client/FluentCaseInsensitiveStringsMap.java +++ b/src/main/java/com/ning/http/client/FluentCaseInsensitiveStringsMap.java @@ -183,8 +183,8 @@ public FluentCaseInsensitiveStringsMap addAll(Map> sr * @param values The new values * @return This object */ - public FluentCaseInsensitiveStringsMap replace(final String key, final String... values) { - return replace(key, Arrays.asList(values)); + public FluentCaseInsensitiveStringsMap replaceWith(final String key, final String... values) { + return replaceWith(key, Arrays.asList(values)); } /** @@ -194,7 +194,7 @@ public FluentCaseInsensitiveStringsMap replace(final String key, final String... * @param values The new values * @return This object */ - public FluentCaseInsensitiveStringsMap replace(final String key, final Collection values) { + public FluentCaseInsensitiveStringsMap replaceWith(final String key, final Collection values) { if (key != null) { List nonNullValues = fetchValues(values); String lcKkey = key.toLowerCase(Locale.ENGLISH); @@ -242,7 +242,7 @@ public FluentCaseInsensitiveStringsMap replaceAll(FluentCaseInsensitiveStringsMa public FluentCaseInsensitiveStringsMap replaceAll(Map> src) { if (src != null) { for (Map.Entry> header : src.entrySet()) { - replace(header.getKey(), header.getValue()); + replaceWith(header.getKey(), header.getValue()); } } return this; diff --git a/src/main/java/com/ning/http/client/FluentStringsMap.java b/src/main/java/com/ning/http/client/FluentStringsMap.java index 3a9a07a9ef..4534f3a192 100644 --- a/src/main/java/com/ning/http/client/FluentStringsMap.java +++ b/src/main/java/com/ning/http/client/FluentStringsMap.java @@ -138,8 +138,8 @@ public FluentStringsMap addAll(Map> src) { * @param values The new values * @return This object */ - public FluentStringsMap replace(final String key, final String... values) { - return replace(key, Arrays.asList(values)); + public FluentStringsMap replaceWith(final String key, final String... values) { + return replaceWith(key, Arrays.asList(values)); } /** @@ -149,7 +149,7 @@ public FluentStringsMap replace(final String key, final String... values) { * @param values The new values * @return This object */ - public FluentStringsMap replace(final String key, final Collection values) { + public FluentStringsMap replaceWith(final String key, final Collection values) { if (key != null) { if (values == null) { this.values.remove(key); @@ -186,7 +186,7 @@ public FluentStringsMap replaceAll(FluentStringsMap src) { public FluentStringsMap replaceAll(Map> src) { if (src != null) { for (Map.Entry> header : src.entrySet()) { - replace(header.getKey(), header.getValue()); + replaceWith(header.getKey(), header.getValue()); } } 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 e68735912c..e77ae89daf 100644 --- a/src/main/java/com/ning/http/client/RequestBuilderBase.java +++ b/src/main/java/com/ning/http/client/RequestBuilderBase.java @@ -287,7 +287,7 @@ public T setVirtualHost(String virtualHost) { } public T setHeader(String name, String value) { - request.headers.replace(name, value); + request.headers.replaceWith(name, value); return derived.cast(this); } diff --git a/src/test/java/com/ning/http/client/async/FluentCaseInsensitiveStringsMapTest.java b/src/test/java/com/ning/http/client/async/FluentCaseInsensitiveStringsMapTest.java index 69e90e4e34..e2de44f893 100644 --- a/src/test/java/com/ning/http/client/async/FluentCaseInsensitiveStringsMapTest.java +++ b/src/test/java/com/ning/http/client/async/FluentCaseInsensitiveStringsMapTest.java @@ -391,7 +391,7 @@ public void replaceTest() { assertEquals(map.getJoinedValue("baz", ", "), "foo, bar"); assertEquals(map.get("baz"), Arrays.asList("foo", "bar")); - map.replace("Foo", "blub", "bla"); + map.replaceWith("Foo", "blub", "bla"); assertEquals(map.keySet(), new LinkedHashSet(Arrays.asList("Foo", "baz"))); assertEquals(map.getFirstValue("foo"), "blub"); @@ -472,7 +472,7 @@ public void replaceValueWithNullTest() { assertEquals(map.getJoinedValue("baz", ", "), "foo, bar"); assertEquals(map.get("baz"), Arrays.asList("foo", "bar")); - map.replace("baZ", (Collection) null); + map.replaceWith("baZ", (Collection) null); assertEquals(map.keySet(), new LinkedHashSet(Arrays.asList("foo"))); assertEquals(map.getFirstValue("foo"), "bar"); 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 0ca6100ed2..a0cab30861 100644 --- a/src/test/java/com/ning/http/client/async/FluentStringsMapTest.java +++ b/src/test/java/com/ning/http/client/async/FluentStringsMapTest.java @@ -466,7 +466,7 @@ public void replaceArrayTest() { assertEquals(map.getJoinedValue("baz", ", "), "foo, bar"); assertEquals(map.get("baz"), Arrays.asList("foo", "bar")); - map.replace("foo", "blub", "bla"); + map.replaceWith("foo", "blub", "bla"); assertEquals(map.keySet(), new LinkedHashSet(Arrays.asList("foo", "baz"))); assertEquals(map.getFirstValue("foo"), "blub"); @@ -602,7 +602,7 @@ public void replaceValueWithNullTest() { assertEquals(map.getJoinedValue("baz", ", "), "foo, bar"); assertEquals(map.get("baz"), Arrays.asList("foo", "bar")); - map.replace("baz", (Collection) null); + map.replaceWith("baz", (Collection) null); assertEquals(map.keySet(), new LinkedHashSet(Arrays.asList("foo"))); assertEquals(map.getFirstValue("foo"), "bar"); From 460b5c5d9c8038db2b3369c59a52b3a205e9de57 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 2 Sep 2014 15:33:53 +0200 Subject: [PATCH 564/701] Fix previous commit?! --- .../ning/http/client/FluentCaseInsensitiveStringsMap.java | 4 ++-- src/main/java/com/ning/http/client/FluentStringsMap.java | 4 ++-- .../client/async/FluentCaseInsensitiveStringsMapTest.java | 4 ++-- .../com/ning/http/client/async/FluentStringsMapTest.java | 8 ++++---- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/ning/http/client/FluentCaseInsensitiveStringsMap.java b/src/main/java/com/ning/http/client/FluentCaseInsensitiveStringsMap.java index a6bd64bf87..7f6d241a8e 100644 --- a/src/main/java/com/ning/http/client/FluentCaseInsensitiveStringsMap.java +++ b/src/main/java/com/ning/http/client/FluentCaseInsensitiveStringsMap.java @@ -226,7 +226,7 @@ public FluentCaseInsensitiveStringsMap replaceWith(final String key, final Colle public FluentCaseInsensitiveStringsMap replaceAll(FluentCaseInsensitiveStringsMap src) { if (src != null) { for (Map.Entry> header : src) { - replace(header.getKey(), header.getValue()); + replaceWith(header.getKey(), header.getValue()); } } return this; @@ -256,7 +256,7 @@ public List put(String key, List value) { List oldValue = get(key); - replace(key, value); + replaceWith(key, value); return oldValue; } diff --git a/src/main/java/com/ning/http/client/FluentStringsMap.java b/src/main/java/com/ning/http/client/FluentStringsMap.java index 4534f3a192..d0f56cd5b9 100644 --- a/src/main/java/com/ning/http/client/FluentStringsMap.java +++ b/src/main/java/com/ning/http/client/FluentStringsMap.java @@ -170,7 +170,7 @@ public FluentStringsMap replaceWith(final String key, final Collection v public FluentStringsMap replaceAll(FluentStringsMap src) { if (src != null) { for (Map.Entry> header : src) { - replace(header.getKey(), header.getValue()); + replaceWith(header.getKey(), header.getValue()); } } return this; @@ -200,7 +200,7 @@ public List put(String key, List value) { List oldValue = get(key); - replace(key, value); + replaceWith(key, value); return oldValue; } diff --git a/src/test/java/com/ning/http/client/async/FluentCaseInsensitiveStringsMapTest.java b/src/test/java/com/ning/http/client/async/FluentCaseInsensitiveStringsMapTest.java index e2de44f893..290158307b 100644 --- a/src/test/java/com/ning/http/client/async/FluentCaseInsensitiveStringsMapTest.java +++ b/src/test/java/com/ning/http/client/async/FluentCaseInsensitiveStringsMapTest.java @@ -417,7 +417,7 @@ public void replaceUndefinedTest() { assertEquals(map.getJoinedValue("baz", ", "), "foo, bar"); assertEquals(map.get("baz"), Arrays.asList("foo", "bar")); - map.replace("bar", Arrays.asList("blub")); + map.replaceWith("bar", Arrays.asList("blub")); assertEquals(map.keySet(), new LinkedHashSet(Arrays.asList("foo", "baz", "bar"))); assertEquals(map.getFirstValue("foo"), "bar"); @@ -446,7 +446,7 @@ public void replaceNullTest() { assertEquals(map.getJoinedValue("baz", ", "), "foo, bar"); assertEquals(map.get("baz"), Arrays.asList("foo", "bar")); - map.replace(null, Arrays.asList("blub")); + map.replaceWith(null, Arrays.asList("blub")); assertEquals(map.keySet(), new LinkedHashSet(Arrays.asList("foo", "baz"))); assertEquals(map.getFirstValue("foo"), "bar"); 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 a0cab30861..5913668de4 100644 --- a/src/test/java/com/ning/http/client/async/FluentStringsMapTest.java +++ b/src/test/java/com/ning/http/client/async/FluentStringsMapTest.java @@ -492,7 +492,7 @@ public void replaceCollectionTest() { assertEquals(map.getJoinedValue("baz", ", "), "foo, bar"); assertEquals(map.get("baz"), Arrays.asList("foo", "bar")); - map.replace("foo", Arrays.asList("blub", "bla")); + map.replaceWith("foo", Arrays.asList("blub", "bla")); assertEquals(map.keySet(), new LinkedHashSet(Arrays.asList("foo", "baz"))); assertEquals(map.getFirstValue("foo"), "blub"); @@ -518,7 +518,7 @@ public void replaceDifferentCaseTest() { assertEquals(map.getJoinedValue("baz", ", "), "foo, bar"); assertEquals(map.get("baz"), Arrays.asList("foo", "bar")); - map.replace("Foo", Arrays.asList("blub", "bla")); + map.replaceWith("Foo", Arrays.asList("blub", "bla")); assertEquals(map.keySet(), new LinkedHashSet(Arrays.asList("foo", "baz", "Foo"))); assertEquals(map.getFirstValue("foo"), "bar"); @@ -547,7 +547,7 @@ public void replaceUndefinedTest() { assertEquals(map.getJoinedValue("baz", ", "), "foo, bar"); assertEquals(map.get("baz"), Arrays.asList("foo", "bar")); - map.replace("bar", Arrays.asList("blub")); + map.replaceWith("bar", Arrays.asList("blub")); assertEquals(map.keySet(), new LinkedHashSet(Arrays.asList("foo", "baz", "bar"))); assertEquals(map.getFirstValue("foo"), "bar"); @@ -576,7 +576,7 @@ public void replaceNullTest() { assertEquals(map.getJoinedValue("baz", ", "), "foo, bar"); assertEquals(map.get("baz"), Arrays.asList("foo", "bar")); - map.replace(null, Arrays.asList("blub")); + map.replaceWith(null, Arrays.asList("blub")); assertEquals(map.keySet(), new LinkedHashSet(Arrays.asList("foo", "baz"))); assertEquals(map.getFirstValue("foo"), "bar"); From 9571d2d0fe858469c72097a9ed0b32d7a33999c8 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 2 Sep 2014 15:51:57 +0200 Subject: [PATCH 565/701] Cache url inside UriComponents, close #688 --- .../providers/netty/handler/Protocol.java | 2 +- .../netty/request/NettyRequestFactory.java | 2 +- .../ning/http/client/uri/UriComponents.java | 30 +++++++++++-------- 3 files changed, 19 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/handler/Protocol.java b/src/main/java/com/ning/http/client/providers/netty/handler/Protocol.java index 00728c06a8..3205b70c47 100644 --- a/src/main/java/com/ning/http/client/providers/netty/handler/Protocol.java +++ b/src/main/java/com/ning/http/client/providers/netty/handler/Protocol.java @@ -126,7 +126,7 @@ protected boolean exitAfterHandlingRedirect(// final String initialPoolKey = channelManager.getPoolKey(future); future.setURI(uri); - String newUrl = uri.toString(); + String newUrl = uri.toUrl(); if (request.getURI().getScheme().startsWith(WEBSOCKET)) { newUrl = newUrl.replaceFirst(HTTP, WEBSOCKET); } diff --git a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestFactory.java b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestFactory.java index f3b2227d61..f9b9881511 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestFactory.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestFactory.java @@ -77,7 +77,7 @@ private String requestUri(UriComponents uri, ProxyServer proxyServer, HttpMethod return getAuthority(uri); else if (proxyServer != null && !(useProxyConnect(uri) && config.isUseRelativeURIsWithConnectProxies())) - return uri.toString(); + return uri.toUrl(); else { String path = getNonEmptyPath(uri); diff --git a/src/main/java/com/ning/http/client/uri/UriComponents.java b/src/main/java/com/ning/http/client/uri/UriComponents.java index 40916490e6..3c9ef33c74 100644 --- a/src/main/java/com/ning/http/client/uri/UriComponents.java +++ b/src/main/java/com/ning/http/client/uri/UriComponents.java @@ -42,6 +42,7 @@ public static UriComponents create(UriComponents context, final String originalU private final int port; private final String query; private final String path; + private String url; public UriComponents(String scheme,// String userInfo,// @@ -92,19 +93,22 @@ public URI toURI() throws URISyntaxException { } public String toUrl() { - StringBuilder sb = new StringBuilder(); - sb.append(scheme).append("://"); - if (userInfo != null) - sb.append(userInfo).append('@'); - sb.append(host); - if (port != -1) - sb.append(':').append(port); - if (path != null) - sb.append(path); - if (query != null) - sb.append('?').append(query); - - return sb.toString(); + if (url == null) { + StringBuilder sb = new StringBuilder(); + sb.append(scheme).append("://"); + if (userInfo != null) + sb.append(userInfo).append('@'); + sb.append(host); + if (port != -1) + sb.append(':').append(port); + if (path != null) + sb.append(path); + if (query != null) + sb.append('?').append(query); + url = sb.toString(); + } + + return url; } public String toRelativeUrl() { From f4b2a6eda763b448d039c58e8308949799ce801f Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 2 Sep 2014 15:52:53 +0200 Subject: [PATCH 566/701] Have a getUrl shortcut on Request without having to grab the UriComponents, close #689 --- src/main/java/com/ning/http/client/Request.java | 2 ++ .../com/ning/http/client/RequestBuilderBase.java | 6 +++++- .../providers/apache/ApacheAsyncHttpProvider.java | 10 +++++----- .../client/resumable/ResumableAsyncHandler.java | 2 +- .../http/client/async/AsyncProvidersBasicTest.java | 2 +- .../ning/http/client/async/RequestBuilderTest.java | 14 +++++++------- 6 files changed, 21 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/ning/http/client/Request.java b/src/main/java/com/ning/http/client/Request.java index 9158ff9275..fcaa51e816 100644 --- a/src/main/java/com/ning/http/client/Request.java +++ b/src/main/java/com/ning/http/client/Request.java @@ -47,6 +47,8 @@ public interface Request { UriComponents getURI(); + String getUrl(); + /** * 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 e77ae89daf..899c2706f3 100644 --- a/src/main/java/com/ning/http/client/RequestBuilderBase.java +++ b/src/main/java/com/ning/http/client/RequestBuilderBase.java @@ -116,6 +116,10 @@ public UriComponents getURI() { return uri; } + public String getUrl() { + return uri.toUrl(); + } + public FluentCaseInsensitiveStringsMap getHeaders() { return headers; } @@ -208,7 +212,7 @@ public List getQueryParams() { @Override public String toString() { - StringBuilder sb = new StringBuilder(getURI().toUrl()); + StringBuilder sb = new StringBuilder(getUrl()); sb.append("\t"); sb.append(method); 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 767125f1ef..6c7de4d8a2 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 @@ -250,7 +250,7 @@ private HttpMethodBase createMethod(HttpClient client, Request request) throws I String methodName = request.getMethod(); HttpMethodBase method = null; if (methodName.equalsIgnoreCase("POST") || methodName.equalsIgnoreCase("PUT")) { - EntityEnclosingMethod post = methodName.equalsIgnoreCase("POST") ? new PostMethod(request.getURI().toUrl()) : new PutMethod(request.getURI().toUrl()); + EntityEnclosingMethod post = methodName.equalsIgnoreCase("POST") ? new PostMethod(request.getUrl()) : new PutMethod(request.getUrl()); String bodyCharset = request.getBodyEncoding() == null ? DEFAULT_CHARSET.name() : request.getBodyEncoding(); @@ -340,13 +340,13 @@ private HttpMethodBase createMethod(HttpClient client, Request request) throws I } method = post; } else if (methodName.equalsIgnoreCase("DELETE")) { - method = new DeleteMethod(request.getURI().toUrl()); + method = new DeleteMethod(request.getUrl()); } else if (methodName.equalsIgnoreCase("HEAD")) { - method = new HeadMethod(request.getURI().toUrl()); + method = new HeadMethod(request.getUrl()); } else if (methodName.equalsIgnoreCase("GET")) { - method = new GetMethod(request.getURI().toUrl()); + method = new GetMethod(request.getUrl()); } else if (methodName.equalsIgnoreCase("OPTIONS")) { - method = new OptionsMethod(request.getURI().toUrl()); + method = new OptionsMethod(request.getUrl()); } else { throw new IllegalStateException(String.format("Invalid Method", methodName)); } 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 5917da7b13..4c1a1cef3e 100644 --- a/src/main/java/com/ning/http/client/resumable/ResumableAsyncHandler.java +++ b/src/main/java/com/ning/http/client/resumable/ResumableAsyncHandler.java @@ -185,7 +185,7 @@ public AsyncHandler.STATE onHeadersReceived(HttpResponseHeaders headers) throws */ public Request adjustRequestRange(Request request) { - Long ri = resumableIndex.get(request.getURI().toUrl()); + Long ri = resumableIndex.get(request.getUrl()); if (ri != null) { byteTransferred.set(ri); } 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 8be286b923..87d0a5b6a8 100755 --- a/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java +++ b/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java @@ -70,7 +70,7 @@ public void asyncProviderEncodingTest() throws Throwable { AsyncHttpClient client = getAsyncHttpClient(null); try { Request request = new RequestBuilder("GET").setUrl(getTargetUrl() + "?q=+%20x").build(); - String requestUrl = request.getURI().toUrl(); + String requestUrl = request.getUrl(); Assert.assertEquals(requestUrl, getTargetUrl() + "?q=%20%20x"); Future responseFuture = client.executeRequest(request, new AsyncCompletionHandler() { @Override diff --git a/src/test/java/com/ning/http/client/async/RequestBuilderTest.java b/src/test/java/com/ning/http/client/async/RequestBuilderTest.java index 669f3d0422..e65437a00c 100644 --- a/src/test/java/com/ning/http/client/async/RequestBuilderTest.java +++ b/src/test/java/com/ning/http/client/async/RequestBuilderTest.java @@ -72,7 +72,7 @@ public void testEncodesQueryParameters() throws UnsupportedEncodingException { } String expValue = sb.toString(); Request request = builder.build(); - assertEquals(request.getURI().toUrl(), "http://example.com/?name=" + expValue); + assertEquals(request.getUrl(), "http://example.com/?name=" + expValue); } } @@ -95,7 +95,7 @@ public void testParsesQueryParams() throws IOException, ExecutionException, Inte .addQueryParam("param2", "value2") .build(); - assertEquals(request.getURI().toUrl(), "http://foo.com/?param1=value1¶m2=value2"); + assertEquals(request.getUrl(), "http://foo.com/?param1=value1¶m2=value2"); List params = request.getQueryParams(); assertEquals(params.size(), 2); assertEquals(params.get(0), new Param("param1", "value1")); @@ -106,14 +106,14 @@ public void testParsesQueryParams() throws IOException, ExecutionException, Inte public void testUserProvidedRequestMethod() { Request req = new RequestBuilder("ABC").setUrl("http://foo.com").build(); assertEquals(req.getMethod(), "ABC"); - assertEquals(req.getURI().toUrl(), "http://foo.com"); + assertEquals(req.getUrl(), "http://foo.com"); } @Test(groups = {"standalone", "default_provider"}) public void testPercentageEncodedUserInfo() { final Request req = new RequestBuilder("GET").setUrl("http://hello:wor%20ld@foo.com").build(); assertEquals(req.getMethod(), "GET"); - assertEquals(req.getURI().toUrl(), "http://hello:wor%20ld@foo.com"); + assertEquals(req.getUrl(), "http://hello:wor%20ld@foo.com"); } @Test(groups = {"standalone", "default_provider"}) @@ -130,15 +130,15 @@ public void testAddQueryParameter() throws UnsupportedEncodingException { .addQueryParam("a", "1?&") .addQueryParam("b", "+ ="); Request request = rb.build(); - assertEquals(request.getURI().toUrl(), "http://example.com/path?a=1%3F%26&b=%2B%20%3D"); + assertEquals(request.getUrl(), "http://example.com/path?a=1%3F%26&b=%2B%20%3D"); } - + @Test(groups = {"standalone", "default_provider"}) public void testRawUrlQuery() throws UnsupportedEncodingException, URISyntaxException { String preEncodedUrl = "http://example.com/space%20mirror.php?%3Bteile"; RequestBuilder rb = new RequestBuilder("GET", true).setUrl(preEncodedUrl); Request request = rb.build(); - assertEquals(request.getURI().toUrl(), preEncodedUrl); + assertEquals(request.getUrl(), preEncodedUrl); assertEquals(request.getURI().toURI().toString(), preEncodedUrl); } } From f00b29bc77d1fd6310e34eef8152460daa90375c Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 3 Sep 2014 10:08:52 +0200 Subject: [PATCH 567/701] Rename UriComponents into Uri, close #691 --- .../client/ConnectionPoolKeyStrategy.java | 4 +- .../client/DefaultConnectionPoolStrategy.java | 4 +- .../ning/http/client/HttpResponseStatus.java | 12 ++--- .../ning/http/client/ProxyServerSelector.java | 6 +-- src/main/java/com/ning/http/client/Realm.java | 14 +++--- .../java/com/ning/http/client/Request.java | 4 +- .../ning/http/client/RequestBuilderBase.java | 14 +++--- .../java/com/ning/http/client/Response.java | 8 ++-- .../com/ning/http/client/ResponseBase.java | 4 +- .../http/client/SimpleAsyncHttpClient.java | 10 ++-- .../oauth/OAuthSignatureCalculator.java | 6 +-- .../apache/ApacheAsyncHttpProvider.java | 8 ++-- .../apache/ApacheResponseStatus.java | 4 +- .../grizzly/GrizzlyAsyncHttpProvider.java | 46 +++++++++---------- .../grizzly/GrizzlyResponseStatus.java | 4 +- .../http/client/providers/grizzly/Utils.java | 4 +- .../providers/jdk/JDKAsyncHttpProvider.java | 18 ++++---- .../client/providers/jdk/ResponseHeaders.java | 4 +- .../client/providers/jdk/ResponseStatus.java | 4 +- .../netty/channel/ChannelManager.java | 2 +- .../netty/future/NettyResponseFuture.java | 10 ++-- .../providers/netty/handler/HttpProtocol.java | 26 +++++------ .../providers/netty/handler/Protocol.java | 10 ++-- .../netty/handler/WebSocketProtocol.java | 4 +- .../netty/request/NettyConnectListener.java | 5 +- .../netty/request/NettyRequestFactory.java | 10 ++-- .../netty/request/NettyRequestSender.java | 26 +++++------ .../netty/response/NettyResponseStatus.java | 4 +- .../providers/netty/util/HttpUtils.java | 6 +-- .../simple/SimpleAHCTransferListener.java | 12 ++--- .../uri/{UriComponents.java => Uri.java} | 24 +++++----- ...riComponentsParser.java => UriParser.java} | 8 ++-- .../webdav/WebDavCompletionHandlerBase.java | 4 +- .../http/client/webdav/WebDavResponse.java | 4 +- .../http/util/AsyncHttpProviderUtils.java | 12 ++--- .../ning/http/util/AuthenticatorUtils.java | 4 +- .../java/com/ning/http/util/ProxyUtils.java | 12 ++--- .../java/com/ning/http/client/RealmTest.java | 6 +-- .../async/PerRequestRelative302Test.java | 6 +-- .../http/client/async/Relative302Test.java | 6 +-- .../http/client/async/RequestBuilderTest.java | 4 +- .../async/SimpleAsyncHttpClientTest.java | 12 ++--- .../client/oauth/TestSignatureCalculator.java | 4 +- .../resumable/ResumableAsyncHandlerTest.java | 4 +- .../{UriComponentsTest.java => UriTest.java} | 20 ++++---- 45 files changed, 211 insertions(+), 212 deletions(-) rename src/main/java/com/ning/http/client/uri/{UriComponents.java => Uri.java} (88%) rename src/main/java/com/ning/http/client/uri/{UriComponentsParser.java => UriParser.java} (97%) rename src/test/java/com/ning/http/client/uri/{UriComponentsTest.java => UriTest.java} (69%) diff --git a/src/main/java/com/ning/http/client/ConnectionPoolKeyStrategy.java b/src/main/java/com/ning/http/client/ConnectionPoolKeyStrategy.java index c0c2172d01..96d506a523 100644 --- a/src/main/java/com/ning/http/client/ConnectionPoolKeyStrategy.java +++ b/src/main/java/com/ning/http/client/ConnectionPoolKeyStrategy.java @@ -15,9 +15,9 @@ */ package com.ning.http.client; -import com.ning.http.client.uri.UriComponents; +import com.ning.http.client.uri.Uri; public interface ConnectionPoolKeyStrategy { - String getKey(UriComponents uri, ProxyServer proxyServer); + String getKey(Uri uri, ProxyServer proxyServer); } diff --git a/src/main/java/com/ning/http/client/DefaultConnectionPoolStrategy.java b/src/main/java/com/ning/http/client/DefaultConnectionPoolStrategy.java index 4369a8a102..900bd62b90 100644 --- a/src/main/java/com/ning/http/client/DefaultConnectionPoolStrategy.java +++ b/src/main/java/com/ning/http/client/DefaultConnectionPoolStrategy.java @@ -15,14 +15,14 @@ */ package com.ning.http.client; -import com.ning.http.client.uri.UriComponents; +import com.ning.http.client.uri.Uri; import com.ning.http.util.AsyncHttpProviderUtils; public enum DefaultConnectionPoolStrategy implements ConnectionPoolKeyStrategy { INSTANCE; - public String getKey(UriComponents uri, ProxyServer proxyServer) { + public String getKey(Uri uri, ProxyServer proxyServer) { String serverPart = AsyncHttpProviderUtils.getBaseUrl(uri); return proxyServer != null ? proxyServer.getUrl() + serverPart : serverPart; } diff --git a/src/main/java/com/ning/http/client/HttpResponseStatus.java b/src/main/java/com/ning/http/client/HttpResponseStatus.java index 9e3b9f7183..34a438b443 100644 --- a/src/main/java/com/ning/http/client/HttpResponseStatus.java +++ b/src/main/java/com/ning/http/client/HttpResponseStatus.java @@ -16,7 +16,7 @@ */ package com.ning.http.client; -import com.ning.http.client.uri.UriComponents; +import com.ning.http.client.uri.Uri; import java.util.List; @@ -25,20 +25,20 @@ */ public abstract class HttpResponseStatus { - private final UriComponents uri; + private final Uri uri; protected final AsyncHttpClientConfig config; - public HttpResponseStatus(UriComponents uri, AsyncHttpClientConfig config) { + public HttpResponseStatus(Uri uri, AsyncHttpClientConfig config) { this.uri = uri; this.config = config; } /** - * Return the request {@link UriComponents} + * Return the request {@link Uri} * - * @return the request {@link UriComponents} + * @return the request {@link Uri} */ - public final UriComponents getUri() { + public final Uri getUri() { return uri; } diff --git a/src/main/java/com/ning/http/client/ProxyServerSelector.java b/src/main/java/com/ning/http/client/ProxyServerSelector.java index 194f268426..e45adb28fc 100644 --- a/src/main/java/com/ning/http/client/ProxyServerSelector.java +++ b/src/main/java/com/ning/http/client/ProxyServerSelector.java @@ -1,6 +1,6 @@ package com.ning.http.client; -import com.ning.http.client.uri.UriComponents; +import com.ning.http.client.uri.Uri; /** * Selector for a proxy server @@ -13,13 +13,13 @@ public interface ProxyServerSelector { * @param uri The URI to select a proxy server for. * @return The proxy server to use, if any. May return null. */ - ProxyServer select(UriComponents uri); + ProxyServer select(Uri uri); /** * A selector that always selects no proxy. */ static final ProxyServerSelector NO_PROXY_SELECTOR = new ProxyServerSelector() { - public ProxyServer select(UriComponents uri) { + public ProxyServer select(Uri uri) { return null; } }; diff --git a/src/main/java/com/ning/http/client/Realm.java b/src/main/java/com/ning/http/client/Realm.java index 46053c082e..d6c9bd7c8a 100644 --- a/src/main/java/com/ning/http/client/Realm.java +++ b/src/main/java/com/ning/http/client/Realm.java @@ -18,7 +18,7 @@ import static com.ning.http.util.MiscUtils.isNonEmpty; -import com.ning.http.client.uri.UriComponents; +import com.ning.http.client.uri.Uri; import com.ning.http.util.StandardCharsets; import java.io.UnsupportedEncodingException; @@ -43,7 +43,7 @@ public class Realm { private final String qop; private final String nc; private final String cnonce; - private final UriComponents uri; + private final Uri uri; private final String methodName; private final boolean usePreemptiveAuth; private final String enc; @@ -74,7 +74,7 @@ private Realm(AuthScheme scheme, String qop, String nc, String cnonce, - UriComponents uri, + Uri uri, String method, boolean usePreemptiveAuth, String ntlmDomain, @@ -158,7 +158,7 @@ public String getCnonce() { return cnonce; } - public UriComponents getUri() { + public Uri getUri() { return uri; } @@ -294,7 +294,7 @@ public static class RealmBuilder { private String qop = "auth"; private String nc = "00000001"; private String cnonce = ""; - private UriComponents uri; + private Uri uri; private String methodName = "GET"; private boolean usePreemptive = false; private String ntlmDomain = System.getProperty("http.auth.ntlm.domain", ""); @@ -414,11 +414,11 @@ public RealmBuilder setNc(String nc) { return this; } - public UriComponents getUri() { + public Uri getUri() { return uri; } - public RealmBuilder setUri(UriComponents uri) { + public RealmBuilder setUri(Uri uri) { this.uri = uri; return this; } diff --git a/src/main/java/com/ning/http/client/Request.java b/src/main/java/com/ning/http/client/Request.java index fcaa51e816..ac2275ffd6 100644 --- a/src/main/java/com/ning/http/client/Request.java +++ b/src/main/java/com/ning/http/client/Request.java @@ -18,7 +18,7 @@ import com.ning.http.client.cookie.Cookie; import com.ning.http.client.multipart.Part; -import com.ning.http.client.uri.UriComponents; +import com.ning.http.client.uri.Uri; import java.io.File; import java.io.InputStream; @@ -45,7 +45,7 @@ public interface Request { */ String getMethod(); - UriComponents getURI(); + Uri getUri(); String getUrl(); diff --git a/src/main/java/com/ning/http/client/RequestBuilderBase.java b/src/main/java/com/ning/http/client/RequestBuilderBase.java index 899c2706f3..6009c03a99 100644 --- a/src/main/java/com/ning/http/client/RequestBuilderBase.java +++ b/src/main/java/com/ning/http/client/RequestBuilderBase.java @@ -22,7 +22,7 @@ import com.ning.http.client.cookie.Cookie; import com.ning.http.client.multipart.Part; -import com.ning.http.client.uri.UriComponents; +import com.ning.http.client.uri.Uri; import com.ning.http.util.AsyncHttpProviderUtils; import com.ning.http.util.QueryComputer; @@ -43,11 +43,11 @@ public abstract class RequestBuilderBase> { private final static Logger logger = LoggerFactory.getLogger(RequestBuilderBase.class); - private static final UriComponents DEFAULT_REQUEST_URL = UriComponents.create("http://localhost"); + private static final Uri DEFAULT_REQUEST_URL = Uri.create("http://localhost"); private static final class RequestImpl implements Request { private String method; - private UriComponents uri; + private Uri uri; private InetAddress address; private InetAddress localAddress; private FluentCaseInsensitiveStringsMap headers = new FluentCaseInsensitiveStringsMap(); @@ -76,7 +76,7 @@ public RequestImpl() { public RequestImpl(Request prototype) { if (prototype != null) { this.method = prototype.getMethod(); - this.uri = prototype.getURI(); + this.uri = prototype.getUri(); this.address = prototype.getInetAddress(); this.localAddress = prototype.getLocalAddress(); this.headers = new FluentCaseInsensitiveStringsMap(prototype.getHeaders()); @@ -112,7 +112,7 @@ public InetAddress getLocalAddress() { return localAddress; } - public UriComponents getURI() { + public Uri getUri() { return uri; } @@ -267,10 +267,10 @@ protected RequestBuilderBase(Class derived, Request prototype, QueryComputer } public T setUrl(String url) { - return setURI(UriComponents.create(url)); + return setUri(Uri.create(url)); } - public T setURI(UriComponents uri) { + public T setUri(Uri uri) { request.uri = uri; return derived.cast(this); } diff --git a/src/main/java/com/ning/http/client/Response.java b/src/main/java/com/ning/http/client/Response.java index 55fd8e00ed..ad21f6938e 100644 --- a/src/main/java/com/ning/http/client/Response.java +++ b/src/main/java/com/ning/http/client/Response.java @@ -17,7 +17,7 @@ package com.ning.http.client; import com.ning.http.client.cookie.Cookie; -import com.ning.http.client.uri.UriComponents; +import com.ning.http.client.uri.Uri; import java.io.IOException; import java.io.InputStream; @@ -111,11 +111,11 @@ public interface Response { String getResponseBody() throws IOException; /** - * Return the request {@link UriComponents}. Note that if the request got redirected, the value of the {@link URI} will be the last valid redirect url. + * Return the request {@link Uri}. Note that if the request got redirected, the value of the {@link URI} will be the last valid redirect url. * - * @return the request {@link UriComponents}. + * @return the request {@link Uri}. */ - UriComponents getUri(); + Uri getUri(); /** * Return the content-type header value. diff --git a/src/main/java/com/ning/http/client/ResponseBase.java b/src/main/java/com/ning/http/client/ResponseBase.java index 45605f73b8..7e96ae9be2 100644 --- a/src/main/java/com/ning/http/client/ResponseBase.java +++ b/src/main/java/com/ning/http/client/ResponseBase.java @@ -16,7 +16,7 @@ import static com.ning.http.util.MiscUtils.isNonEmpty; import com.ning.http.client.cookie.Cookie; -import com.ning.http.client.uri.UriComponents; +import com.ning.http.client.uri.Uri; import com.ning.http.util.AsyncHttpProviderUtils; import java.nio.charset.Charset; @@ -59,7 +59,7 @@ public final String getStatusText() { } @Override - public final UriComponents getUri() { + public final Uri getUri() { return status.getUri(); } diff --git a/src/main/java/com/ning/http/client/SimpleAsyncHttpClient.java b/src/main/java/com/ning/http/client/SimpleAsyncHttpClient.java index c99a578cc9..4af6283a62 100644 --- a/src/main/java/com/ning/http/client/SimpleAsyncHttpClient.java +++ b/src/main/java/com/ning/http/client/SimpleAsyncHttpClient.java @@ -20,7 +20,7 @@ import com.ning.http.client.resumable.ResumableIOExceptionFilter; import com.ning.http.client.simple.HeaderMap; import com.ning.http.client.simple.SimpleAHCTransferListener; -import com.ning.http.client.uri.UriComponents; +import com.ning.http.client.uri.Uri; import javax.net.ssl.SSLContext; @@ -276,7 +276,7 @@ private Future execute(RequestBuilder rb, BodyConsumer bodyConsumer, T } Request request = rb.build(); - ProgressAsyncHandler handler = new BodyConsumerAsyncHandler(bodyConsumer, throwableHandler, errorDocumentBehaviour, request.getURI(), listener); + ProgressAsyncHandler handler = new BodyConsumerAsyncHandler(bodyConsumer, throwableHandler, errorDocumentBehaviour, request.getUri(), listener); if (resumeEnabled && request.getMethod().equals("GET") && bodyConsumer != null && bodyConsumer instanceof ResumableBodyConsumer) { @@ -710,7 +710,7 @@ private final static class BodyConsumerAsyncHandler extends AsyncCompletionHandl private final BodyConsumer bodyConsumer; private final ThrowableHandler exceptionHandler; private final ErrorDocumentBehaviour errorDocumentBehaviour; - private final UriComponents uri; + private final Uri uri; private final SimpleAHCTransferListener listener; private boolean accumulateBody = false; @@ -718,7 +718,7 @@ private final static class BodyConsumerAsyncHandler extends AsyncCompletionHandl private int amount = 0; private long total = -1; - public BodyConsumerAsyncHandler(BodyConsumer bodyConsumer, ThrowableHandler exceptionHandler, ErrorDocumentBehaviour errorDocumentBehaviour, UriComponents uri, SimpleAHCTransferListener listener) { + public BodyConsumerAsyncHandler(BodyConsumer bodyConsumer, ThrowableHandler exceptionHandler, ErrorDocumentBehaviour errorDocumentBehaviour, Uri uri, SimpleAHCTransferListener listener) { this.bodyConsumer = bodyConsumer; this.exceptionHandler = exceptionHandler; this.errorDocumentBehaviour = errorDocumentBehaviour; @@ -837,7 +837,7 @@ private void fireHeaders(HttpResponseHeaders headers) { } } - private void fireSent(UriComponents uri, long amount, long current, long total) { + private void fireSent(Uri uri, long amount, long current, long total) { if (listener != null) { listener.onBytesSent(uri, amount, current, total); } 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 7058ae927f..283f09380c 100644 --- a/src/main/java/com/ning/http/client/oauth/OAuthSignatureCalculator.java +++ b/src/main/java/com/ning/http/client/oauth/OAuthSignatureCalculator.java @@ -22,7 +22,7 @@ import com.ning.http.client.Request; import com.ning.http.client.RequestBuilderBase; import com.ning.http.client.SignatureCalculator; -import com.ning.http.client.uri.UriComponents; +import com.ning.http.client.uri.Uri; import com.ning.http.util.Base64; import com.ning.http.util.StandardCharsets; import com.ning.http.util.UTF8UrlEncoder; @@ -85,7 +85,7 @@ public OAuthSignatureCalculator(ConsumerKey consumerAuth, RequestToken userAuth) public void calculateAndAddSignature(Request request, RequestBuilderBase requestBuilder) { String nonce = generateNonce(); long timestamp = System.currentTimeMillis() / 1000L; - String signature = calculateSignature(request.getMethod(), request.getURI(), timestamp, nonce, request.getFormParams(), request.getQueryParams()); + String signature = calculateSignature(request.getMethod(), request.getUri(), timestamp, nonce, request.getFormParams(), request.getQueryParams()); String headerValue = constructAuthHeader(signature, nonce, timestamp); requestBuilder.setHeader(HEADER_AUTHORIZATION, headerValue); } @@ -93,7 +93,7 @@ public void calculateAndAddSignature(Request request, RequestBuilderBase requ /** * Method for calculating OAuth signature using HMAC/SHA-1 method. */ - public String calculateSignature(String method, UriComponents uri, long oauthTimestamp, String nonce, + public String calculateSignature(String method, Uri uri, long oauthTimestamp, String nonce, List formParams, List queryParams) { StringBuilder signedText = new StringBuilder(100); signedText.append(method); // POST / GET etc (nothing to URL encode) 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 6c7de4d8a2..035268bcd4 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 @@ -78,7 +78,7 @@ import com.ning.http.client.multipart.Part; import com.ning.http.client.multipart.StringPart; import com.ning.http.client.resumable.ResumableAsyncHandler; -import com.ning.http.client.uri.UriComponents; +import com.ning.http.client.uri.Uri; import com.ning.http.util.AsyncHttpProviderUtils; import com.ning.http.util.ProxyUtils; import com.ning.http.util.StandardCharsets; @@ -452,7 +452,7 @@ public T call() { terminate = true; AsyncHandler.STATE state = AsyncHandler.STATE.ABORT; try { - UriComponents uri = request.getURI(); + Uri uri = request.getUri(); int delay = AsyncHttpProviderUtils.requestTimeout(config, future.getRequest()); if (delay != -1) { @@ -500,14 +500,14 @@ public T call() { if (currentRedirectCount++ < config.getMaxRedirects()) { String location = method.getResponseHeader("Location").getValue(); - UriComponents rediUri = UriComponents.create(uri, location); + Uri rediUri = Uri.create(uri, location); if (!rediUri.equals(uri)) { RequestBuilder builder = new RequestBuilder(request); logger.debug("Redirecting to {}", rediUri); - request = builder.setURI(rediUri).build(); + request = builder.setUri(rediUri).build(); method = createMethod(httpClient, request); terminate = false; return call(); diff --git a/src/main/java/com/ning/http/client/providers/apache/ApacheResponseStatus.java b/src/main/java/com/ning/http/client/providers/apache/ApacheResponseStatus.java index e7009f56db..930750bc33 100644 --- a/src/main/java/com/ning/http/client/providers/apache/ApacheResponseStatus.java +++ b/src/main/java/com/ning/http/client/providers/apache/ApacheResponseStatus.java @@ -19,7 +19,7 @@ import com.ning.http.client.HttpResponseHeaders; import com.ning.http.client.HttpResponseStatus; import com.ning.http.client.Response; -import com.ning.http.client.uri.UriComponents; +import com.ning.http.client.uri.Uri; import java.util.List; @@ -30,7 +30,7 @@ public class ApacheResponseStatus extends HttpResponseStatus { private final HttpMethodBase method; - public ApacheResponseStatus(UriComponents uri, AsyncHttpClientConfig config, HttpMethodBase method) { + public ApacheResponseStatus(Uri uri, AsyncHttpClientConfig config, HttpMethodBase method) { super(uri, config); this.method = method; } 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 0f0ebaca81..55d8d37298 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 @@ -107,7 +107,7 @@ import com.ning.http.client.multipart.MultipartUtils; import com.ning.http.client.multipart.Part; import com.ning.http.client.ntlm.NTLMEngine; -import com.ning.http.client.uri.UriComponents; +import com.ning.http.client.uri.Uri; import com.ning.http.client.websocket.WebSocket; import com.ning.http.client.websocket.WebSocketByteListener; import com.ning.http.client.websocket.WebSocketCloseCodeReasonListener; @@ -524,7 +524,7 @@ void timeout(final Connection c) { } - static int getPort(final UriComponents uri, final int p) { + static int getPort(final Uri uri, final int p) { int port = p; if (port == -1) { final String protocol = uri.getScheme().toLowerCase(Locale.ENGLISH); @@ -596,7 +596,7 @@ static final class HttpTransactionContext { final GrizzlyAsyncHttpProvider provider; Request request; - UriComponents requestUri; + Uri requestUri; AsyncHandler handler; BodyHandler bodyHandler; StatusHandler statusHandler; @@ -608,7 +608,7 @@ static final class HttpTransactionContext { AtomicLong totalBodyWritten = new AtomicLong(); AsyncHandler.STATE currentState; - UriComponents wsRequestURI; + Uri wsRequestURI; boolean isWSRequest; HandShake handshake; ProtocolHandler protocolHandler; @@ -667,7 +667,7 @@ static HttpTransactionContext get(final Connection c) { this.handler = handler; redirectsAllowed = provider.clientConfig.isFollowRedirect(); maxRedirectCount = provider.clientConfig.getMaxRedirects(); - this.requestUri = request.getURI(); + this.requestUri = request.getUri(); } @@ -847,7 +847,7 @@ private boolean sendAsGrizzlyRequest(final Request request, convertToUpgradeRequest(httpCtx); } final Request req = httpCtx.request; - final UriComponents uri = req.getURI(); + final Uri uri = req.getUri(); final Method method = Method.valueOf(request.getMethod()); final HttpRequestPacket.Builder builder = HttpRequestPacket.builder(); boolean secure = "https".equals(uri.getScheme()); @@ -900,7 +900,7 @@ private boolean sendAsGrizzlyRequest(final Request request, HttpRequestPacket requestPacket; if (httpCtx.isWSRequest && !httpCtx.establishingTunnel) { try { - final URI wsURI = httpCtx.wsRequestURI.toURI(); + final URI wsURI = httpCtx.wsRequestURI.toJavaNetURI(); secure = "wss".equalsIgnoreCase(wsURI.getScheme()); httpCtx.protocolHandler = Version.RFC6455.createHandler(true); httpCtx.handshake = httpCtx.protocolHandler.createHandShake(wsURI); @@ -1008,13 +1008,13 @@ private boolean isUpgradeRequest(final AsyncHandler handler) { } - private boolean isWSRequest(final UriComponents requestUri) { + private boolean isWSRequest(final Uri requestUri) { return requestUri.getScheme().startsWith("ws"); } private void convertToUpgradeRequest(final HttpTransactionContext ctx) { - final UriComponents requestUri = ctx.requestUri; + final Uri requestUri = ctx.requestUri; ctx.wsRequestURI = requestUri; ctx.requestUri = requestUri.withNewScheme( @@ -1247,7 +1247,7 @@ protected void onInitialLineParsed(HttpHeader httpHeader, } final GrizzlyResponseStatus responseStatus = new GrizzlyResponseStatus((HttpResponsePacket) httpHeader, - context.request.getURI(), + context.request.getUri(), provider.clientConfig); context.responseStatus = responseStatus; if (context.statusHandler != null) { @@ -1578,7 +1578,7 @@ public boolean handleStatus(final HttpResponsePacket responsePacket, final Request req = httpTransactionContext.request; realm = new Realm.RealmBuilder().clone(realm) .setScheme(realm.getAuthScheme()) - .setUri(httpTransactionContext.request.getURI()) + .setUri(httpTransactionContext.request.getUri()) .setMethodName(req.getMethod()) .setUsePreemptiveAuth(true) .parseWWWAuthenticateHeader(auth) @@ -1655,16 +1655,16 @@ public boolean handleStatus(final HttpResponsePacket responsePacket, throw new IllegalStateException("redirect received, but no location header was present"); } - UriComponents orig; + Uri orig; if (httpTransactionContext.lastRedirectURI == null) { - orig = httpTransactionContext.request.getURI(); + orig = httpTransactionContext.request.getUri(); } else { - orig = UriComponents.create(httpTransactionContext.request.getURI(), + orig = Uri.create(httpTransactionContext.request.getUri(), httpTransactionContext.lastRedirectURI); } httpTransactionContext.lastRedirectURI = redirectURL; Request requestToSend; - UriComponents uri = UriComponents.create(orig, redirectURL); + Uri uri = Uri.create(orig, redirectURL); if (!uri.toUrl().equalsIgnoreCase(orig.toUrl())) { requestToSend = newRequest(uri, responsePacket, @@ -1697,7 +1697,7 @@ public boolean handleStatus(final HttpResponsePacket responsePacket, httpTransactionContext.future = null; newContext.invocationStatus = InvocationStatus.CONTINUE; newContext.request = requestToSend; - newContext.requestUri = requestToSend.getURI(); + newContext.requestUri = requestToSend.getUri(); HttpTransactionContext.set(c, newContext); httpTransactionContext.provider.execute(c, requestToSend, @@ -1726,8 +1726,8 @@ private boolean sendAsGet(final HttpResponsePacket response, } - private boolean switchingSchemes(final UriComponents oldUri, - final UriComponents newUri) { + private boolean switchingSchemes(final Uri oldUri, + final Uri newUri) { return !oldUri.getScheme().equals(newUri.getScheme()); @@ -1735,7 +1735,7 @@ private boolean switchingSchemes(final UriComponents oldUri, private void notifySchemeSwitch(final FilterChainContext ctx, final Connection c, - final UriComponents uri) throws IOException { + final Uri uri) throws IOException { ctx.notifyDownstream(new SwitchingSSLFilter.SSLSwitchingEvent( "https".equals(uri.getScheme()), c)); @@ -1747,7 +1747,7 @@ private void notifySchemeSwitch(final FilterChainContext ctx, // ----------------------------------------------------- Private Methods - private static Request newRequest(final UriComponents uri, + private static Request newRequest(final Uri uri, final HttpResponsePacket response, final HttpTransactionContext ctx, boolean asGet) { @@ -2403,7 +2403,7 @@ void doAsyncConnect(final Request request, throws IOException, ExecutionException, InterruptedException { ProxyServer proxy = requestFuture.getProxy(); - final UriComponents uri = request.getURI(); + final Uri uri = request.getUri(); String host = ((proxy != null) ? proxy.getHost() : uri.getHost()); int port = ((proxy != null) ? proxy.getPort() : uri.getPort()); @@ -2437,7 +2437,7 @@ private Connection obtainConnection0(final Request request, final GrizzlyResponseFuture requestFuture) throws IOException, ExecutionException, InterruptedException, TimeoutException { - final UriComponents uri = request.getURI(); + 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(); @@ -2520,7 +2520,7 @@ public void updated(Connection result) { } private static String getPoolKey(Request request, ProxyServer proxyServer) { - return request.getConnectionPoolKeyStrategy().getKey(request.getURI(), proxyServer); + return request.getConnectionPoolKeyStrategy().getKey(request.getUri(), proxyServer); } // ------------------------------------------------------ Nested Classes diff --git a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponseStatus.java b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponseStatus.java index a9684b544c..9117d7439c 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponseStatus.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/GrizzlyResponseStatus.java @@ -18,7 +18,7 @@ import com.ning.http.client.HttpResponseHeaders; import com.ning.http.client.HttpResponseStatus; import com.ning.http.client.Response; -import com.ning.http.client.uri.UriComponents; +import com.ning.http.client.uri.Uri; import java.util.List; @@ -40,7 +40,7 @@ public class GrizzlyResponseStatus extends HttpResponseStatus { public GrizzlyResponseStatus(final HttpResponsePacket response, - final UriComponents uri, + final Uri uri, final AsyncHttpClientConfig config) { super(uri, config); diff --git a/src/main/java/com/ning/http/client/providers/grizzly/Utils.java b/src/main/java/com/ning/http/client/providers/grizzly/Utils.java index 658f656aa3..631bf3f9f5 100644 --- a/src/main/java/com/ning/http/client/providers/grizzly/Utils.java +++ b/src/main/java/com/ning/http/client/providers/grizzly/Utils.java @@ -13,7 +13,7 @@ package com.ning.http.client.providers.grizzly; -import com.ning.http.client.uri.UriComponents; +import com.ning.http.client.uri.Uri; public class Utils { // ------------------------------------------------------------ Constructors @@ -27,7 +27,7 @@ public static boolean isSecure(final String uri) { return (uri.startsWith("https") || uri.startsWith("wss")); } - public static boolean isSecure(final UriComponents uri) { + public static boolean isSecure(final Uri uri) { final String scheme = uri.getScheme(); return ("https".equals(scheme) || "wss".equals(scheme)); } 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 ccc4a97d25..4650f013ea 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 @@ -38,7 +38,7 @@ import com.ning.http.client.filter.IOExceptionFilter; import com.ning.http.client.filter.ResponseFilter; import com.ning.http.client.listener.TransferCompletionHandler; -import com.ning.http.client.uri.UriComponents; +import com.ning.http.client.uri.Uri; import com.ning.http.util.AsyncHttpProviderUtils; import com.ning.http.util.AuthenticatorUtils; import com.ning.http.util.ProxyUtils; @@ -174,9 +174,9 @@ private HttpURLConnection createUrlConnection(Request request) throws IOExceptio } HttpURLConnection urlConnection = (HttpURLConnection) - request.getURI().toURI().toURL().openConnection(proxy == null ? Proxy.NO_PROXY : proxy); + request.getUri().toJavaNetURI().toURL().openConnection(proxy == null ? Proxy.NO_PROXY : proxy); - if (request.getURI().getScheme().equals("https")) { + if (request.getUri().getScheme().equals("https")) { HttpsURLConnection secure = (HttpsURLConnection) urlConnection; SSLContext sslContext = config.getSSLContext(); if (sslContext == null) { @@ -221,7 +221,7 @@ public AsyncHttpUrlConnection(HttpURLConnection urlConnection, Request request, public T call() throws Exception { AsyncHandler.STATE state = AsyncHandler.STATE.ABORT; try { - UriComponents uri = request.getURI(); + Uri uri = request.getUri(); configure(uri, urlConnection, request); urlConnection.connect(); @@ -255,14 +255,14 @@ public T call() throws Exception { if (currentRedirectCount++ < config.getMaxRedirects()) { String location = urlConnection.getHeaderField("Location"); - UriComponents redirUri = UriComponents.create(uri, location); + Uri redirUri = Uri.create(uri, location); if (!redirUri.equals(uri)) { RequestBuilder builder = new RequestBuilder(request); logger.debug("Redirecting to {}", redirUri); - request = builder.setURI(redirUri).build(); + request = builder.setUri(redirUri).build(); urlConnection = createUrlConnection(request); terminate = false; return call(); @@ -276,11 +276,11 @@ public T call() throws Exception { if (statusCode == 401 && !isAuth.getAndSet(true) && realm != null) { String wwwAuth = urlConnection.getHeaderField("WWW-Authenticate"); - logger.debug("Sending authentication to {}", request.getURI()); + logger.debug("Sending authentication to {}", request.getUri()); Realm nr = new Realm.RealmBuilder().clone(realm) .parseWWWAuthenticateHeader(wwwAuth) - .setUri(request.getURI()) + .setUri(request.getUri()) .setMethodName(request.getMethod()) .setUsePreemptiveAuth(true) .build(); @@ -424,7 +424,7 @@ private Throwable filterException(Throwable t) { return t; } - private void configure(UriComponents uri, HttpURLConnection urlConnection, Request request) throws IOException, AuthenticationException { + private void configure(Uri uri, HttpURLConnection urlConnection, Request request) throws IOException, AuthenticationException { int requestTimeout = AsyncHttpProviderUtils.requestTimeout(config, request); diff --git a/src/main/java/com/ning/http/client/providers/jdk/ResponseHeaders.java b/src/main/java/com/ning/http/client/providers/jdk/ResponseHeaders.java index 672093beb9..9d6050e1d1 100644 --- a/src/main/java/com/ning/http/client/providers/jdk/ResponseHeaders.java +++ b/src/main/java/com/ning/http/client/providers/jdk/ResponseHeaders.java @@ -15,7 +15,7 @@ import com.ning.http.client.AsyncHttpProvider; import com.ning.http.client.FluentCaseInsensitiveStringsMap; import com.ning.http.client.HttpResponseHeaders; -import com.ning.http.client.uri.UriComponents; +import com.ning.http.client.uri.Uri; import java.net.HttpURLConnection; import java.util.List; @@ -28,7 +28,7 @@ public class ResponseHeaders extends HttpResponseHeaders { private final FluentCaseInsensitiveStringsMap headers; - public ResponseHeaders(UriComponents uri, HttpURLConnection urlConnection, AsyncHttpProvider provider) { + public ResponseHeaders(Uri uri, HttpURLConnection urlConnection, AsyncHttpProvider provider) { headers = computerHeaders(urlConnection); } diff --git a/src/main/java/com/ning/http/client/providers/jdk/ResponseStatus.java b/src/main/java/com/ning/http/client/providers/jdk/ResponseStatus.java index d9d506e297..fe93ce5025 100644 --- a/src/main/java/com/ning/http/client/providers/jdk/ResponseStatus.java +++ b/src/main/java/com/ning/http/client/providers/jdk/ResponseStatus.java @@ -17,7 +17,7 @@ import com.ning.http.client.HttpResponseHeaders; import com.ning.http.client.HttpResponseStatus; import com.ning.http.client.Response; -import com.ning.http.client.uri.UriComponents; +import com.ning.http.client.uri.Uri; import java.io.IOException; import java.net.HttpURLConnection; @@ -30,7 +30,7 @@ public class ResponseStatus extends HttpResponseStatus { private final HttpURLConnection urlConnection; - public ResponseStatus(UriComponents uri, AsyncHttpClientConfig config, HttpURLConnection urlConnection) { + public ResponseStatus(Uri uri, AsyncHttpClientConfig config, HttpURLConnection urlConnection) { super(uri, config); this.urlConnection = urlConnection; } diff --git a/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java b/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java index db15d3e084..7e0456fcac 100644 --- a/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java +++ b/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java @@ -394,7 +394,7 @@ public void upgradeProtocol(ChannelPipeline pipeline, String scheme, String host } public String getPoolKey(NettyResponseFuture future) { - return future.getConnectionPoolKeyStrategy().getKey(future.getURI(), future.getProxyServer()); + return future.getConnectionPoolKeyStrategy().getKey(future.getUri(), future.getProxyServer()); } public void verifyChannelPipeline(ChannelPipeline pipeline, String scheme) throws IOException, GeneralSecurityException { diff --git a/src/main/java/com/ning/http/client/providers/netty/future/NettyResponseFuture.java b/src/main/java/com/ning/http/client/providers/netty/future/NettyResponseFuture.java index 12e732a261..6522eb67c1 100755 --- a/src/main/java/com/ning/http/client/providers/netty/future/NettyResponseFuture.java +++ b/src/main/java/com/ning/http/client/providers/netty/future/NettyResponseFuture.java @@ -28,7 +28,7 @@ import com.ning.http.client.providers.netty.channel.Channels; import com.ning.http.client.providers.netty.request.NettyRequest; import com.ning.http.client.providers.netty.request.timeout.TimeoutsHolder; -import com.ning.http.client.uri.UriComponents; +import com.ning.http.client.uri.Uri; import java.net.SocketAddress; import java.util.concurrent.CancellationException; @@ -81,7 +81,7 @@ public enum STATE { // state mutated only inside the event loop private Channel channel; - private UriComponents uri; + private Uri uri; private boolean keepAlive = true; private Request request; private NettyRequest nettyRequest; @@ -93,7 +93,7 @@ public enum STATE { private boolean dontWriteBodyBecauseExpectContinue; private boolean allowConnect; - public NettyResponseFuture(UriComponents uri,// + public NettyResponseFuture(Uri uri,// Request request,// AsyncHandler asyncHandler,// NettyRequest nettyRequest,// @@ -245,11 +245,11 @@ public void touch() { /** INTERNAL **/ /*********************************************/ - public UriComponents getURI() { + public Uri getUri() { return uri; } - public void setURI(UriComponents uri) { + public void setUri(Uri uri) { this.uri = uri; } diff --git a/src/main/java/com/ning/http/client/providers/netty/handler/HttpProtocol.java b/src/main/java/com/ning/http/client/providers/netty/handler/HttpProtocol.java index 8e92b16042..6ccc73e394 100644 --- a/src/main/java/com/ning/http/client/providers/netty/handler/HttpProtocol.java +++ b/src/main/java/com/ning/http/client/providers/netty/handler/HttpProtocol.java @@ -49,7 +49,7 @@ import com.ning.http.client.providers.netty.response.NettyResponseHeaders; import com.ning.http.client.providers.netty.response.NettyResponseStatus; import com.ning.http.client.providers.netty.spnego.SpnegoEngine; -import com.ning.http.client.uri.UriComponents; +import com.ning.http.client.uri.Uri; import java.io.IOException; import java.util.List; @@ -75,7 +75,7 @@ private Realm kerberosChallenge(Channel channel,// boolean proxyInd) throws NTLMEngineException { - UriComponents uri = request.getURI(); + Uri uri = request.getUri(); String host = request.getVirtualHost() == null ? uri.getHost() : request.getVirtualHost(); String server = proxyServer == null ? host : proxyServer.getHost(); try { @@ -115,7 +115,7 @@ private Realm ntlmChallenge(List wwwAuth, Request request, ProxyServer p String ntlmHost = useRealm ? realm.getNtlmHost() : proxyServer.getHost(); String principal = useRealm ? realm.getPrincipal() : proxyServer.getPrincipal(); String password = useRealm ? realm.getPassword() : proxyServer.getPassword(); - UriComponents uri = request.getURI(); + Uri uri = request.getUri(); if (realm != null && !realm.isNtlmMessageType2Received()) { String challengeHeader = NTLMEngine.INSTANCE.generateType1Msg(ntlmDomain, ntlmHost); @@ -151,7 +151,7 @@ private Realm ntlmProxyChallenge(List wwwAuth, Request request, ProxySer return newRealmBuilder(realm)// // .setScheme(realm.getAuthScheme()) - .setUri(request.getURI())// + .setUri(request.getUri())// .setMethodName(request.getMethod()).build(); } @@ -231,7 +231,7 @@ private boolean exitAfterHandling401(// newRealm = new Realm.RealmBuilder()// .clone(realm)// .setScheme(realm.getAuthScheme())// - .setUri(request.getURI())// + .setUri(request.getUri())// .setMethodName(request.getMethod())// .setUsePreemptiveAuth(true)// .parseWWWAuthenticateHeader(wwwAuthHeaders.get(0))// @@ -241,7 +241,7 @@ private boolean exitAfterHandling401(// Realm nr = newRealm; final Request nextRequest = new RequestBuilder(future.getRequest()).setHeaders(requestHeaders).setRealm(nr).build(); - logger.debug("Sending authentication to {}", request.getURI()); + logger.debug("Sending authentication to {}", request.getUri()); Callback callback = new Callback(future) { public void call() throws Exception { channelManager.drainChannel(channel, future); @@ -289,7 +289,7 @@ private boolean exitAfterHandling407(// List proxyAuthHeaders = response.headers().getAll(HttpHeaders.Names.PROXY_AUTHENTICATE); if (!proxyAuthHeaders.isEmpty()) { - logger.debug("Sending proxy authentication to {}", request.getURI()); + logger.debug("Sending proxy authentication to {}", request.getUri()); future.setState(NettyResponseFuture.STATE.NEW); Realm newRealm = null; @@ -306,7 +306,7 @@ private boolean exitAfterHandling407(// } else { newRealm = new Realm.RealmBuilder().clone(realm)// .setScheme(realm.getAuthScheme())// - .setUri(request.getURI())// + .setUri(request.getUri())// .setOmitQuery(true)// .setMethodName(HttpMethod.CONNECT.getName())// .setUsePreemptiveAuth(true)// @@ -338,10 +338,10 @@ private boolean exitAfterHandlingConnect(// future.attachChannel(channel, true); try { - UriComponents requestURI = request.getURI(); - String scheme = requestURI.getScheme(); - String host = requestURI.getHost(); - int port = getDefaultPort(requestURI); + Uri requestUri = request.getUri(); + String scheme = requestUri.getScheme(); + String host = requestUri.getHost(); + int port = getDefaultPort(requestUri); logger.debug("Connecting to proxy {} for scheme {}", proxyServer, scheme); channelManager.upgradeProtocol(channel.getPipeline(), scheme, host, port); @@ -406,7 +406,7 @@ private boolean handleHttpResponse(final HttpResponse response,// future.setKeepAlive(!HttpHeaders.Values.CLOSE.equalsIgnoreCase(response.headers().get(HttpHeaders.Names.CONNECTION))); - NettyResponseStatus status = new NettyResponseStatus(future.getURI(), config, response); + NettyResponseStatus status = new NettyResponseStatus(future.getUri(), config, response); int statusCode = response.getStatus().getCode(); Request request = future.getRequest(); Realm realm = request.getRealm() != null ? request.getRealm() : config.getRealm(); diff --git a/src/main/java/com/ning/http/client/providers/netty/handler/Protocol.java b/src/main/java/com/ning/http/client/providers/netty/handler/Protocol.java index 3205b70c47..c3ac3d3074 100644 --- a/src/main/java/com/ning/http/client/providers/netty/handler/Protocol.java +++ b/src/main/java/com/ning/http/client/providers/netty/handler/Protocol.java @@ -46,7 +46,7 @@ import com.ning.http.client.providers.netty.channel.Channels; import com.ning.http.client.providers.netty.future.NettyResponseFuture; import com.ning.http.client.providers.netty.request.NettyRequestSender; -import com.ning.http.client.uri.UriComponents; +import com.ning.http.client.uri.Uri; import java.io.IOException; import java.util.HashSet; @@ -108,9 +108,9 @@ protected boolean exitAfterHandlingRedirect(// HttpHeaders responseHeaders = response.headers(); String location = responseHeaders.get(HttpHeaders.Names.LOCATION); - UriComponents uri = UriComponents.create(future.getURI(), location); + Uri uri = Uri.create(future.getUri(), location); - if (!uri.equals(future.getURI())) { + if (!uri.equals(future.getUri())) { final RequestBuilder requestBuilder = new RequestBuilder(future.getRequest()); if (!config.isRemoveQueryParamOnRedirect()) @@ -125,9 +125,9 @@ protected boolean exitAfterHandlingRedirect(// final boolean initialConnectionKeepAlive = future.isKeepAlive(); final String initialPoolKey = channelManager.getPoolKey(future); - future.setURI(uri); + future.setUri(uri); String newUrl = uri.toUrl(); - if (request.getURI().getScheme().startsWith(WEBSOCKET)) { + if (request.getUri().getScheme().startsWith(WEBSOCKET)) { newUrl = newUrl.replaceFirst(HTTP, WEBSOCKET); } diff --git a/src/main/java/com/ning/http/client/providers/netty/handler/WebSocketProtocol.java b/src/main/java/com/ning/http/client/providers/netty/handler/WebSocketProtocol.java index 6548363c79..6aba8a24c5 100644 --- a/src/main/java/com/ning/http/client/providers/netty/handler/WebSocketProtocol.java +++ b/src/main/java/com/ning/http/client/providers/netty/handler/WebSocketProtocol.java @@ -75,7 +75,7 @@ public void handle(Channel channel, NettyResponseFuture future, Object e) thr if (e instanceof HttpResponse) { HttpResponse response = (HttpResponse) e; - HttpResponseStatus status = new NettyResponseStatus(future.getURI(), config, response); + HttpResponseStatus status = new NettyResponseStatus(future.getUri(), config, response); HttpResponseHeaders responseHeaders = new NettyResponseHeaders(response.headers()); if (exitAfterProcessingFilters(channel, future, handler, status, responseHeaders)) { @@ -93,7 +93,7 @@ public void handle(Channel channel, NettyResponseFuture future, Object e) thr connection = response.headers().get(HttpHeaders.Names.CONNECTION.toLowerCase(Locale.ENGLISH)); boolean validConnection = HttpHeaders.Values.UPGRADE.equalsIgnoreCase(connection); - status = new NettyResponseStatus(future.getURI(), config, response); + status = new NettyResponseStatus(future.getUri(), config, response); final boolean statusReceived = handler.onStatusReceived(status) == STATE.UPGRADE; if (!statusReceived) { diff --git a/src/main/java/com/ning/http/client/providers/netty/request/NettyConnectListener.java b/src/main/java/com/ning/http/client/providers/netty/request/NettyConnectListener.java index 45fe22fd81..2ea10bffdf 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/NettyConnectListener.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/NettyConnectListener.java @@ -95,7 +95,7 @@ public final void operationComplete(ChannelFuture f) throws Exception { final HostnameVerifier hostnameVerifier = config.getHostnameVerifier(); if (hostnameVerifier != null && sslHandler != null) { - final String host = future.getURI().getHost(); + final String host = future.getUri().getHost(); sslHandler.handshake().addListener(new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture handshakeFuture) throws Exception { @@ -139,8 +139,7 @@ public void operationComplete(ChannelFuture handshakeFuture) throws Exception { LOGGER.debug("Failed to recover from exception: {} with channel {}", cause, f.getChannel()); boolean printCause = f.getCause() != null && cause.getMessage() != null; - ConnectException e = new ConnectException(printCause ? cause.getMessage() + " to " + future.getURI().toString() : future - .getURI().toString()); + ConnectException e = new ConnectException(printCause ? cause.getMessage() + " to " + future.getUri() : future.getUri()); if (cause != null) { e.initCause(cause); } diff --git a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestFactory.java b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestFactory.java index f9b9881511..0b40daea91 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestFactory.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestFactory.java @@ -51,7 +51,7 @@ import com.ning.http.client.providers.netty.request.body.NettyInputStreamBody; import com.ning.http.client.providers.netty.request.body.NettyMultipartBody; import com.ning.http.client.providers.netty.spnego.SpnegoEngine; -import com.ning.http.client.uri.UriComponents; +import com.ning.http.client.uri.Uri; import com.ning.http.util.UTF8UrlEncoder; import java.io.IOException; @@ -72,7 +72,7 @@ public NettyRequestFactory(AsyncHttpClientConfig config, NettyAsyncHttpProviderC this.nettyConfig = nettyConfig; } - private String requestUri(UriComponents uri, ProxyServer proxyServer, HttpMethod method) { + private String requestUri(Uri uri, ProxyServer proxyServer, HttpMethod method) { if (method == HttpMethod.CONNECT) return getAuthority(uri); @@ -88,12 +88,12 @@ else if (proxyServer != null && !(useProxyConnect(uri) && config.isUseRelativeUR } } - private String hostHeader(Request request, UriComponents uri) { + private String hostHeader(Request request, Uri uri) { String host = request.getVirtualHost() != null ? request.getVirtualHost() : uri.getHost(); return request.getVirtualHost() != null || uri.getPort() == -1 ? host : host + ":" + uri.getPort(); } - private String authorizationHeader(Request request, UriComponents uri, ProxyServer proxyServer, Realm realm) throws IOException { + private String authorizationHeader(Request request, Uri uri, ProxyServer proxyServer, Realm realm) throws IOException { String authorizationHeader = null; @@ -241,7 +241,7 @@ else if (request.getBodyGenerator() != null) return nettyBody; } - public NettyRequest newNettyRequest(Request request, UriComponents uri, boolean forceConnect, ProxyServer proxyServer) + public NettyRequest newNettyRequest(Request request, Uri uri, boolean forceConnect, ProxyServer proxyServer) throws IOException { HttpMethod method = forceConnect ? HttpMethod.CONNECT : HttpMethod.valueOf(request.getMethod()); diff --git a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java index 6b2b9f1369..a65aa1ba17 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java @@ -51,7 +51,7 @@ import com.ning.http.client.providers.netty.request.timeout.ReadTimeoutTimerTask; import com.ning.http.client.providers.netty.request.timeout.RequestTimeoutTimerTask; import com.ning.http.client.providers.netty.request.timeout.TimeoutsHolder; -import com.ning.http.client.uri.UriComponents; +import com.ning.http.client.uri.Uri; import com.ning.http.client.websocket.WebSocketUpgradeHandler; import java.io.IOException; @@ -90,7 +90,7 @@ public ListenableFuture sendRequest(final Request request,// if (closed.get()) throw new IOException("Closed"); - UriComponents uri = request.getURI(); + Uri uri = request.getUri(); // FIXME really useful? Why not do this check when building the request? if (uri.getScheme().startsWith(WEBSOCKET) && !validateWebSocketRequest(request, asyncHandler)) @@ -123,7 +123,7 @@ private ListenableFuture sendRequestWithCertainForceConnect(// AsyncHandler asyncHandler,// NettyResponseFuture future,// boolean reclaimCache,// - UriComponents uri,// + Uri uri,// ProxyServer proxyServer,// boolean useProxy,// boolean forceConnect) throws IOException { @@ -148,7 +148,7 @@ private ListenableFuture sendRequestThroughSslProxy(// AsyncHandler asyncHandler,// NettyResponseFuture future,// boolean reclaimCache,// - UriComponents uri,// + Uri uri,// ProxyServer proxyServer) throws IOException { NettyResponseFuture newFuture = null; @@ -171,7 +171,7 @@ private ListenableFuture sendRequestThroughSslProxy(// } private NettyResponseFuture newNettyRequestAndResponseFuture(final Request request, final AsyncHandler asyncHandler, - NettyResponseFuture originalFuture, UriComponents uri, ProxyServer proxy, boolean forceConnect) throws IOException { + NettyResponseFuture originalFuture, Uri uri, ProxyServer proxy, boolean forceConnect) throws IOException { NettyRequest nettyRequest = requestFactory.newNettyRequest(request, uri, forceConnect, proxy); @@ -184,7 +184,7 @@ private NettyResponseFuture newNettyRequestAndResponseFuture(final Reques } } - private Channel getCachedChannel(NettyResponseFuture future, UriComponents uri, ConnectionPoolKeyStrategy poolKeyGen, + private Channel getCachedChannel(NettyResponseFuture future, Uri uri, ConnectionPoolKeyStrategy poolKeyGen, ProxyServer proxyServer, AsyncHandler asyncHandler) { if (future != null && future.reuseChannel() && Channels.isChannelValid(future.channel())) @@ -193,7 +193,7 @@ private Channel getCachedChannel(NettyResponseFuture future, UriComponents ur return pollAndVerifyCachedChannel(uri, proxyServer, poolKeyGen, asyncHandler); } - private ListenableFuture sendRequestWithCachedChannel(Request request, UriComponents uri, ProxyServer proxy, + private ListenableFuture sendRequestWithCachedChannel(Request request, Uri uri, ProxyServer proxy, NettyResponseFuture future, AsyncHandler asyncHandler, Channel channel) throws IOException { if (asyncHandler instanceof AsyncHandlerExtensions) @@ -228,7 +228,7 @@ private ListenableFuture sendRequestWithCachedChannel(Request request, Ur private ListenableFuture sendRequestWithNewChannel(// Request request,// - UriComponents uri,// + Uri uri,// ProxyServer proxy,// boolean useProxy,// NettyResponseFuture future,// @@ -240,7 +240,7 @@ private ListenableFuture sendRequestWithNewChannel(// // Do not throw an exception when we need an extra connection for a // redirect // FIXME why? This violate the max connection per host handling, right? - ClientBootstrap bootstrap = channelManager.getBootstrap(request.getURI().getScheme(), useProxy, useSSl); + ClientBootstrap bootstrap = channelManager.getBootstrap(request.getUri().getScheme(), useProxy, useSSl); boolean channelPreempted = false; String poolKey = null; @@ -273,7 +273,7 @@ private ListenableFuture sendRequestWithNewChannel(// return future; } - private NettyResponseFuture newNettyResponseFuture(UriComponents uri, Request request, AsyncHandler asyncHandler, + private NettyResponseFuture newNettyResponseFuture(Uri uri, Request request, AsyncHandler asyncHandler, NettyRequest nettyRequest, ProxyServer proxyServer) { NettyResponseFuture future = new NettyResponseFuture(// @@ -330,7 +330,7 @@ public void writeRequest(NettyResponseFuture future, Channel channel) { scheduleTimeouts(future); } - private InetSocketAddress remoteAddress(Request request, UriComponents uri, ProxyServer proxy, boolean useProxy) { + private InetSocketAddress remoteAddress(Request request, Uri uri, ProxyServer proxy, boolean useProxy) { if (request.getInetAddress() != null) return new InetSocketAddress(request.getInetAddress(), getDefaultPort(uri)); @@ -341,7 +341,7 @@ else if (!useProxy || avoidProxy(proxy, uri.getHost())) return new InetSocketAddress(proxy.getHost(), proxy.getPort()); } - private ChannelFuture connect(Request request, UriComponents uri, ProxyServer proxy, boolean useProxy, ClientBootstrap bootstrap) { + private ChannelFuture connect(Request request, Uri uri, ProxyServer proxy, boolean useProxy, ClientBootstrap bootstrap) { InetSocketAddress remoteAddress = remoteAddress(request, uri, proxy, useProxy); if (request.getLocalAddress() != null) @@ -462,7 +462,7 @@ private boolean validateWebSocketRequest(Request request, AsyncHandler asyncH return request.getMethod().equals(HttpMethod.GET.getName()) && asyncHandler instanceof WebSocketUpgradeHandler; } - public Channel pollAndVerifyCachedChannel(UriComponents uri, ProxyServer proxy, ConnectionPoolKeyStrategy connectionPoolKeyStrategy, AsyncHandler asyncHandler) { + public Channel pollAndVerifyCachedChannel(Uri uri, ProxyServer proxy, ConnectionPoolKeyStrategy connectionPoolKeyStrategy, AsyncHandler asyncHandler) { if (asyncHandler instanceof AsyncHandlerExtensions) AsyncHandlerExtensions.class.cast(asyncHandler).onPoolConnection(); diff --git a/src/main/java/com/ning/http/client/providers/netty/response/NettyResponseStatus.java b/src/main/java/com/ning/http/client/providers/netty/response/NettyResponseStatus.java index f2640b93d0..12b61db391 100644 --- a/src/main/java/com/ning/http/client/providers/netty/response/NettyResponseStatus.java +++ b/src/main/java/com/ning/http/client/providers/netty/response/NettyResponseStatus.java @@ -18,7 +18,7 @@ import com.ning.http.client.HttpResponseHeaders; import com.ning.http.client.HttpResponseStatus; import com.ning.http.client.Response; -import com.ning.http.client.uri.UriComponents; +import com.ning.http.client.uri.Uri; import java.util.List; @@ -31,7 +31,7 @@ public class NettyResponseStatus extends HttpResponseStatus { private final HttpResponse response; - public NettyResponseStatus(UriComponents uri, AsyncHttpClientConfig config, HttpResponse response) { + public NettyResponseStatus(Uri uri, AsyncHttpClientConfig config, HttpResponse response) { super(uri, config); this.response = response; } diff --git a/src/main/java/com/ning/http/client/providers/netty/util/HttpUtils.java b/src/main/java/com/ning/http/client/providers/netty/util/HttpUtils.java index 663be5c39f..b130873459 100644 --- a/src/main/java/com/ning/http/client/providers/netty/util/HttpUtils.java +++ b/src/main/java/com/ning/http/client/providers/netty/util/HttpUtils.java @@ -17,7 +17,7 @@ import org.jboss.netty.handler.codec.http.HttpHeaders; -import com.ning.http.client.uri.UriComponents; +import com.ning.http.client.uri.Uri; import java.util.ArrayList; import java.util.List; @@ -55,11 +55,11 @@ public static boolean isSecure(String scheme) { return HTTPS.equals(scheme) || WEBSOCKET_SSL.equals(scheme); } - public static boolean isSecure(UriComponents uri) { + public static boolean isSecure(Uri uri) { return isSecure(uri.getScheme()); } - public static boolean useProxyConnect(UriComponents uri) { + public static boolean useProxyConnect(Uri uri) { return isSecure(uri) || isWebSocket(uri.getScheme()); } } diff --git a/src/main/java/com/ning/http/client/simple/SimpleAHCTransferListener.java b/src/main/java/com/ning/http/client/simple/SimpleAHCTransferListener.java index b25aa8eeaa..4f512bcf50 100644 --- a/src/main/java/com/ning/http/client/simple/SimpleAHCTransferListener.java +++ b/src/main/java/com/ning/http/client/simple/SimpleAHCTransferListener.java @@ -14,7 +14,7 @@ */ import com.ning.http.client.SimpleAsyncHttpClient; -import com.ning.http.client.uri.UriComponents; +import com.ning.http.client.uri.Uri; /** * A simple transfer listener for use with the {@link SimpleAsyncHttpClient}. @@ -34,7 +34,7 @@ public interface SimpleAHCTransferListener { * @param statusCode the received status code. * @param statusText the received status text. */ - void onStatus(UriComponents uri, int statusCode, String statusText); + void onStatus(Uri uri, int statusCode, String statusText); /** * This method is called after the response headers are received. @@ -42,7 +42,7 @@ public interface SimpleAHCTransferListener { * @param uri the uri * @param headers the received headers, never {@code null}. */ - void onHeaders(UriComponents uri, HeaderMap headers); + void onHeaders(Uri uri, HeaderMap headers); /** * This method is called when bytes of the responses body are received. @@ -54,7 +54,7 @@ public interface SimpleAHCTransferListener { * @param total the total number of bytes to be transferred. This is taken * from the Content-Length-header and may be unspecified (-1). */ - void onBytesReceived(UriComponents uri, long amount, long current, long total); + void onBytesReceived(Uri uri, long amount, long current, long total); /** * This method is called when bytes are sent. @@ -66,7 +66,7 @@ public interface SimpleAHCTransferListener { * @param total the total number of bytes to be transferred. This is taken * from the Content-Length-header and may be unspecified (-1). */ - void onBytesSent(UriComponents uri, long amount, long current, long total); + void onBytesSent(Uri uri, long amount, long current, long total); /** * This method is called when the request is completed. @@ -75,6 +75,6 @@ public interface SimpleAHCTransferListener { * @param statusCode the received status code. * @param statusText the received status text. */ - void onCompleted(UriComponents uri, int statusCode, String statusText); + void onCompleted(Uri uri, int statusCode, String statusText); } diff --git a/src/main/java/com/ning/http/client/uri/UriComponents.java b/src/main/java/com/ning/http/client/uri/Uri.java similarity index 88% rename from src/main/java/com/ning/http/client/uri/UriComponents.java rename to src/main/java/com/ning/http/client/uri/Uri.java index 3c9ef33c74..8767c9968a 100644 --- a/src/main/java/com/ning/http/client/uri/UriComponents.java +++ b/src/main/java/com/ning/http/client/uri/Uri.java @@ -18,17 +18,17 @@ import java.net.URI; import java.net.URISyntaxException; -public class UriComponents { +public class Uri { - public static UriComponents create(String originalUrl) { + public static Uri create(String originalUrl) { return create(null, originalUrl); } - public static UriComponents create(UriComponents context, final String originalUrl) { - UriComponentsParser parser = new UriComponentsParser(); + public static Uri create(Uri context, final String originalUrl) { + UriParser parser = new UriParser(); parser.parse(context, originalUrl); - return new UriComponents(parser.scheme,// + return new Uri(parser.scheme,// parser.userInfo,// parser.host,// parser.port,// @@ -44,7 +44,7 @@ public static UriComponents create(UriComponents context, final String originalU private final String path; private String url; - public UriComponents(String scheme,// + public Uri(String scheme,// String userInfo,// String host,// int port,// @@ -88,7 +88,7 @@ public String getHost() { return host; } - public URI toURI() throws URISyntaxException { + public URI toJavaNetURI() throws URISyntaxException { return new URI(toUrl()); } @@ -129,8 +129,8 @@ public String toString() { return toUrl(); } - public UriComponents withNewScheme(String newScheme) { - return new UriComponents(newScheme,// + public Uri withNewScheme(String newScheme) { + return new Uri(newScheme,// userInfo,// host,// port,// @@ -138,8 +138,8 @@ public UriComponents withNewScheme(String newScheme) { query); } - public UriComponents withNewQuery(String newQuery) { - return new UriComponents(scheme,// + public Uri withNewQuery(String newQuery) { + return new Uri(scheme,// userInfo,// host,// port,// @@ -168,7 +168,7 @@ public boolean equals(Object obj) { return false; if (getClass() != obj.getClass()) return false; - UriComponents other = (UriComponents) obj; + Uri other = (Uri) obj; if (host == null) { if (other.host != null) return false; diff --git a/src/main/java/com/ning/http/client/uri/UriComponentsParser.java b/src/main/java/com/ning/http/client/uri/UriParser.java similarity index 97% rename from src/main/java/com/ning/http/client/uri/UriComponentsParser.java rename to src/main/java/com/ning/http/client/uri/UriParser.java index 930b893592..979b31a885 100644 --- a/src/main/java/com/ning/http/client/uri/UriComponentsParser.java +++ b/src/main/java/com/ning/http/client/uri/UriParser.java @@ -13,7 +13,7 @@ */ package com.ning.http.client.uri; -final class UriComponentsParser { +final class UriParser { public String scheme; public String host; @@ -75,7 +75,7 @@ private void computeInitialScheme(String originalUrl) { } } - private boolean overrideWithContext(UriComponents context, String originalUrl) { + private boolean overrideWithContext(Uri context, String originalUrl) { boolean isRelative = false; @@ -106,7 +106,7 @@ private void computeFragment(String originalUrl) { } } - private void inheritContextQuery(UriComponents context, boolean isRelative) { + private void inheritContextQuery(Uri context, boolean isRelative) { // see RFC2396 5.2.2: query and fragment inheritance if (isRelative && start == end) { query = context.getQuery(); @@ -315,7 +315,7 @@ else if (path == null) path = ""; } - public void parse(UriComponents context, final String originalUrl) { + public void parse(Uri context, final String originalUrl) { if (originalUrl == null) throw new NullPointerException("originalUrl"); 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 239ad73843..a18b09f729 100644 --- a/src/main/java/com/ning/http/client/webdav/WebDavCompletionHandlerBase.java +++ b/src/main/java/com/ning/http/client/webdav/WebDavCompletionHandlerBase.java @@ -29,7 +29,7 @@ import com.ning.http.client.HttpResponseStatus; import com.ning.http.client.Response; import com.ning.http.client.cookie.Cookie; -import com.ning.http.client.uri.UriComponents; +import com.ning.http.client.uri.Uri; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; @@ -167,7 +167,7 @@ public String getResponseBody() throws IOException { } @Override - public UriComponents getUri() { + public Uri getUri() { return wrappedResponse.getUri(); } 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 f8beebf5e7..5c7e3d773d 100644 --- a/src/main/java/com/ning/http/client/webdav/WebDavResponse.java +++ b/src/main/java/com/ning/http/client/webdav/WebDavResponse.java @@ -22,7 +22,7 @@ import com.ning.http.client.FluentCaseInsensitiveStringsMap; import com.ning.http.client.Response; import com.ning.http.client.cookie.Cookie; -import com.ning.http.client.uri.UriComponents; +import com.ning.http.client.uri.Uri; /** * Customized {@link Response} which add support for getting the response's body as an XML document (@link WebDavResponse#getBodyAsXML} @@ -74,7 +74,7 @@ public String getResponseBody(String charset) throws IOException { return response.getResponseBody(charset); } - public UriComponents getUri() { + public Uri getUri() { return response.getUri(); } diff --git a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java index e5cbd569cc..2fcf77a4c3 100644 --- a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java +++ b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java @@ -19,7 +19,7 @@ import com.ning.http.client.HttpResponseBodyPartsInputStream; import com.ning.http.client.Param; import com.ning.http.client.Request; -import com.ning.http.client.uri.UriComponents; +import com.ning.http.client.uri.Uri; import java.io.ByteArrayInputStream; import java.io.IOException; @@ -39,7 +39,7 @@ public class AsyncHttpProviderUtils { static final byte[] EMPTY_BYTE_ARRAY = "".getBytes(); - public static final void validateSupportedScheme(UriComponents uri) { + 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")) { @@ -48,11 +48,11 @@ public static final void validateSupportedScheme(UriComponents uri) { } } - public final static String getBaseUrl(UriComponents uri) { + public final static String getBaseUrl(Uri uri) { return uri.getScheme() + "://" + getAuthority(uri); } - public final static String getAuthority(UriComponents uri) { + public final static String getAuthority(Uri uri) { int port = uri.getPort() != -1 ? uri.getPort() : getDefaultPort(uri); return uri.getHost() + ":" + port; } @@ -87,7 +87,7 @@ public final static InputStream contentToInputStream(List return bodyParts.isEmpty() ? new ByteArrayInputStream(EMPTY_BYTE_ARRAY) : new HttpResponseBodyPartsInputStream(bodyParts); } - public final static int getDefaultPort(UriComponents uri) { + public final static int getDefaultPort(Uri uri) { int port = uri.getPort(); if (port == -1) port = uri.getScheme().equals("http") || uri.getScheme().equals("ws") ? 80 : 443; @@ -99,7 +99,7 @@ public final static int getDefaultPort(UriComponents uri) { * * @return the raw path or "/" if it's null */ - public final static String getNonEmptyPath(UriComponents uri) { + public final static String getNonEmptyPath(Uri uri) { return isNonEmpty(uri.getPath()) ? uri.getPath() : "/"; } diff --git a/src/main/java/com/ning/http/util/AuthenticatorUtils.java b/src/main/java/com/ning/http/util/AuthenticatorUtils.java index dc2f2d68f8..baf6f9af06 100644 --- a/src/main/java/com/ning/http/util/AuthenticatorUtils.java +++ b/src/main/java/com/ning/http/util/AuthenticatorUtils.java @@ -17,7 +17,7 @@ import com.ning.http.client.ProxyServer; import com.ning.http.client.Realm; -import com.ning.http.client.uri.UriComponents; +import com.ning.http.client.uri.Uri; import java.io.UnsupportedEncodingException; import java.security.NoSuchAlgorithmException; @@ -35,7 +35,7 @@ public static String computeBasicAuthentication(ProxyServer proxyServer) throws } private static String computeRealmURI(Realm realm) { - UriComponents uri = realm.getUri(); + Uri uri = realm.getUri(); if (realm.isTargetProxy()) { return "/"; } else { diff --git a/src/main/java/com/ning/http/util/ProxyUtils.java b/src/main/java/com/ning/http/util/ProxyUtils.java index 67427af23e..ce461a2e91 100644 --- a/src/main/java/com/ning/http/util/ProxyUtils.java +++ b/src/main/java/com/ning/http/util/ProxyUtils.java @@ -16,7 +16,7 @@ import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.ProxyServer; import com.ning.http.client.ProxyServer.Protocol; -import com.ning.http.client.uri.UriComponents; +import com.ning.http.client.uri.Uri; import com.ning.http.client.ProxyServerSelector; import com.ning.http.client.Request; @@ -85,7 +85,7 @@ public static ProxyServer getProxyServer(AsyncHttpClientConfig config, Request r if (proxyServer == null) { ProxyServerSelector selector = config.getProxyServerSelector(); if (selector != null) { - proxyServer = selector.select(request.getURI()); + proxyServer = selector.select(request.getUri()); } } return ProxyUtils.avoidProxy(proxyServer, request) ? null : proxyServer; @@ -95,7 +95,7 @@ public static ProxyServer getProxyServer(AsyncHttpClientConfig config, Request r * @see #avoidProxy(ProxyServer, String) */ public static boolean avoidProxy(final ProxyServer proxyServer, final Request request) { - return avoidProxy(proxyServer, request.getURI().getHost()); + return avoidProxy(proxyServer, request.getUri().getHost()); } private static boolean matchNonProxyHost(String targetHost, String nonProxyHost) { @@ -200,9 +200,9 @@ public static ProxyServerSelector getJdkDefaultProxyServerSelector() { */ public static ProxyServerSelector createProxyServerSelector(final ProxySelector proxySelector) { return new ProxyServerSelector() { - public ProxyServer select(UriComponents uri) { + public ProxyServer select(Uri uri) { try { - URI javaUri = uri.toURI(); + URI javaUri = uri.toJavaNetURI(); List proxies = proxySelector.select(javaUri); if (proxies != null) { @@ -242,7 +242,7 @@ public ProxyServer select(UriComponents uri) { */ public static ProxyServerSelector createProxyServerSelector(final ProxyServer proxyServer) { return new ProxyServerSelector() { - public ProxyServer select(UriComponents uri) { + public ProxyServer select(Uri uri) { return proxyServer; } }; diff --git a/src/test/java/com/ning/http/client/RealmTest.java b/src/test/java/com/ning/http/client/RealmTest.java index 5d6e319b27..43be2b07b1 100644 --- a/src/test/java/com/ning/http/client/RealmTest.java +++ b/src/test/java/com/ning/http/client/RealmTest.java @@ -14,7 +14,7 @@ import com.ning.http.client.Realm.AuthScheme; import com.ning.http.client.Realm.RealmBuilder; -import com.ning.http.client.uri.UriComponents; +import com.ning.http.client.uri.Uri; import com.ning.http.util.StandardCharsets; import org.testng.Assert; @@ -62,7 +62,7 @@ private void testOldDigest(String qop) { String realm = "realm"; String nonce = "nonce"; String method = "GET"; - UriComponents uri = UriComponents.create("http://ahc.io/foo"); + Uri uri = Uri.create("http://ahc.io/foo"); RealmBuilder builder = new RealmBuilder(); builder.setPrincipal(user).setPassword(pass); builder.setNonce(nonce); @@ -87,7 +87,7 @@ public void testStrongDigest() { String realm = "realm"; String nonce = "nonce"; String method = "GET"; - UriComponents uri = UriComponents.create("http://ahc.io/foo"); + Uri uri = Uri.create("http://ahc.io/foo"); String qop = "auth"; RealmBuilder builder = new RealmBuilder(); builder.setPrincipal(user).setPassword(pass); 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 6992cd3118..4061ad75df 100644 --- a/src/test/java/com/ning/http/client/async/PerRequestRelative302Test.java +++ b/src/test/java/com/ning/http/client/async/PerRequestRelative302Test.java @@ -18,7 +18,7 @@ import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.Response; -import com.ning.http.client.uri.UriComponents; +import com.ning.http.client.uri.Uri; import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.Request; @@ -124,7 +124,7 @@ public void notRedirected302Test() throws Throwable { } } - private String getBaseUrl(UriComponents uri) { + private String getBaseUrl(Uri uri) { String url = uri.toString(); int port = uri.getPort(); if (port == -1) { @@ -134,7 +134,7 @@ private String getBaseUrl(UriComponents uri) { return url.substring(0, url.lastIndexOf(":") + String.valueOf(port).length() + 1); } - private static int getPort(UriComponents uri) { + private static int getPort(Uri uri) { int port = uri.getPort(); if (port == -1) port = uri.getScheme().equals("http") ? 80 : 443; 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 8f1264df54..a5804933fa 100644 --- a/src/test/java/com/ning/http/client/async/Relative302Test.java +++ b/src/test/java/com/ning/http/client/async/Relative302Test.java @@ -18,7 +18,7 @@ import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.Response; -import com.ning.http.client.uri.UriComponents; +import com.ning.http.client.uri.Uri; import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.Request; @@ -108,7 +108,7 @@ public void redirected302Test() throws Throwable { } } - private String getBaseUrl(UriComponents uri) { + private String getBaseUrl(Uri uri) { String url = uri.toString(); int port = uri.getPort(); if (port == -1) { @@ -118,7 +118,7 @@ private String getBaseUrl(UriComponents uri) { return url.substring(0, url.lastIndexOf(":") + String.valueOf(port).length() + 1); } - private static int getPort(UriComponents uri) { + private static int getPort(Uri uri) { int port = uri.getPort(); if (port == -1) port = uri.getScheme().equals("http") ? 80 : 443; diff --git a/src/test/java/com/ning/http/client/async/RequestBuilderTest.java b/src/test/java/com/ning/http/client/async/RequestBuilderTest.java index e65437a00c..1573c22119 100644 --- a/src/test/java/com/ning/http/client/async/RequestBuilderTest.java +++ b/src/test/java/com/ning/http/client/async/RequestBuilderTest.java @@ -85,7 +85,7 @@ public void testChaining() throws IOException, ExecutionException, InterruptedEx Request request2 = new RequestBuilder(request).build(); - assertEquals(request2.getURI(), request.getURI()); + assertEquals(request2.getUri(), request.getUri()); } @Test(groups = {"standalone", "default_provider"}) @@ -139,6 +139,6 @@ public void testRawUrlQuery() throws UnsupportedEncodingException, URISyntaxExce RequestBuilder rb = new RequestBuilder("GET", true).setUrl(preEncodedUrl); Request request = rb.build(); assertEquals(request.getUrl(), preEncodedUrl); - assertEquals(request.getURI().toURI().toString(), preEncodedUrl); + assertEquals(request.getUri().toJavaNetURI().toString(), preEncodedUrl); } } 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 4cb6e3973d..68c7a67dd7 100644 --- a/src/test/java/com/ning/http/client/async/SimpleAsyncHttpClientTest.java +++ b/src/test/java/com/ning/http/client/async/SimpleAsyncHttpClientTest.java @@ -31,7 +31,7 @@ import com.ning.http.client.multipart.ByteArrayPart; import com.ning.http.client.simple.HeaderMap; import com.ning.http.client.simple.SimpleAHCTransferListener; -import com.ning.http.client.uri.UriComponents; +import com.ning.http.client.uri.Uri; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -173,29 +173,29 @@ public void testSimpleTransferListener() throws Exception { SimpleAHCTransferListener listener = new SimpleAHCTransferListener() { - public void onStatus(UriComponents uri, int statusCode, String statusText) { + public void onStatus(Uri uri, int statusCode, String statusText) { assertEquals(statusCode, 200); assertEquals(uri.toUrl(), getTargetUrl()); } - public void onHeaders(UriComponents uri, HeaderMap headers) { + public void onHeaders(Uri uri, HeaderMap headers) { assertEquals(uri.toUrl(), getTargetUrl()); assertNotNull(headers); assertTrue(!headers.isEmpty()); assertEquals(headers.getFirstValue("X-Custom"), "custom"); } - public void onCompleted(UriComponents uri, int statusCode, String statusText) { + public void onCompleted(Uri uri, int statusCode, String statusText) { assertEquals(statusCode, 200); assertEquals(uri.toUrl(), getTargetUrl()); } - public void onBytesSent(UriComponents uri, long amount, long current, long total) { + public void onBytesSent(Uri uri, long amount, long current, long total) { assertEquals(uri.toUrl(), getTargetUrl()); assertEquals(total, MY_MESSAGE.getBytes().length); } - public void onBytesReceived(UriComponents uri, long amount, long current, long total) { + public void onBytesReceived(Uri uri, long amount, long current, long total) { assertEquals(uri.toUrl(), getTargetUrl()); assertEquals(total, -1); } diff --git a/src/test/java/com/ning/http/client/oauth/TestSignatureCalculator.java b/src/test/java/com/ning/http/client/oauth/TestSignatureCalculator.java index 08df681c96..e26c9e4211 100644 --- a/src/test/java/com/ning/http/client/oauth/TestSignatureCalculator.java +++ b/src/test/java/com/ning/http/client/oauth/TestSignatureCalculator.java @@ -19,7 +19,7 @@ import org.testng.annotations.Test; import com.ning.http.client.Param; -import com.ning.http.client.uri.UriComponents; +import com.ning.http.client.uri.Uri; import java.util.ArrayList; import java.util.List; @@ -48,7 +48,7 @@ public void test() { queryParams.add(new Param("file", "vacation.jpg")); queryParams.add(new Param("size", "original")); String url = "http://photos.example.net/photos"; - String sig = calc.calculateSignature("GET", UriComponents.create(url), TIMESTAMP, NONCE, null, queryParams); + String sig = calc.calculateSignature("GET", Uri.create(url), TIMESTAMP, NONCE, null, queryParams); Assert.assertEquals("tR3+Ty81lMeYAr/Fid0kMTYa/WM=", sig); } diff --git a/src/test/java/com/ning/http/client/resumable/ResumableAsyncHandlerTest.java b/src/test/java/com/ning/http/client/resumable/ResumableAsyncHandlerTest.java index 3b620df322..552090828c 100644 --- a/src/test/java/com/ning/http/client/resumable/ResumableAsyncHandlerTest.java +++ b/src/test/java/com/ning/http/client/resumable/ResumableAsyncHandlerTest.java @@ -32,13 +32,13 @@ public void testAdjustRange() { ResumableAsyncHandler h = new ResumableAsyncHandler(proc); Request request = new RequestBuilder("GET").setUrl("http://test/url").build(); Request newRequest = h.adjustRequestRange(request); - assertEquals(newRequest.getURI(), request.getURI()); + assertEquals(newRequest.getUri(), request.getUri()); String rangeHeader = newRequest.getHeaders().getFirstValue("Range"); assertNull(rangeHeader); proc.put("http://test/url", 5000); newRequest = h.adjustRequestRange(request); - assertEquals(newRequest.getURI(), request.getURI()); + assertEquals(newRequest.getUri(), request.getUri()); rangeHeader = newRequest.getHeaders().getFirstValue("Range"); assertEquals(rangeHeader, "bytes=5000-"); } diff --git a/src/test/java/com/ning/http/client/uri/UriComponentsTest.java b/src/test/java/com/ning/http/client/uri/UriTest.java similarity index 69% rename from src/test/java/com/ning/http/client/uri/UriComponentsTest.java rename to src/test/java/com/ning/http/client/uri/UriTest.java index 45e98ac9e9..1c57c60c56 100644 --- a/src/test/java/com/ning/http/client/uri/UriComponentsTest.java +++ b/src/test/java/com/ning/http/client/uri/UriTest.java @@ -16,11 +16,11 @@ import static org.testng.Assert.assertEquals; -public class UriComponentsTest { +public class UriTest { @Test public void testSimpleParsing() { - UriComponents url = UriComponents.create("https://graph.facebook.com/750198471659552/accounts/test-users?method=get&access_token=750198471659552lleveCvbUu_zqBa9tkT3tcgaPh4"); + Uri url = Uri.create("https://graph.facebook.com/750198471659552/accounts/test-users?method=get&access_token=750198471659552lleveCvbUu_zqBa9tkT3tcgaPh4"); assertEquals(url.getScheme(), "https"); assertEquals(url.getHost(), "graph.facebook.com"); assertEquals(url.getPort(), -1); @@ -31,9 +31,9 @@ public void testSimpleParsing() { @Test public void testRootRelativeURIWithRootContext() { - UriComponents context = UriComponents.create("https://graph.facebook.com"); + Uri context = Uri.create("https://graph.facebook.com"); - UriComponents url = UriComponents.create(context, "/750198471659552/accounts/test-users?method=get&access_token=750198471659552lleveCvbUu_zqBa9tkT3tcgaPh4"); + Uri url = Uri.create(context, "/750198471659552/accounts/test-users?method=get&access_token=750198471659552lleveCvbUu_zqBa9tkT3tcgaPh4"); assertEquals(url.getScheme(), "https"); assertEquals(url.getHost(), "graph.facebook.com"); @@ -45,9 +45,9 @@ public void testRootRelativeURIWithRootContext() { @Test public void testRootRelativeURIWithNonRootContext() { - UriComponents context = UriComponents.create("https://graph.facebook.com/foo/bar"); + Uri context = Uri.create("https://graph.facebook.com/foo/bar"); - UriComponents url = UriComponents.create(context, "/750198471659552/accounts/test-users?method=get&access_token=750198471659552lleveCvbUu_zqBa9tkT3tcgaPh4"); + Uri url = Uri.create(context, "/750198471659552/accounts/test-users?method=get&access_token=750198471659552lleveCvbUu_zqBa9tkT3tcgaPh4"); assertEquals(url.getScheme(), "https"); assertEquals(url.getHost(), "graph.facebook.com"); @@ -59,9 +59,9 @@ public void testRootRelativeURIWithNonRootContext() { @Test public void testNonRootRelativeURIWithNonRootContext() { - UriComponents context = UriComponents.create("https://graph.facebook.com/foo/bar"); + Uri context = Uri.create("https://graph.facebook.com/foo/bar"); - UriComponents url = UriComponents.create(context, "750198471659552/accounts/test-users?method=get&access_token=750198471659552lleveCvbUu_zqBa9tkT3tcgaPh4"); + Uri url = Uri.create(context, "750198471659552/accounts/test-users?method=get&access_token=750198471659552lleveCvbUu_zqBa9tkT3tcgaPh4"); assertEquals(url.getScheme(), "https"); assertEquals(url.getHost(), "graph.facebook.com"); @@ -73,9 +73,9 @@ public void testNonRootRelativeURIWithNonRootContext() { @Test public void testAbsoluteURIWithContext() { - UriComponents context = UriComponents.create("https://hello.com/foo/bar"); + Uri context = Uri.create("https://hello.com/foo/bar"); - UriComponents url = UriComponents.create(context, "https://graph.facebook.com/750198471659552/accounts/test-users?method=get&access_token=750198471659552lleveCvbUu_zqBa9tkT3tcgaPh4"); + Uri url = Uri.create(context, "https://graph.facebook.com/750198471659552/accounts/test-users?method=get&access_token=750198471659552lleveCvbUu_zqBa9tkT3tcgaPh4"); assertEquals(url.getScheme(), "https"); assertEquals(url.getHost(), "graph.facebook.com"); From 89f6b3379e08712f70b81bf7a32d202482676b53 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 4 Sep 2014 10:09:13 +0200 Subject: [PATCH 568/701] Fix build --- .../client/providers/netty/request/NettyConnectListener.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/request/NettyConnectListener.java b/src/main/java/com/ning/http/client/providers/netty/request/NettyConnectListener.java index 2ea10bffdf..2306148161 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/NettyConnectListener.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/NettyConnectListener.java @@ -139,7 +139,7 @@ public void operationComplete(ChannelFuture handshakeFuture) throws Exception { LOGGER.debug("Failed to recover from exception: {} with channel {}", cause, f.getChannel()); boolean printCause = f.getCause() != null && cause.getMessage() != null; - ConnectException e = new ConnectException(printCause ? cause.getMessage() + " to " + future.getUri() : future.getUri()); + ConnectException e = new ConnectException(printCause ? cause.getMessage() + " to " + future.getUri().toUrl() : future.getUri().toUrl()); if (cause != null) { e.initCause(cause); } From 872f79dcd7ef2e13645f4fb5db4c1a2c5f11ed32 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 4 Sep 2014 10:17:52 +0200 Subject: [PATCH 569/701] Turn "compressionEnabled" into "compressionEnforced", close #692 --- .../http/client/AsyncHttpClientConfig.java | 28 +++++++++---------- .../client/AsyncHttpClientConfigDefaults.java | 4 +-- .../apache/ApacheAsyncHttpProvider.java | 24 ++++++++-------- .../grizzly/GrizzlyAsyncHttpProvider.java | 18 ++++++------ .../providers/jdk/JDKAsyncHttpProvider.java | 2 +- .../netty/channel/ChannelManager.java | 8 ++---- .../netty/request/NettyRequestFactory.java | 8 ++---- 7 files changed, 41 insertions(+), 51 deletions(-) diff --git a/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java b/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java index 68f5a09198..f20657a535 100644 --- a/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java @@ -68,7 +68,7 @@ public class AsyncHttpClientConfig { protected ProxyServerSelector proxyServerSelector; protected boolean useRelativeURIsWithConnectProxies; - protected boolean compressionEnabled; + protected boolean compressionEnforced; protected String userAgent; protected ExecutorService applicationThreadPool; protected Realm realm; @@ -104,7 +104,7 @@ private AsyncHttpClientConfig(int connectionTimeout,// ExecutorService applicationThreadPool,// ProxyServerSelector proxyServerSelector, // boolean useRelativeURIsWithConnectProxies, // - boolean compressionEnabled, // + boolean compressionEnforced, // String userAgent,// Realm realm,// List requestFilters,// @@ -135,7 +135,7 @@ private AsyncHttpClientConfig(int connectionTimeout,// this.strict302Handling = strict302Handling; this.proxyServerSelector = proxyServerSelector; this.useRelativeURIsWithConnectProxies = useRelativeURIsWithConnectProxies; - this.compressionEnabled = compressionEnabled; + this.compressionEnforced = compressionEnforced; this.userAgent = userAgent; this.applicationThreadPool = applicationThreadPool == null ? Executors.newCachedThreadPool() : applicationThreadPool; this.realm = realm; @@ -250,12 +250,12 @@ public String getUserAgent() { } /** - * Is HTTP compression enabled. + * Is HTTP compression enforced. * - * @return true if compression is enabled + * @return true if compression is enforced */ - public boolean isCompressionEnabled() { - return compressionEnabled; + public boolean isCompressionEnforced() { + return compressionEnforced; } /** @@ -474,7 +474,7 @@ public static class Builder { private boolean useProxySelector = defaultUseProxySelector(); private boolean useProxyProperties = defaultUseProxyProperties(); private boolean useRelativeURIsWithConnectProxies = defaultUseRelativeURIsWithConnectProxies(); - private boolean compressionEnabled = defaultCompressionEnabled(); + private boolean compressionEnforced = defaultCompressionEnforced(); private String userAgent = defaultUserAgent(); private ExecutorService applicationThreadPool; private Realm realm; @@ -595,13 +595,13 @@ public Builder setMaxRedirects(int maxRedirects) { } /** - * Enable HTTP compression. + * Enforce HTTP compression. * - * @param compressionEnabled true if compression is enabled + * @param compressionEnforced true if compression is enforced * @return a {@link Builder} */ - public Builder setCompressionEnabled(boolean compressionEnabled) { - this.compressionEnabled = compressionEnabled; + public Builder setCompressionEnabled(boolean compressionEnforced) { + this.compressionEnforced = compressionEnforced; return this; } @@ -924,7 +924,7 @@ public Builder(AsyncHttpClientConfig prototype) { sslContext = prototype.getSSLContext(); userAgent = prototype.getUserAgent(); followRedirect = prototype.isFollowRedirect(); - compressionEnabled = prototype.isCompressionEnabled(); + compressionEnforced = prototype.isCompressionEnforced(); applicationThreadPool = prototype.executorService(); requestFilters.clear(); @@ -996,7 +996,7 @@ else if (hostnameVerifier == null) applicationThreadPool, // proxyServerSelector, // useRelativeURIsWithConnectProxies, // - compressionEnabled, // + compressionEnforced, // userAgent,// realm,// requestFilters, // diff --git a/src/main/java/com/ning/http/client/AsyncHttpClientConfigDefaults.java b/src/main/java/com/ning/http/client/AsyncHttpClientConfigDefaults.java index 147c26aef7..f0cd38456b 100644 --- a/src/main/java/com/ning/http/client/AsyncHttpClientConfigDefaults.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClientConfigDefaults.java @@ -61,8 +61,8 @@ public static int defaultMaxRedirects() { return Integer.getInteger(ASYNC_CLIENT + "maxRedirects", 5); } - public static boolean defaultCompressionEnabled() { - return Boolean.getBoolean(ASYNC_CLIENT + "compressionEnabled"); + public static boolean defaultCompressionEnforced() { + return Boolean.getBoolean(ASYNC_CLIENT + "compressionEnforced"); } public static String defaultUserAgent() { 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 035268bcd4..afd6232886 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 @@ -387,21 +387,19 @@ private HttpMethodBase createMethod(HttpClient client, Request request) throws I method.setRequestHeader("User-Agent", config.getUserAgent()); } - if (config.isCompressionEnabled()) { - Header acceptableEncodingHeader = method.getRequestHeader("Accept-Encoding"); - if (acceptableEncodingHeader != null) { - String acceptableEncodings = acceptableEncodingHeader.getValue(); - if (acceptableEncodings.indexOf("gzip") == -1) { - StringBuilder buf = new StringBuilder(acceptableEncodings); - if (buf.length() > 1) { - buf.append(","); - } - buf.append("gzip"); - method.setRequestHeader("Accept-Encoding", buf.toString()); + Header acceptableEncodingHeader = method.getRequestHeader("Accept-Encoding"); + if (acceptableEncodingHeader != null) { + String acceptableEncodings = acceptableEncodingHeader.getValue(); + if (acceptableEncodings.indexOf("gzip") == -1) { + StringBuilder buf = new StringBuilder(acceptableEncodings); + if (buf.length() > 1) { + buf.append(","); } - } else { - method.setRequestHeader("Accept-Encoding", "gzip"); + buf.append("gzip"); + method.setRequestHeader("Accept-Encoding", buf.toString()); } + } else if (config.isCompressionEnforced()) { + method.setRequestHeader("Accept-Encoding", "gzip"); } if (request.getVirtualHost() != 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 55d8d37298..8d89a835c8 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 @@ -394,7 +394,7 @@ public void onTimeout(Connection connection) { eventFilter.removeContentEncoding(encoding); } } - if (clientConfig.isCompressionEnabled()) { + if (clientConfig.isCompressionEnforced()) { eventFilter.addContentEncoding( new GZipContentEncoding(512, 512, @@ -1942,10 +1942,10 @@ public boolean doHandle(final FilterChainContext ctx, final byte[] data = request.getByteData(); final Buffer gBuffer = Buffers.wrap(mm, data); if (requestPacket.getContentLength() == -1) { - if (!clientConfig.isCompressionEnabled()) { - requestPacket.setContentLengthLong(data.length); - } + if (!clientConfig.isCompressionEnforced()) { + requestPacket.setContentLengthLong(data.length); } + } final HttpContent content = requestPacket.httpContentBuilder().content(gBuffer).build(); content.setLast(true); ctx.write(content, ((!requestPacket.isCommitted()) ? ctx.getTransportContext().getCompletionHandler() : null)); @@ -1958,7 +1958,7 @@ protected long getContentLength(final Request request) { return request.getContentLength(); } - return clientConfig.isCompressionEnabled() + return clientConfig.isCompressionEnforced() ? -1 : request.getByteData().length; } @@ -1989,7 +1989,7 @@ public boolean doHandle(final FilterChainContext ctx, final MemoryManager mm = ctx.getMemoryManager(); final Buffer gBuffer = Buffers.wrap(mm, data); if (requestPacket.getContentLength() == -1) { - if (!clientConfig.isCompressionEnabled()) { + if (!clientConfig.isCompressionEnforced()) { requestPacket.setContentLengthLong(data.length); } } @@ -2038,7 +2038,7 @@ public boolean doHandle(final FilterChainContext ctx, final MemoryManager mm = ctx.getMemoryManager(); final Buffer gBuffer = Buffers.wrap(mm, data); final HttpContent content = requestPacket.httpContentBuilder().content(gBuffer).build(); - if (requestPacket.getContentLength() == -1 && !clientConfig.isCompressionEnabled()) { + if (requestPacket.getContentLength() == -1 && !clientConfig.isCompressionEnforced()) { requestPacket.setContentLengthLong(data.length); } content.setLast(true); @@ -2191,7 +2191,7 @@ public boolean doHandle(final FilterChainContext ctx, final File f = request.getFile(); requestPacket.setContentLengthLong(f.length()); final HttpTransactionContext context = HttpTransactionContext.get(ctx.getConnection()); - if (clientConfig.isCompressionEnabled() || !SEND_FILE_SUPPORT || + if (clientConfig.isCompressionEnforced() || !SEND_FILE_SUPPORT || requestPacket.isSecure()) { final FileInputStream fis = new FileInputStream(request.getFile()); @@ -2251,7 +2251,7 @@ protected long getContentLength(final Request request) { return request.getContentLength(); } - return clientConfig.isCompressionEnabled() + return clientConfig.isCompressionEnforced() ? -1 : request.getFile().length(); } 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 4650f013ea..5e776d63c8 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 @@ -448,7 +448,7 @@ private void configure(Uri uri, HttpURLConnection urlConnection, Request request } - if (config.isCompressionEnabled()) { + if (config.isCompressionEnforced()) { urlConnection.setRequestProperty("Accept-Encoding", "gzip"); } diff --git a/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java b/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java index 7e0456fcac..61e390fcf1 100644 --- a/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java +++ b/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java @@ -195,15 +195,12 @@ public void configureBootstraps(NettyRequestSender requestSender, AtomicBoolean Protocol wsProtocol = new WebSocketProtocol(this, config, nettyConfig, requestSender); wsProcessor = new Processor(config, this, requestSender, wsProtocol); - final boolean compressionEnabled = config.isCompressionEnabled(); - plainBootstrap.setPipelineFactory(new ChannelPipelineFactory() { public ChannelPipeline getPipeline() throws Exception { ChannelPipeline pipeline = pipeline(); pipeline.addLast(HTTP_HANDLER, newHttpClientCodec()); - if (compressionEnabled) - pipeline.addLast(INFLATER_HANDLER, new HttpContentDecompressor()); + pipeline.addLast(INFLATER_HANDLER, new HttpContentDecompressor()); pipeline.addLast(CHUNKED_WRITER_HANDLER, new ChunkedWriteHandler()); pipeline.addLast(HTTP_PROCESSOR, httpProcessor); return pipeline; @@ -226,8 +223,7 @@ public ChannelPipeline getPipeline() throws Exception { ChannelPipeline pipeline = pipeline(); pipeline.addLast(SSL_HANDLER, new SslInitializer(ChannelManager.this)); pipeline.addLast(HTTP_HANDLER, newHttpClientCodec()); - if (compressionEnabled) - pipeline.addLast(INFLATER_HANDLER, new HttpContentDecompressor()); + pipeline.addLast(INFLATER_HANDLER, new HttpContentDecompressor()); pipeline.addLast(CHUNKED_WRITER_HANDLER, new ChunkedWriteHandler()); pipeline.addLast(HTTP_PROCESSOR, httpProcessor); return pipeline; diff --git a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestFactory.java b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestFactory.java index 0b40daea91..900f8cdc3e 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestFactory.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestFactory.java @@ -275,12 +275,8 @@ public NettyRequest newNettyRequest(Request request, Uri uri, boolean forceConne if (isNonEmpty(request.getCookies())) headers.set(HttpHeaders.Names.COOKIE, CookieEncoder.encode(request.getCookies())); - if (config.isCompressionEnabled()) { - if (!headers.contains(HttpHeaders.Names.ACCEPT_ENCODING)) - headers.set(HttpHeaders.Names.ACCEPT_ENCODING, GZIP_DEFLATE); - } else { - headers.remove(HttpHeaders.Names.ACCEPT_ENCODING); - } + if (config.isCompressionEnforced() && !headers.contains(HttpHeaders.Names.ACCEPT_ENCODING)) + headers.set(HttpHeaders.Names.ACCEPT_ENCODING, GZIP_DEFLATE); } if (body != null) { From f4381b39d2471cca17629b64954a26aa0d3d630a Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 4 Sep 2014 10:31:35 +0200 Subject: [PATCH 570/701] Fix previous commit --- .../com/ning/http/client/AsyncHttpClientConfigBean.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/ning/http/client/AsyncHttpClientConfigBean.java b/src/main/java/com/ning/http/client/AsyncHttpClientConfigBean.java index 35743b730e..301bfeda41 100644 --- a/src/main/java/com/ning/http/client/AsyncHttpClientConfigBean.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClientConfigBean.java @@ -55,7 +55,7 @@ void configureDefaults() { connectionTTL = defaultConnectionTTL(); followRedirect = defaultFollowRedirect(); maxRedirects = defaultMaxRedirects(); - compressionEnabled = defaultCompressionEnabled(); + compressionEnforced = defaultCompressionEnforced(); userAgent = defaultUserAgent(); allowPoolingConnections = defaultAllowPoolingConnections(); useRelativeURIsWithConnectProxies = defaultUseRelativeURIsWithConnectProxies(); @@ -134,8 +134,8 @@ public AsyncHttpClientConfigBean setMaxRedirects(int maxRedirects) { return this; } - public AsyncHttpClientConfigBean setCompressionEnabled(boolean compressionEnabled) { - this.compressionEnabled = compressionEnabled; + public AsyncHttpClientConfigBean setCompressionEnforced(boolean compressionEnforced) { + this.compressionEnforced = compressionEnforced; return this; } From 7aae712bf0743b5056ea0d1628669cc01fbd8362 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 4 Sep 2014 10:39:58 +0200 Subject: [PATCH 571/701] Don't depend on cache key for determining if ssl, close #690 --- .../providers/netty/channel/pool/DefaultChannelPool.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/channel/pool/DefaultChannelPool.java b/src/main/java/com/ning/http/client/providers/netty/channel/pool/DefaultChannelPool.java index 740e67e906..51795583f7 100644 --- a/src/main/java/com/ning/http/client/providers/netty/channel/pool/DefaultChannelPool.java +++ b/src/main/java/com/ning/http/client/providers/netty/channel/pool/DefaultChannelPool.java @@ -16,6 +16,7 @@ import static com.ning.http.util.DateUtils.millisTime; import org.jboss.netty.channel.Channel; +import org.jboss.netty.handler.ssl.SslHandler; import org.jboss.netty.util.Timeout; import org.jboss.netty.util.Timer; import org.jboss.netty.util.TimerTask; @@ -236,7 +237,7 @@ private ConcurrentLinkedQueue getPoolForKey(String key) { } public boolean offer(Channel channel, String poolKey) { - if (isClosed.get() || (!sslConnectionPoolEnabled && poolKey.startsWith("https"))) + if (isClosed.get() || (!sslConnectionPoolEnabled && channel.getPipeline().get(SslHandler.class) != null)) return false; long now = millisTime(); From d2fa1c8e704554df1b92bb189655947a9fbec291 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 4 Sep 2014 11:22:46 +0200 Subject: [PATCH 572/701] Rename ConnectionPoolKeyStrategy, close #694 --- ...y.java => ConnectionPoolPartitioning.java} | 4 +- ...a => PerHostConnectionPoolPartioning.java} | 4 +- .../java/com/ning/http/client/Request.java | 2 +- .../ning/http/client/RequestBuilderBase.java | 12 ++-- .../grizzly/GrizzlyAsyncHttpProvider.java | 8 +-- .../netty/channel/ChannelManager.java | 22 ++++--- .../netty/channel/pool/ChannelPool.java | 12 ++-- .../channel/pool/DefaultChannelPool.java | 60 +++++++++---------- .../netty/future/NettyResponseFuture.java | 12 ++-- .../providers/netty/handler/HttpProtocol.java | 2 +- .../providers/netty/handler/Protocol.java | 2 +- .../netty/request/NettyRequestSender.java | 16 ++--- 12 files changed, 79 insertions(+), 77 deletions(-) rename src/main/java/com/ning/http/client/{ConnectionPoolKeyStrategy.java => ConnectionPoolPartitioning.java} (86%) rename src/main/java/com/ning/http/client/{DefaultConnectionPoolStrategy.java => PerHostConnectionPoolPartioning.java} (85%) diff --git a/src/main/java/com/ning/http/client/ConnectionPoolKeyStrategy.java b/src/main/java/com/ning/http/client/ConnectionPoolPartitioning.java similarity index 86% rename from src/main/java/com/ning/http/client/ConnectionPoolKeyStrategy.java rename to src/main/java/com/ning/http/client/ConnectionPoolPartitioning.java index 96d506a523..6ce6e18457 100644 --- a/src/main/java/com/ning/http/client/ConnectionPoolKeyStrategy.java +++ b/src/main/java/com/ning/http/client/ConnectionPoolPartitioning.java @@ -17,7 +17,7 @@ import com.ning.http.client.uri.Uri; -public interface ConnectionPoolKeyStrategy { +public interface ConnectionPoolPartitioning { - String getKey(Uri uri, ProxyServer proxyServer); + String getPartitionId(Uri uri, ProxyServer proxyServer); } diff --git a/src/main/java/com/ning/http/client/DefaultConnectionPoolStrategy.java b/src/main/java/com/ning/http/client/PerHostConnectionPoolPartioning.java similarity index 85% rename from src/main/java/com/ning/http/client/DefaultConnectionPoolStrategy.java rename to src/main/java/com/ning/http/client/PerHostConnectionPoolPartioning.java index 900bd62b90..16e355603a 100644 --- a/src/main/java/com/ning/http/client/DefaultConnectionPoolStrategy.java +++ b/src/main/java/com/ning/http/client/PerHostConnectionPoolPartioning.java @@ -18,11 +18,11 @@ import com.ning.http.client.uri.Uri; import com.ning.http.util.AsyncHttpProviderUtils; -public enum DefaultConnectionPoolStrategy implements ConnectionPoolKeyStrategy { +public enum PerHostConnectionPoolPartioning implements ConnectionPoolPartitioning { INSTANCE; - public String getKey(Uri uri, ProxyServer proxyServer) { + public String getPartitionId(Uri uri, ProxyServer proxyServer) { String serverPart = AsyncHttpProviderUtils.getBaseUrl(uri); return proxyServer != null ? proxyServer.getUrl() + serverPart : serverPart; } diff --git a/src/main/java/com/ning/http/client/Request.java b/src/main/java/com/ning/http/client/Request.java index ac2275ffd6..31952de494 100644 --- a/src/main/java/com/ning/http/client/Request.java +++ b/src/main/java/com/ning/http/client/Request.java @@ -184,5 +184,5 @@ public interface Request { */ String getBodyEncoding(); - ConnectionPoolKeyStrategy getConnectionPoolKeyStrategy(); + ConnectionPoolPartitioning getConnectionPoolPartitioning(); } diff --git a/src/main/java/com/ning/http/client/RequestBuilderBase.java b/src/main/java/com/ning/http/client/RequestBuilderBase.java index 6009c03a99..a7eb568108 100644 --- a/src/main/java/com/ning/http/client/RequestBuilderBase.java +++ b/src/main/java/com/ning/http/client/RequestBuilderBase.java @@ -67,7 +67,7 @@ private static final class RequestImpl implements Request { private int requestTimeout; private long rangeOffset; public String charset; - private ConnectionPoolKeyStrategy connectionPoolKeyStrategy = DefaultConnectionPoolStrategy.INSTANCE; + private ConnectionPoolPartitioning connectionPoolPartitioning = PerHostConnectionPoolPartioning.INSTANCE; private List queryParams; public RequestImpl() { @@ -96,7 +96,7 @@ public RequestImpl(Request prototype) { this.requestTimeout = prototype.getRequestTimeout(); this.rangeOffset = prototype.getRangeOffset(); this.charset = prototype.getBodyEncoding(); - this.connectionPoolKeyStrategy = prototype.getConnectionPoolKeyStrategy(); + this.connectionPoolPartitioning = prototype.getConnectionPoolPartitioning(); } } @@ -188,8 +188,8 @@ public String getBodyEncoding() { return charset; } - public ConnectionPoolKeyStrategy getConnectionPoolKeyStrategy() { - return connectionPoolKeyStrategy; + public ConnectionPoolPartitioning getConnectionPoolPartitioning() { + return connectionPoolPartitioning; } @Override @@ -514,8 +514,8 @@ public T setBodyEncoding(String charset) { return derived.cast(this); } - public T setConnectionPoolKeyStrategy(ConnectionPoolKeyStrategy connectionPoolKeyStrategy) { - request.connectionPoolKeyStrategy = connectionPoolKeyStrategy; + public T setConnectionPoolKeyStrategy(ConnectionPoolPartitioning connectionPoolKeyStrategy) { + request.connectionPoolPartitioning = connectionPoolKeyStrategy; return derived.cast(this); } 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 8d89a835c8..8c01041a38 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 @@ -2374,7 +2374,7 @@ void doAsyncTrackedConnection(final Request request, final GrizzlyResponseFuture requestFuture, final CompletionHandler connectHandler) throws IOException, ExecutionException, InterruptedException { - Connection c = pool.poll(getPoolKey(request, requestFuture.getProxy())); + Connection c = pool.poll(getPartitionId(request, requestFuture.getProxy())); if (c == null) { if (!connectionMonitor.acquire()) { throw new IOException("Max connections exceeded"); @@ -2459,7 +2459,7 @@ private Connection obtainConnection0(final Request request, 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, proxyServer), c)); + && pool.offer(getPartitionId(request, proxyServer), c)); if (result) { if (provider.resolver != null) { provider.resolver.setTimeoutMillis(c, IdleTimeoutFilter.FOREVER); @@ -2519,8 +2519,8 @@ public void updated(Connection result) { }; } - private static String getPoolKey(Request request, ProxyServer proxyServer) { - return request.getConnectionPoolKeyStrategy().getKey(request.getUri(), proxyServer); + private static String getPartitionId(Request request, ProxyServer proxyServer) { + return request.getConnectionPoolPartitioning().getPartitionId(request.getUri(), proxyServer); } // ------------------------------------------------------ Nested Classes diff --git a/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java b/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java index 61e390fcf1..c03847cc22 100644 --- a/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java +++ b/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java @@ -39,6 +39,8 @@ import org.slf4j.LoggerFactory; import com.ning.http.client.AsyncHttpClientConfig; +import com.ning.http.client.ConnectionPoolPartitioning; +import com.ning.http.client.ProxyServer; import com.ning.http.client.providers.netty.Callback; import com.ning.http.client.providers.netty.NettyAsyncHttpProviderConfig; import com.ning.http.client.providers.netty.channel.pool.ChannelPool; @@ -50,6 +52,7 @@ import com.ning.http.client.providers.netty.handler.Protocol; import com.ning.http.client.providers.netty.handler.WebSocketProtocol; import com.ning.http.client.providers.netty.request.NettyRequestSender; +import com.ning.http.client.uri.Uri; import com.ning.http.util.SslUtils; import javax.net.ssl.SSLContext; @@ -242,12 +245,12 @@ public ChannelPipeline getPipeline() throws Exception { }); } - public final void tryToOfferChannelToPool(Channel channel, boolean keepAlive, String poolKey) { + public final void tryToOfferChannelToPool(Channel channel, boolean keepAlive, String partition) { if (keepAlive && channel.isReadable()) { - LOGGER.debug("Adding key: {} for channel {}", poolKey, channel); - channelPool.offer(channel, poolKey); + LOGGER.debug("Adding key: {} for channel {}", partition, channel); + channelPool.offer(channel, partition); if (maxConnectionsPerHostEnabled) - channelId2KeyPool.putIfAbsent(channel.getId(), poolKey); + channelId2KeyPool.putIfAbsent(channel.getId(), partition); Channels.setDiscard(channel); } else { // not offered @@ -255,8 +258,9 @@ public final void tryToOfferChannelToPool(Channel channel, boolean keepAlive, St } } - public Channel poll(String uri) { - return channelPool.poll(uri); + public Channel poll(Uri uri, ProxyServer proxy, ConnectionPoolPartitioning connectionPoolPartitioning) { + String partitionId = connectionPoolPartitioning.getPartitionId(uri, proxy); + return channelPool.poll(partitionId); } public boolean removeAll(Channel connection) { @@ -389,8 +393,8 @@ public void upgradeProtocol(ChannelPipeline pipeline, String scheme, String host } } - public String getPoolKey(NettyResponseFuture future) { - return future.getConnectionPoolKeyStrategy().getKey(future.getUri(), future.getProxyServer()); + public String getPartitionId(NettyResponseFuture future) { + return future.getConnectionPoolPartitioning().getPartitionId(future.getUri(), future.getProxyServer()); } public void verifyChannelPipeline(ChannelPipeline pipeline, String scheme) throws IOException, GeneralSecurityException { @@ -429,6 +433,6 @@ public void call() throws Exception { } public void drainChannel(final Channel channel, final NettyResponseFuture future) { - Channels.setAttribute(channel, newDrainCallback(future, channel, future.isKeepAlive(), getPoolKey(future))); + Channels.setAttribute(channel, newDrainCallback(future, channel, future.isKeepAlive(), getPartitionId(future))); } } diff --git a/src/main/java/com/ning/http/client/providers/netty/channel/pool/ChannelPool.java b/src/main/java/com/ning/http/client/providers/netty/channel/pool/ChannelPool.java index c01195bfdb..9acaebb93c 100644 --- a/src/main/java/com/ning/http/client/providers/netty/channel/pool/ChannelPool.java +++ b/src/main/java/com/ning/http/client/providers/netty/channel/pool/ChannelPool.java @@ -23,19 +23,19 @@ public interface ChannelPool { /** * Add a connection to the pool * - * @param poolKey a key used to retrieve the cached connection + * @param partitionId a key used to retrieve the cached connection * @param connection an I/O connection * @return true if added. */ - boolean offer(Channel connection, String poolKey); + boolean offer(Channel connection, String partitionId); /** - * Remove the connection associated with the uri. + * Get a connection from a partition * - * @param uri the uri used when invoking addConnection - * @return the connection associated with the uri + * @param partitionId the id of the partition used when invoking offer + * @return the connection associated with the partitionId */ - Channel poll(String uri); + Channel poll(String partitionId); /** * Remove all connections from the cache. A connection might have been associated with several uri. diff --git a/src/main/java/com/ning/http/client/providers/netty/channel/pool/DefaultChannelPool.java b/src/main/java/com/ning/http/client/providers/netty/channel/pool/DefaultChannelPool.java index 51795583f7..b06ab06ccf 100644 --- a/src/main/java/com/ning/http/client/providers/netty/channel/pool/DefaultChannelPool.java +++ b/src/main/java/com/ning/http/client/providers/netty/channel/pool/DefaultChannelPool.java @@ -42,7 +42,7 @@ public final class DefaultChannelPool implements ChannelPool { private static final Logger LOGGER = LoggerFactory.getLogger(DefaultChannelPool.class); - private final ConcurrentHashMap> poolsPerKey = new ConcurrentHashMap>(); + private final ConcurrentHashMap> partitions = new ConcurrentHashMap>(); private final ConcurrentHashMap channelId2Creation = new ConcurrentHashMap(); private final AtomicBoolean isClosed = new AtomicBoolean(false); private final Timer nettyTimer; @@ -130,10 +130,10 @@ private boolean isIdleTimeoutExpired(IdleChannel idleChannel, long now) { return !maxIdleTimeDisabled && now - idleChannel.start >= maxIdleTime; } - private List expiredChannels(ConcurrentLinkedQueue pool, long now) { + private List expiredChannels(ConcurrentLinkedQueue partition, long now) { // lazy create List idleTimeoutChannels = null; - for (IdleChannel idleChannel : pool) { + for (IdleChannel idleChannel : partition) { if (isTTLExpired(idleChannel.channel, now) || isIdleTimeoutExpired(idleChannel, now) || !Channels.isChannelValid(idleChannel.channel)) { LOGGER.debug("Adding Candidate expired Channel {}", idleChannel.channel); @@ -187,27 +187,27 @@ public void run(Timeout timeout) throws Exception { try { if (LOGGER.isDebugEnabled()) - for (String key : poolsPerKey.keySet()) { - LOGGER.debug("Entry count for : {} : {}", key, poolsPerKey.get(key).size()); + for (String key : partitions.keySet()) { + LOGGER.debug("Entry count for : {} : {}", key, partitions.get(key).size()); } long start = millisTime(); int closedCount = 0; int totalCount = 0; - for (ConcurrentLinkedQueue pool : poolsPerKey.values()) { + for (ConcurrentLinkedQueue partition : partitions.values()) { // store in intermediate unsynchronized lists to minimize the impact on the ConcurrentLinkedQueue if (LOGGER.isDebugEnabled()) - totalCount += pool.size(); + totalCount += partition.size(); - List closedChannels = closeChannels(expiredChannels(pool, start)); + List closedChannels = closeChannels(expiredChannels(partition, start)); if (!closedChannels.isEmpty()) { for (IdleChannel closedChannel : closedChannels) channelId2Creation.remove(closedChannel.channel.getId()); - pool.removeAll(closedChannels); + partition.removeAll(closedChannels); closedCount += closedChannels.size(); } } @@ -224,19 +224,19 @@ public void run(Timeout timeout) throws Exception { } } - private ConcurrentLinkedQueue getPoolForKey(String key) { - ConcurrentLinkedQueue pool = poolsPerKey.get(key); - if (pool == null) { - // lazy init pool - ConcurrentLinkedQueue newPool = new ConcurrentLinkedQueue(); - pool = poolsPerKey.putIfAbsent(key, newPool); - if (pool == null) - pool = newPool; + private ConcurrentLinkedQueue getPartition(String partitionId) { + ConcurrentLinkedQueue partition = partitions.get(partitionId); + if (partition == null) { + // lazy init partition + ConcurrentLinkedQueue newPartition = new ConcurrentLinkedQueue(); + partition = partitions.putIfAbsent(partitionId, newPartition); + if (partition == null) + partition = newPartition; } - return pool; + return partition; } - public boolean offer(Channel channel, String poolKey) { + public boolean offer(Channel channel, String partition) { if (isClosed.get() || (!sslConnectionPoolEnabled && channel.getPipeline().get(SslHandler.class) != null)) return false; @@ -245,22 +245,20 @@ public boolean offer(Channel channel, String poolKey) { if (isTTLExpired(channel, now)) return false; - boolean added = getPoolForKey(poolKey).add(new IdleChannel(channel, now)); + boolean added = getPartition(partition).add(new IdleChannel(channel, now)); if (added) - channelId2Creation.putIfAbsent(channel.getId(), new ChannelCreation(now, poolKey)); + channelId2Creation.putIfAbsent(channel.getId(), new ChannelCreation(now, partition)); return added; } - public Channel poll(String poolKey) { - if (!sslConnectionPoolEnabled && poolKey.startsWith("https")) - return null; + public Channel poll(String partitionId) { IdleChannel idleChannel = null; - ConcurrentLinkedQueue pooledConnectionForKey = poolsPerKey.get(poolKey); - if (pooledConnectionForKey != null) { + ConcurrentLinkedQueue partition = partitions.get(partitionId); + if (partition != null) { while (idleChannel == null) { - idleChannel = pooledConnectionForKey.poll(); + idleChannel = partition.poll(); if (idleChannel == null) // pool is empty @@ -277,7 +275,7 @@ else if (!Channels.isChannelValid(idleChannel.channel)) { @Override public boolean removeAll(Channel channel) { ChannelCreation creation = channelId2Creation.remove(channel.getId()); - return !isClosed.get() && creation != null && poolsPerKey.get(creation.poolKey).remove(channel); + return !isClosed.get() && creation != null && partitions.get(creation.poolKey).remove(channel); } @Override @@ -290,12 +288,12 @@ public void destroy() { if (isClosed.getAndSet(true)) return; - for (ConcurrentLinkedQueue pool : poolsPerKey.values()) { - for (IdleChannel idleChannel : pool) + for (ConcurrentLinkedQueue partition : partitions.values()) { + for (IdleChannel idleChannel : partition) close(idleChannel.channel); } - poolsPerKey.clear(); + partitions.clear(); channelId2Creation.clear(); } diff --git a/src/main/java/com/ning/http/client/providers/netty/future/NettyResponseFuture.java b/src/main/java/com/ning/http/client/providers/netty/future/NettyResponseFuture.java index 6522eb67c1..0114a67742 100755 --- a/src/main/java/com/ning/http/client/providers/netty/future/NettyResponseFuture.java +++ b/src/main/java/com/ning/http/client/providers/netty/future/NettyResponseFuture.java @@ -21,7 +21,7 @@ import org.slf4j.LoggerFactory; import com.ning.http.client.AsyncHandler; -import com.ning.http.client.ConnectionPoolKeyStrategy; +import com.ning.http.client.ConnectionPoolPartitioning; import com.ning.http.client.ProxyServer; import com.ning.http.client.Request; import com.ning.http.client.listenable.AbstractListenableFuture; @@ -58,7 +58,7 @@ public enum STATE { private volatile boolean requestTimeoutReached; private volatile boolean idleConnectionTimeoutReached; private final long start = millisTime(); - private final ConnectionPoolKeyStrategy connectionPoolKeyStrategy; + private final ConnectionPoolPartitioning connectionPoolPartitioning; private final ProxyServer proxyServer; private final int maxRetry; private final CountDownLatch latch = new CountDownLatch(1); @@ -98,14 +98,14 @@ public NettyResponseFuture(Uri uri,// AsyncHandler asyncHandler,// NettyRequest nettyRequest,// int maxRetry,// - ConnectionPoolKeyStrategy connectionPoolKeyStrategy,// + ConnectionPoolPartitioning connectionPoolPartitioning,// ProxyServer proxyServer) { this.asyncHandler = asyncHandler; this.request = request; this.nettyRequest = nettyRequest; this.uri = uri; - this.connectionPoolKeyStrategy = connectionPoolKeyStrategy; + this.connectionPoolPartitioning = connectionPoolPartitioning; this.proxyServer = proxyServer; this.maxRetry = maxRetry; } @@ -253,8 +253,8 @@ public void setUri(Uri uri) { this.uri = uri; } - public ConnectionPoolKeyStrategy getConnectionPoolKeyStrategy() { - return connectionPoolKeyStrategy; + public ConnectionPoolPartitioning getConnectionPoolPartitioning() { + return connectionPoolPartitioning; } public ProxyServer getProxyServer() { diff --git a/src/main/java/com/ning/http/client/providers/netty/handler/HttpProtocol.java b/src/main/java/com/ning/http/client/providers/netty/handler/HttpProtocol.java index 6ccc73e394..d622e7f290 100644 --- a/src/main/java/com/ning/http/client/providers/netty/handler/HttpProtocol.java +++ b/src/main/java/com/ning/http/client/providers/netty/handler/HttpProtocol.java @@ -172,7 +172,7 @@ private void finishUpdate(final NettyResponseFuture future, Channel channel, if (expectOtherChunks && keepAlive) channelManager.drainChannel(channel, future); else - channelManager.tryToOfferChannelToPool(channel, keepAlive, channelManager.getPoolKey(future)); + channelManager.tryToOfferChannelToPool(channel, keepAlive, channelManager.getPartitionId(future)); markAsDone(future, channel); } diff --git a/src/main/java/com/ning/http/client/providers/netty/handler/Protocol.java b/src/main/java/com/ning/http/client/providers/netty/handler/Protocol.java index c3ac3d3074..821125e37d 100644 --- a/src/main/java/com/ning/http/client/providers/netty/handler/Protocol.java +++ b/src/main/java/com/ning/http/client/providers/netty/handler/Protocol.java @@ -123,7 +123,7 @@ protected boolean exitAfterHandlingRedirect(// // in case of a redirect from HTTP to HTTPS, future attributes might change final boolean initialConnectionKeepAlive = future.isKeepAlive(); - final String initialPoolKey = channelManager.getPoolKey(future); + final String initialPoolKey = channelManager.getPartitionId(future); future.setUri(uri); String newUrl = uri.toUrl(); diff --git a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java index a65aa1ba17..b4afd9718f 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java @@ -35,7 +35,7 @@ import com.ning.http.client.AsyncHandler; import com.ning.http.client.AsyncHandlerExtensions; import com.ning.http.client.AsyncHttpClientConfig; -import com.ning.http.client.ConnectionPoolKeyStrategy; +import com.ning.http.client.ConnectionPoolPartitioning; import com.ning.http.client.FluentCaseInsensitiveStringsMap; import com.ning.http.client.ListenableFuture; import com.ning.http.client.ProxyServer; @@ -129,7 +129,7 @@ private ListenableFuture sendRequestWithCertainForceConnect(// boolean forceConnect) throws IOException { NettyResponseFuture newFuture = newNettyRequestAndResponseFuture(request, asyncHandler, future, uri, proxyServer, forceConnect); - Channel channel = getCachedChannel(future, uri, request.getConnectionPoolKeyStrategy(), proxyServer, asyncHandler); + Channel channel = getCachedChannel(future, uri, request.getConnectionPoolPartitioning(), proxyServer, asyncHandler); if (Channels.isChannelValid(channel)) return sendRequestWithCachedChannel(request, uri, proxyServer, newFuture, asyncHandler, channel); @@ -153,7 +153,7 @@ private ListenableFuture sendRequestThroughSslProxy(// NettyResponseFuture newFuture = null; for (int i = 0; i < 3; i++) { - Channel channel = getCachedChannel(future, uri, request.getConnectionPoolKeyStrategy(), proxyServer, asyncHandler); + Channel channel = getCachedChannel(future, uri, request.getConnectionPoolPartitioning(), proxyServer, asyncHandler); if (Channels.isChannelValid(channel)) if (newFuture == null) newFuture = newNettyRequestAndResponseFuture(request, asyncHandler, future, uri, proxyServer, false); @@ -184,7 +184,7 @@ private NettyResponseFuture newNettyRequestAndResponseFuture(final Reques } } - private Channel getCachedChannel(NettyResponseFuture future, Uri uri, ConnectionPoolKeyStrategy poolKeyGen, + private Channel getCachedChannel(NettyResponseFuture future, Uri uri, ConnectionPoolPartitioning poolKeyGen, ProxyServer proxyServer, AsyncHandler asyncHandler) { if (future != null && future.reuseChannel() && Channels.isChannelValid(future.channel())) @@ -251,7 +251,7 @@ private ListenableFuture sendRequestWithNewChannel(// // only compute when maxConnectionPerHost is enabled // FIXME clean up if (config.getMaxConnectionsPerHost() > 0) - poolKey = channelManager.getPoolKey(future); + poolKey = channelManager.getPartitionId(future); channelPreempted = preemptChannel(asyncHandler, poolKey); } @@ -282,7 +282,7 @@ private NettyResponseFuture newNettyResponseFuture(Uri uri, Request reque asyncHandler,// nettyRequest,// config.getMaxRequestRetry(),// - request.getConnectionPoolKeyStrategy(),// + request.getConnectionPoolPartitioning(),// proxyServer); String expectHeader = request.getHeaders().getFirstValue(HttpHeaders.Names.EXPECT); @@ -462,12 +462,12 @@ private boolean validateWebSocketRequest(Request request, AsyncHandler asyncH return request.getMethod().equals(HttpMethod.GET.getName()) && asyncHandler instanceof WebSocketUpgradeHandler; } - public Channel pollAndVerifyCachedChannel(Uri uri, ProxyServer proxy, ConnectionPoolKeyStrategy connectionPoolKeyStrategy, AsyncHandler asyncHandler) { + public Channel pollAndVerifyCachedChannel(Uri uri, ProxyServer proxy, ConnectionPoolPartitioning connectionPoolPartitioning, AsyncHandler asyncHandler) { if (asyncHandler instanceof AsyncHandlerExtensions) AsyncHandlerExtensions.class.cast(asyncHandler).onPoolConnection(); - final Channel channel = channelManager.poll(connectionPoolKeyStrategy.getKey(uri, proxy)); + final Channel channel = channelManager.poll(uri, proxy, connectionPoolPartitioning); if (channel != null) { LOGGER.debug("Using cached Channel {}\n for uri {}\n", channel, uri); From 8b6f5db0bc0d2b1289d92791309b856540e3e876 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 4 Sep 2014 12:30:21 +0200 Subject: [PATCH 573/701] Introduce a way to flush a ChannelPool partition, close #679 --- .../netty/NettyAsyncHttpProvider.java | 9 +++++ .../netty/channel/ChannelManager.java | 9 +++++ .../netty/channel/pool/ChannelPool.java | 14 ++++++++ .../pool/ChannelPoolPartitionSelector.java | 19 ++++++++++ .../channel/pool/DefaultChannelPool.java | 24 +++++++++++++ .../netty/channel/pool/NoopChannelPool.java | 13 +++++++ .../async/netty/NettyConnectionPoolTest.java | 36 ++++--------------- 7 files changed, 94 insertions(+), 30 deletions(-) create mode 100644 src/main/java/com/ning/http/client/providers/netty/channel/pool/ChannelPoolPartitionSelector.java 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 e32f6e870e..1f95be7f7c 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 @@ -25,6 +25,7 @@ import com.ning.http.client.ListenableFuture; import com.ning.http.client.Request; import com.ning.http.client.providers.netty.channel.ChannelManager; +import com.ning.http.client.providers.netty.channel.pool.ChannelPoolPartitionSelector; import com.ning.http.client.providers.netty.request.NettyRequestSender; import java.io.IOException; @@ -85,4 +86,12 @@ public void close() { public ListenableFuture execute(Request request, final AsyncHandler asyncHandler) throws IOException { return requestSender.sendRequest(request, asyncHandler, null, false); } + + public void flushChannelPoolPartition(String partitionId) { + channelManager.flushPartition(partitionId); + } + + public void flushChannelPoolPartitions(ChannelPoolPartitionSelector selector) { + channelManager.flushPartitions(selector); + } } diff --git a/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java b/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java index c03847cc22..92b33d4c9e 100644 --- a/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java +++ b/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java @@ -44,6 +44,7 @@ import com.ning.http.client.providers.netty.Callback; import com.ning.http.client.providers.netty.NettyAsyncHttpProviderConfig; import com.ning.http.client.providers.netty.channel.pool.ChannelPool; +import com.ning.http.client.providers.netty.channel.pool.ChannelPoolPartitionSelector; import com.ning.http.client.providers.netty.channel.pool.DefaultChannelPool; import com.ning.http.client.providers.netty.channel.pool.NoopChannelPool; import com.ning.http.client.providers.netty.future.NettyResponseFuture; @@ -435,4 +436,12 @@ public void call() throws Exception { public void drainChannel(final Channel channel, final NettyResponseFuture future) { Channels.setAttribute(channel, newDrainCallback(future, channel, future.isKeepAlive(), getPartitionId(future))); } + + public void flushPartition(String partitionId) { + channelPool.flushPartition(partitionId); + } + + public void flushPartitions(ChannelPoolPartitionSelector selector) { + channelPool.flushPartitions(selector); + } } diff --git a/src/main/java/com/ning/http/client/providers/netty/channel/pool/ChannelPool.java b/src/main/java/com/ning/http/client/providers/netty/channel/pool/ChannelPool.java index 9acaebb93c..9e241ab5f9 100644 --- a/src/main/java/com/ning/http/client/providers/netty/channel/pool/ChannelPool.java +++ b/src/main/java/com/ning/http/client/providers/netty/channel/pool/ChannelPool.java @@ -57,4 +57,18 @@ public interface ChannelPool { * Destroy all connections that has been cached by this instance. */ void destroy(); + + /** + * Flush a partition + * + * @param partitionId + */ + void flushPartition(String partitionId); + + /** + * Flush partitions based on a selector + * + * @param selector + */ + void flushPartitions(ChannelPoolPartitionSelector selector); } diff --git a/src/main/java/com/ning/http/client/providers/netty/channel/pool/ChannelPoolPartitionSelector.java b/src/main/java/com/ning/http/client/providers/netty/channel/pool/ChannelPoolPartitionSelector.java new file mode 100644 index 0000000000..615f8ce01c --- /dev/null +++ b/src/main/java/com/ning/http/client/providers/netty/channel/pool/ChannelPoolPartitionSelector.java @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2014 AsyncHttpClient Project. 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.providers.netty.channel.pool; + +public interface ChannelPoolPartitionSelector { + + boolean select(String partitionId); +} diff --git a/src/main/java/com/ning/http/client/providers/netty/channel/pool/DefaultChannelPool.java b/src/main/java/com/ning/http/client/providers/netty/channel/pool/DefaultChannelPool.java index b06ab06ccf..a0aa742c3a 100644 --- a/src/main/java/com/ning/http/client/providers/netty/channel/pool/DefaultChannelPool.java +++ b/src/main/java/com/ning/http/client/providers/netty/channel/pool/DefaultChannelPool.java @@ -30,6 +30,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.TimeUnit; @@ -303,4 +304,27 @@ private void close(Channel channel) { channelId2Creation.remove(channel.getId()); Channels.silentlyCloseChannel(channel); } + + private void flushPartition(String partitionId, ConcurrentLinkedQueue partition) { + if (partition != null) { + partitions.remove(partitionId); + for (IdleChannel idleChannel : partition) + close(idleChannel.channel); + } + } + + @Override + public void flushPartition(String partitionId) { + flushPartition(partitionId, partitions.get(partitionId)); + } + + @Override + public void flushPartitions(ChannelPoolPartitionSelector selector) { + + for (Map.Entry> partitionsEntry : partitions.entrySet()) { + String partitionId = partitionsEntry.getKey(); + if (selector.select(partitionId)) + flushPartition(partitionId, partitionsEntry.getValue()); + } + } } diff --git a/src/main/java/com/ning/http/client/providers/netty/channel/pool/NoopChannelPool.java b/src/main/java/com/ning/http/client/providers/netty/channel/pool/NoopChannelPool.java index 6449e0c105..9286439fad 100644 --- a/src/main/java/com/ning/http/client/providers/netty/channel/pool/NoopChannelPool.java +++ b/src/main/java/com/ning/http/client/providers/netty/channel/pool/NoopChannelPool.java @@ -17,22 +17,35 @@ public class NoopChannelPool implements ChannelPool { + @Override public boolean offer(Channel connection, String poolKey) { return false; } + @Override public Channel poll(String uri) { return null; } + @Override public boolean removeAll(Channel connection) { return false; } + @Override public boolean isOpen() { return true; } + @Override public void destroy() { } + + @Override + public void flushPartition(String partitionId) { + } + + @Override + public void flushPartitions(ChannelPoolPartitionSelector selector) { + } } diff --git a/src/test/java/com/ning/http/client/async/netty/NettyConnectionPoolTest.java b/src/test/java/com/ning/http/client/async/netty/NettyConnectionPoolTest.java index e5bf904f59..a470cbf2bd 100644 --- a/src/test/java/com/ning/http/client/async/netty/NettyConnectionPoolTest.java +++ b/src/test/java/com/ning/http/client/async/netty/NettyConnectionPoolTest.java @@ -28,6 +28,7 @@ import com.ning.http.client.async.ProviderUtil; import com.ning.http.client.providers.netty.NettyAsyncHttpProviderConfig; import com.ning.http.client.providers.netty.channel.pool.ChannelPool; +import com.ning.http.client.providers.netty.channel.pool.NoopChannelPool; import java.net.ConnectException; import java.util.concurrent.TimeUnit; @@ -42,27 +43,17 @@ public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { @Test(groups = { "standalone", "default_provider" }) public void testInvalidConnectionsPool() { - ChannelPool cp = new ChannelPool() { + ChannelPool cp = new NoopChannelPool() { + @Override public boolean offer(Channel connection, String poolKey) { return false; } - public Channel poll(String connection) { - return null; - } - - public boolean removeAll(Channel connection) { - return false; - } - + @Override public boolean isOpen() { return false; } - - public void destroy() { - - } }; NettyAsyncHttpProviderConfig providerConfig = new NettyAsyncHttpProviderConfig(); @@ -86,27 +77,12 @@ public void destroy() { @Test(groups = { "standalone", "default_provider" }) public void testValidConnectionsPool() { - ChannelPool cp = new ChannelPool() { + ChannelPool cp = new NoopChannelPool() { + @Override public boolean offer(Channel connection, String poolKey) { return true; } - - public Channel poll(String connection) { - return null; - } - - public boolean removeAll(Channel connection) { - return false; - } - - public boolean isOpen() { - return true; - } - - public void destroy() { - - } }; NettyAsyncHttpProviderConfig providerConfig = new NettyAsyncHttpProviderConfig(); From 35cdab3e20ebfbba5d6b4b626cabffe4ddd5774e Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 4 Sep 2014 12:42:26 +0200 Subject: [PATCH 574/701] Rename sendTextMessage into sendMessage and streamText into stream, close #671 --- .../grizzly/GrizzlyAsyncHttpProvider.java | 4 ++-- .../client/providers/netty/ws/NettyWebSocket.java | 4 ++-- .../com/ning/http/client/websocket/WebSocket.java | 4 ++-- .../http/client/websocket/ProxyTunnellingTest.java | 2 +- .../http/client/websocket/TextMessageTest.java | 14 +++++++------- 5 files changed, 14 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 8c01041a38..364fee7ab7 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 @@ -2705,13 +2705,13 @@ public WebSocket stream(byte[] fragment, int offset, int len, boolean last) { } @Override - public WebSocket sendTextMessage(String message) { + public WebSocket sendMessage(String message) { gWebSocket.send(message); return this; } @Override - public WebSocket streamText(String fragment, boolean last) { + public WebSocket stream(String fragment, boolean last) { gWebSocket.stream(last, fragment); return this; } diff --git a/src/main/java/com/ning/http/client/providers/netty/ws/NettyWebSocket.java b/src/main/java/com/ning/http/client/providers/netty/ws/NettyWebSocket.java index bda897561b..ed5c970843 100644 --- a/src/main/java/com/ning/http/client/providers/netty/ws/NettyWebSocket.java +++ b/src/main/java/com/ning/http/client/providers/netty/ws/NettyWebSocket.java @@ -91,13 +91,13 @@ public WebSocket stream(byte[] fragment, int offset, int len, boolean last) { } @Override - public WebSocket sendTextMessage(String message) { + public WebSocket sendMessage(String message) { channel.write(new TextWebSocketFrame(message)); return this; } @Override - public WebSocket streamText(String fragment, boolean last) { + public WebSocket stream(String fragment, boolean last) { TextWebSocketFrame frame = new TextWebSocketFrame(fragment); frame.setFinalFragment(last); channel.write(frame); 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 ef045289d8..c9c8390fab 100644 --- a/src/main/java/com/ning/http/client/websocket/WebSocket.java +++ b/src/main/java/com/ning/http/client/websocket/WebSocket.java @@ -52,7 +52,7 @@ public interface WebSocket extends Closeable { * @param message a text message * @return this. */ - WebSocket sendTextMessage(String message); + WebSocket sendMessage(String message); /** * Allows streaming of multiple text fragments. @@ -61,7 +61,7 @@ public interface WebSocket extends Closeable { * @param last flag indicating whether or not this is the last fragment. * @return this. */ - WebSocket streamText(String fragment, boolean last); + WebSocket stream(String fragment, boolean last); /** * Send a ping with an optional payload diff --git a/src/test/java/com/ning/http/client/websocket/ProxyTunnellingTest.java b/src/test/java/com/ning/http/client/websocket/ProxyTunnellingTest.java index 032e086851..6b69fe1acd 100644 --- a/src/test/java/com/ning/http/client/websocket/ProxyTunnellingTest.java +++ b/src/test/java/com/ning/http/client/websocket/ProxyTunnellingTest.java @@ -149,7 +149,7 @@ public void onError(Throwable t) { } }).build()).get(); - websocket.sendTextMessage("ECHO"); + websocket.sendMessage("ECHO"); latch.await(); assertEquals(text.get(), "ECHO"); 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 c031567b4a..c69731f246 100644 --- a/src/test/java/com/ning/http/client/websocket/TextMessageTest.java +++ b/src/test/java/com/ning/http/client/websocket/TextMessageTest.java @@ -232,7 +232,7 @@ public void onError(Throwable t) { } }).build()).get(); - websocket.sendTextMessage("ECHO"); + websocket.sendMessage("ECHO"); latch.await(); assertEquals(text.get(), "ECHO"); @@ -294,7 +294,7 @@ public void onError(Throwable t) { } }).build()).get(); - websocket.sendTextMessage("ECHO"); + websocket.sendMessage("ECHO"); latch.await(); assertEquals(text.get(), "ECHOECHO"); @@ -320,7 +320,7 @@ public void onMessage(String message) { @Override public void onOpen(com.ning.http.client.websocket.WebSocket websocket) { - websocket.sendTextMessage("ECHO").sendTextMessage("ECHO"); + websocket.sendMessage("ECHO").sendMessage("ECHO"); } @Override @@ -372,8 +372,8 @@ public void onError(Throwable t) { } }).build()).get(); - websocket.streamText("ECHO", false); - websocket.streamText("ECHO", true); + websocket.stream("ECHO", false); + websocket.stream("ECHO", true); latch.await(); assertEquals(text.get(), "ECHOECHO"); @@ -414,10 +414,10 @@ public void onError(Throwable t) { } }).build()).get(); - websocket.sendTextMessage("ECHO"); + websocket.sendMessage("ECHO"); textLatch.await(); - websocket.sendTextMessage("CLOSE"); + websocket.sendMessage("CLOSE"); closeLatch.await(); assertEquals(text.get(), "ECHO"); From ce9802d055ca3cdb2f7be72dba17e56251e68b62 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 4 Sep 2014 13:02:55 +0200 Subject: [PATCH 575/701] [maven-release-plugin] prepare release async-http-client-1.9.0-BETA11 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 8a64df6dc6..24fde2eeb6 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.9.0-SNAPSHOT + 1.9.0-BETA11 jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From 65dfb0fd3e4af3ac926592d7a981cbe46d073f3a Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 4 Sep 2014 13:02:59 +0200 Subject: [PATCH 576/701] [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 24fde2eeb6..8a64df6dc6 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.9.0-BETA11 + 1.9.0-SNAPSHOT jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From b36d8e2320ed2694a7b6edc8e43cda08963d2af8 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 4 Sep 2014 14:38:20 +0200 Subject: [PATCH 577/701] setCompressionEnabled => setCompressionEnforced --- src/main/java/com/ning/http/client/AsyncHttpClientConfig.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java b/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java index f20657a535..b86848b0ac 100644 --- a/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java @@ -600,7 +600,7 @@ public Builder setMaxRedirects(int maxRedirects) { * @param compressionEnforced true if compression is enforced * @return a {@link Builder} */ - public Builder setCompressionEnabled(boolean compressionEnforced) { + public Builder setCompressionEnforced(boolean compressionEnforced) { this.compressionEnforced = compressionEnforced; return this; } From eefe2cf873ffea60d5c52ed8a7029a6d533faab2 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 4 Sep 2014 14:58:57 +0200 Subject: [PATCH 578/701] typo --- ...olPartioning.java => PerHostConnectionPoolPartitioning.java} | 2 +- src/main/java/com/ning/http/client/RequestBuilderBase.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename src/main/java/com/ning/http/client/{PerHostConnectionPoolPartioning.java => PerHostConnectionPoolPartitioning.java} (91%) diff --git a/src/main/java/com/ning/http/client/PerHostConnectionPoolPartioning.java b/src/main/java/com/ning/http/client/PerHostConnectionPoolPartitioning.java similarity index 91% rename from src/main/java/com/ning/http/client/PerHostConnectionPoolPartioning.java rename to src/main/java/com/ning/http/client/PerHostConnectionPoolPartitioning.java index 16e355603a..911e66a769 100644 --- a/src/main/java/com/ning/http/client/PerHostConnectionPoolPartioning.java +++ b/src/main/java/com/ning/http/client/PerHostConnectionPoolPartitioning.java @@ -18,7 +18,7 @@ import com.ning.http.client.uri.Uri; import com.ning.http.util.AsyncHttpProviderUtils; -public enum PerHostConnectionPoolPartioning implements ConnectionPoolPartitioning { +public enum PerHostConnectionPoolPartitioning implements ConnectionPoolPartitioning { INSTANCE; diff --git a/src/main/java/com/ning/http/client/RequestBuilderBase.java b/src/main/java/com/ning/http/client/RequestBuilderBase.java index a7eb568108..3ee680301f 100644 --- a/src/main/java/com/ning/http/client/RequestBuilderBase.java +++ b/src/main/java/com/ning/http/client/RequestBuilderBase.java @@ -67,7 +67,7 @@ private static final class RequestImpl implements Request { private int requestTimeout; private long rangeOffset; public String charset; - private ConnectionPoolPartitioning connectionPoolPartitioning = PerHostConnectionPoolPartioning.INSTANCE; + private ConnectionPoolPartitioning connectionPoolPartitioning = PerHostConnectionPoolPartitioning.INSTANCE; private List queryParams; public RequestImpl() { From 7f62351d0392aa63e399379ff2780f62a5f49bc0 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 4 Sep 2014 16:08:51 +0200 Subject: [PATCH 579/701] Fix build --- src/main/java/com/ning/http/client/SimpleAsyncHttpClient.java | 4 ++-- .../com/ning/http/client/async/AsyncProvidersBasicTest.java | 2 +- .../java/com/ning/http/client/async/NoNullResponseTest.java | 2 +- .../client/async/grizzly/GrizzlyNoTransferEncodingTest.java | 1 - .../client/async/netty/NettyRequestThrottleTimeoutTest.java | 2 +- 5 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/ning/http/client/SimpleAsyncHttpClient.java b/src/main/java/com/ning/http/client/SimpleAsyncHttpClient.java index 4af6283a62..c6062df7ed 100644 --- a/src/main/java/com/ning/http/client/SimpleAsyncHttpClient.java +++ b/src/main/java/com/ning/http/client/SimpleAsyncHttpClient.java @@ -518,8 +518,8 @@ public Builder setMaximumNumberOfRedirects(int maxDefaultRedirects) { return this; } - public Builder setCompressionEnabled(boolean compressionEnabled) { - configBuilder.setCompressionEnabled(compressionEnabled); + public Builder setCompressionEnforced(boolean compressionEnabled) { + configBuilder.setCompressionEnforced(compressionEnabled); return this; } 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 87d0a5b6a8..638ca6444c 100755 --- a/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java +++ b/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java @@ -707,7 +707,7 @@ public Response onCompleted(Response response) throws Exception { @Test(groups = { "standalone", "default_provider", "async" }) public void asyncDoPostBasicGZIPTest() throws Throwable { - AsyncHttpClientConfig cf = new AsyncHttpClientConfig.Builder().setCompressionEnabled(true).build(); + AsyncHttpClientConfig cf = new AsyncHttpClientConfig.Builder().build(); AsyncHttpClient client = getAsyncHttpClient(cf); try { final CountDownLatch l = new CountDownLatch(1); 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 f4ddd828b0..cb224c0b44 100644 --- a/src/test/java/com/ning/http/client/async/NoNullResponseTest.java +++ b/src/test/java/com/ning/http/client/async/NoNullResponseTest.java @@ -54,7 +54,7 @@ public void multipleSslRequestsWithDelayAndKeepAlive() throws Throwable { } private AsyncHttpClient create() throws GeneralSecurityException { - final AsyncHttpClientConfig.Builder configBuilder = new AsyncHttpClientConfig.Builder().setCompressionEnabled(true).setFollowRedirect(true).setSSLContext(getSSLContext()).setAllowPoolingConnections(true).setConnectionTimeout(10000) + final AsyncHttpClientConfig.Builder configBuilder = new AsyncHttpClientConfig.Builder().setFollowRedirect(true).setSSLContext(getSSLContext()).setAllowPoolingConnections(true).setConnectionTimeout(10000) .setPooledConnectionIdleTimeout(60000).setRequestTimeout(10000).setMaxConnectionsPerHost(-1).setMaxConnections(-1); return getAsyncHttpClient(configBuilder.build()); } diff --git a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyNoTransferEncodingTest.java b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyNoTransferEncodingTest.java index eb46291796..70f8213673 100644 --- a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyNoTransferEncodingTest.java +++ b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyNoTransferEncodingTest.java @@ -85,7 +85,6 @@ public void testNoTransferEncoding() throws Exception { String url = "http://localhost:" + port + "/test"; AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder() - .setCompressionEnabled(true) .setFollowRedirect(false) .setConnectionTimeout(15000) .setRequestTimeout(15000) 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 index 515ffb1e6a..c63ebbdd35 100644 --- a/src/test/java/com/ning/http/client/async/netty/NettyRequestThrottleTimeoutTest.java +++ b/src/test/java/com/ning/http/client/async/netty/NettyRequestThrottleTimeoutTest.java @@ -73,7 +73,7 @@ public void run() { public void testRequestTimeout() throws IOException { final Semaphore requestThrottle = new Semaphore(1); - final AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setCompressionEnabled(true) + final AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder() .setAllowPoolingConnections(true).setMaxConnections(1).build()); try { From 6cbbb173ec5191ee7fd8b03fdf67ff9385d81d15 Mon Sep 17 00:00:00 2001 From: jfarcand Date: Mon, 8 Sep 2014 10:01:41 -0400 Subject: [PATCH 580/701] Add a default constructor to simplify migration --- .../ning/http/client/websocket/WebSocketUpgradeHandler.java | 5 +++++ 1 file changed, 5 insertions(+) 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 fbd18baec7..2954dc9f76 100644 --- a/src/main/java/com/ning/http/client/websocket/WebSocketUpgradeHandler.java +++ b/src/main/java/com/ning/http/client/websocket/WebSocketUpgradeHandler.java @@ -19,6 +19,7 @@ import com.ning.http.client.UpgradeHandler; import java.util.ArrayList; +import java.util.LinkedList; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; @@ -33,6 +34,10 @@ public class WebSocketUpgradeHandler implements UpgradeHandler, Async private boolean onSuccessCalled; private int status; + protected WebSocketUpgradeHandler() { + this.listeners = new LinkedList<>(); + } + protected WebSocketUpgradeHandler(List listeners) { this.listeners = listeners; } From 42c61710d2aa24063d23ca2ae5dcf75d247fe1d5 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 8 Sep 2014 23:31:30 +0200 Subject: [PATCH 581/701] setQueryParams should also drop the query, close #696 --- .../com/ning/http/client/RequestBuilderBase.java | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/ning/http/client/RequestBuilderBase.java b/src/main/java/com/ning/http/client/RequestBuilderBase.java index 3ee680301f..0968c00d25 100644 --- a/src/main/java/com/ning/http/client/RequestBuilderBase.java +++ b/src/main/java/com/ning/http/client/RequestBuilderBase.java @@ -416,16 +416,17 @@ public T setBody(BodyGenerator bodyGenerator) { } public T addQueryParam(String name, String value) { - if (queryParams == null) { + if (queryParams == null) queryParams = new ArrayList(1); - } queryParams.add(new Param(name, value)); return derived.cast(this); } - public T addQueryParams(List queryParams) { - for (Param queryParam: queryParams) - addQueryParam(queryParam.getName(), queryParam.getValue()); + public T addQueryParams(List params) { + if (queryParams == null) + queryParams = params; + else + queryParams.addAll(params); return derived.cast(this); } @@ -447,6 +448,9 @@ public T setQueryParams(Map> map) { } public T setQueryParams(List params) { + // reset existing query + if (isNonEmpty(request.uri.getQuery())) + request.uri = request.uri.withNewQuery(null); queryParams = params; return derived.cast(this); } From 929856004b161fa25a7cda673250d5800fe3d800 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 9 Sep 2014 10:12:37 +0200 Subject: [PATCH 582/701] [maven-release-plugin] prepare release async-http-client-1.9.0-BETA12 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 8a64df6dc6..af6f20821e 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.9.0-SNAPSHOT + 1.9.0-BETA12 jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From 6556e90df72c3cf710fa5decf58b434558e894bb Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 9 Sep 2014 10:12:41 +0200 Subject: [PATCH 583/701] [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 af6f20821e..8a64df6dc6 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.9.0-BETA12 + 1.9.0-SNAPSHOT jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From bf97dd478859772577a1a788d2c3c07f0717940a Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 9 Sep 2014 14:23:58 +0200 Subject: [PATCH 584/701] Fix NPE in TimeoutTimerTask, close #697 --- .../netty/future/NettyResponseFuture.java | 2 +- .../netty/request/NettyRequestSender.java | 27 ++++++++++--------- .../request/timeout/TimeoutTimerTask.java | 4 ++- 3 files changed, 19 insertions(+), 14 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/future/NettyResponseFuture.java b/src/main/java/com/ning/http/client/providers/netty/future/NettyResponseFuture.java index 0114a67742..c227c7ceb8 100755 --- a/src/main/java/com/ning/http/client/providers/netty/future/NettyResponseFuture.java +++ b/src/main/java/com/ning/http/client/providers/netty/future/NettyResponseFuture.java @@ -418,7 +418,7 @@ public boolean canRetry() { } public SocketAddress getChannelRemoteAddress() { - return channel() != null ? channel().getRemoteAddress() : null; + return channel != null ? channel.getRemoteAddress() : null; } public void setRequest(Request request) { diff --git a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java index b4afd9718f..71f158db0e 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java @@ -292,17 +292,18 @@ private NettyResponseFuture newNettyResponseFuture(Uri uri, Request reque } public void writeRequest(NettyResponseFuture future, Channel channel) { + + NettyRequest nettyRequest = future.getNettyRequest(); + HttpRequest httpRequest = nettyRequest.getHttpRequest(); + AsyncHandler handler = future.getAsyncHandler(); + + // if the channel is dead because it was pooled and the remote + // server decided to close it, + // we just let it go and the channelInactive do its work + if (!Channels.isChannelValid(channel)) + return; + 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 channelInactive do its work - if (!Channels.isChannelValid(channel)) - return; - - NettyRequest nettyRequest = future.getNettyRequest(); - HttpRequest httpRequest = nettyRequest.getHttpRequest(); - AsyncHandler handler = future.getAsyncHandler(); - if (handler instanceof TransferCompletionHandler) configureTransferAdapter(handler, httpRequest); @@ -323,11 +324,13 @@ public void writeRequest(NettyResponseFuture future, Channel channel) { && nettyRequest.getBody() != null) nettyRequest.getBody().write(channel, future, config); + // don't bother scheduling timeouts if channel became invalid + if (Channels.isChannelValid(channel)) + scheduleTimeouts(future); + } catch (Throwable ioe) { Channels.silentlyCloseChannel(channel); } - - scheduleTimeouts(future); } private InetSocketAddress remoteAddress(Request request, Uri uri, ProxyServer proxy, boolean useProxy) { diff --git a/src/main/java/com/ning/http/client/providers/netty/request/timeout/TimeoutTimerTask.java b/src/main/java/com/ning/http/client/providers/netty/request/timeout/TimeoutTimerTask.java index 9ecf7476e0..73352f8ee3 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/timeout/TimeoutTimerTask.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/timeout/TimeoutTimerTask.java @@ -19,6 +19,7 @@ import com.ning.http.client.providers.netty.future.NettyResponseFuture; import com.ning.http.client.providers.netty.request.NettyRequestSender; +import java.net.SocketAddress; import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicBoolean; @@ -37,7 +38,8 @@ public TimeoutTimerTask(NettyResponseFuture nettyResponseFuture, NettyRequest this.requestSender = requestSender; this.timeoutsHolder = timeoutsHolder; // saving remote address as the channel might be removed from the future when an exception occurs - remoteAddress = nettyResponseFuture.getChannelRemoteAddress().toString(); + SocketAddress sa = nettyResponseFuture.getChannelRemoteAddress(); + remoteAddress = sa != null ? sa.toString() : "not-connected"; } protected void expire(String message, long time) { From bca5f324592c7e8bfdeee8b8d7463153fb952e7d Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 9 Sep 2014 14:26:36 +0200 Subject: [PATCH 585/701] Damn JDK8! --- src/main/java/com/ning/http/util/ProxyUtils.java | 1 - 1 file changed, 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 ce461a2e91..46e49c1ee2 100644 --- a/src/main/java/com/ning/http/util/ProxyUtils.java +++ b/src/main/java/com/ning/http/util/ProxyUtils.java @@ -143,7 +143,6 @@ public static boolean avoidProxy(final ProxyServer proxyServer, final String hos /** * Creates a proxy server instance from the given properties. - *

      * Currently the default http.* proxy properties are supported as well as properties specific for AHC. * * @param properties the properties to evaluate. Must not be null. From 0751fbdcf1047be8aacb39142426b1edbd53f6f7 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 15 Sep 2014 09:54:45 +0200 Subject: [PATCH 586/701] Fix keep-alive when request says to close, close #698 --- .../http/client/providers/netty/handler/HttpProtocol.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/handler/HttpProtocol.java b/src/main/java/com/ning/http/client/providers/netty/handler/HttpProtocol.java index d622e7f290..e8183aa266 100644 --- a/src/main/java/com/ning/http/client/providers/netty/handler/HttpProtocol.java +++ b/src/main/java/com/ning/http/client/providers/netty/handler/HttpProtocol.java @@ -391,6 +391,10 @@ private boolean exitAfterHandlingBody(Channel channel, NettyResponseFuture fu return false; } + private boolean isConnectionKeepAlive(HttpHeaders headers) { + return !HttpHeaders.Values.CLOSE.equalsIgnoreCase(headers.get(HttpHeaders.Names.CONNECTION)); + } + private boolean handleHttpResponse(final HttpResponse response,// final Channel channel,// final NettyResponseFuture future,// @@ -404,7 +408,7 @@ private boolean handleHttpResponse(final HttpResponse response,// // the handler in case of trailing headers future.setHttpHeaders(response.headers()); - future.setKeepAlive(!HttpHeaders.Values.CLOSE.equalsIgnoreCase(response.headers().get(HttpHeaders.Names.CONNECTION))); + future.setKeepAlive(isConnectionKeepAlive(httpRequest.headers()) && isConnectionKeepAlive(response.headers())); NettyResponseStatus status = new NettyResponseStatus(future.getUri(), config, response); int statusCode = response.getStatus().getCode(); From 6d5e440613a6ca550c3a08bd7d9184acd8729d4d Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 15 Sep 2014 10:05:04 +0200 Subject: [PATCH 587/701] Upgrade Netty 3.9.4 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 8a64df6dc6..f4a8bbce5f 100644 --- a/pom.xml +++ b/pom.xml @@ -565,7 +565,7 @@ http://oss.sonatype.org/content/repositories/snapshots true - 3.9.3.Final + 3.9.4.Final 2.3.16 1.7 1.7 From c8ce69790e90f7c12a6c7dd666a900b88164f173 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 15 Sep 2014 10:24:14 +0200 Subject: [PATCH 588/701] Invalid debug logs when failing to connect, close #699 --- .../client/providers/netty/request/NettyConnectListener.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/request/NettyConnectListener.java b/src/main/java/com/ning/http/client/providers/netty/request/NettyConnectListener.java index 2306148161..1e89892534 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/NettyConnectListener.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/NettyConnectListener.java @@ -127,7 +127,7 @@ public void operationComplete(ChannelFuture handshakeFuture) throws Exception { Throwable cause = f.getCause(); boolean canRetry = future.canRetry(); - LOGGER.debug("Trying to recover a dead cached channel {} with a retry value of {} ", f.getChannel(), canRetry); + LOGGER.debug("Trying to recover from failing to connect channel {} with a retry value of {} ", f.getChannel(), canRetry); if (canRetry && cause != null && (cause instanceof ClosedChannelException || future.getState() != NettyResponseFuture.STATE.NEW || StackTraceInspector.abortOnDisconnectException(cause))) { @@ -136,7 +136,7 @@ public void operationComplete(ChannelFuture handshakeFuture) throws Exception { return; } - LOGGER.debug("Failed to recover from exception: {} with channel {}", cause, f.getChannel()); + LOGGER.debug("Failed to recover from connect exception: {} with channel {}", cause, f.getChannel()); boolean printCause = f.getCause() != null && cause.getMessage() != null; ConnectException e = new ConnectException(printCause ? cause.getMessage() + " to " + future.getUri().toUrl() : future.getUri().toUrl()); From 76f19533b7634b1ba3d21ba5dd613f4554e51bc2 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 15 Sep 2014 10:28:28 +0200 Subject: [PATCH 589/701] Clean up, align on AHC2 --- .../netty/request/NettyConnectListener.java | 113 +++++++++--------- 1 file changed, 59 insertions(+), 54 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/request/NettyConnectListener.java b/src/main/java/com/ning/http/client/providers/netty/request/NettyConnectListener.java index 1e89892534..be1fb37176 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/NettyConnectListener.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/NettyConnectListener.java @@ -87,63 +87,68 @@ private void writeRequest(Channel channel, String poolKey) { requestSender.writeRequest(future, channel); } - public final void operationComplete(ChannelFuture f) throws Exception { - Channel channel = f.getChannel(); - if (f.isSuccess()) { - Channels.setAttribute(channel, future); - final SslHandler sslHandler = ChannelManager.getSslHandler(channel.getPipeline()); - - final HostnameVerifier hostnameVerifier = config.getHostnameVerifier(); - if (hostnameVerifier != null && sslHandler != null) { - final String host = future.getUri().getHost(); - sslHandler.handshake().addListener(new ChannelFutureListener() { - @Override - public void operationComplete(ChannelFuture handshakeFuture) throws Exception { - if (handshakeFuture.isSuccess()) { - Channel channel = (Channel) handshakeFuture.getChannel(); - SSLEngine engine = sslHandler.getEngine(); - SSLSession session = engine.getSession(); - - if (LOGGER.isDebugEnabled()) - LOGGER.debug("onFutureSuccess: session = {}, id = {}, isValid = {}, host = {}", session.toString(), - Base64.encode(session.getId()), session.isValid(), host); - if (hostnameVerifier.verify(host, session)) { - writeRequest(channel, poolKey); - } else { - abortChannelPreemption(poolKey); - ConnectException exception = new ConnectException("HostnameVerifier exception"); - future.abort(exception); - throw exception; - } + private void onFutureSuccess(final Channel channel) throws ConnectException { + Channels.setAttribute(channel, future); + final SslHandler sslHandler = ChannelManager.getSslHandler(channel.getPipeline()); + + final HostnameVerifier hostnameVerifier = config.getHostnameVerifier(); + if (hostnameVerifier != null && sslHandler != null) { + final String host = future.getUri().getHost(); + sslHandler.handshake().addListener(new ChannelFutureListener() { + @Override + public void operationComplete(ChannelFuture handshakeFuture) throws Exception { + if (handshakeFuture.isSuccess()) { + Channel channel = (Channel) handshakeFuture.getChannel(); + SSLEngine engine = sslHandler.getEngine(); + SSLSession session = engine.getSession(); + + if (LOGGER.isDebugEnabled()) + LOGGER.debug("onFutureSuccess: session = {}, id = {}, isValid = {}, host = {}", session.toString(), + Base64.encode(session.getId()), session.isValid(), host); + if (hostnameVerifier.verify(host, session)) { + writeRequest(channel, poolKey); + } else { + abortChannelPreemption(poolKey); + ConnectException exception = new ConnectException("HostnameVerifier exception"); + future.abort(exception); + throw exception; } } - }); - } else { - writeRequest(f.getChannel(), poolKey); - } - + } + }); } else { - abortChannelPreemption(poolKey); - Throwable cause = f.getCause(); - - boolean canRetry = future.canRetry(); - LOGGER.debug("Trying to recover from failing to connect channel {} with a retry value of {} ", f.getChannel(), canRetry); - if (canRetry - && cause != null - && (cause instanceof ClosedChannelException || future.getState() != NettyResponseFuture.STATE.NEW || StackTraceInspector.abortOnDisconnectException(cause))) { - - if (!requestSender.retry(future)) - return; - } - - LOGGER.debug("Failed to recover from connect exception: {} with channel {}", cause, f.getChannel()); - - boolean printCause = f.getCause() != null && cause.getMessage() != null; - ConnectException e = new ConnectException(printCause ? cause.getMessage() + " to " + future.getUri().toUrl() : future.getUri().toUrl()); - if (cause != null) { - e.initCause(cause); - } - future.abort(e); + writeRequest(channel, poolKey); + } + } + + private void onFutureFailure(Channel channel, Throwable cause) { + abortChannelPreemption(poolKey); + + boolean canRetry = future.canRetry(); + LOGGER.debug("Trying to recover from failing to connect channel {} with a retry value of {} ", channel, canRetry); + if (canRetry + && cause != null + && (cause instanceof ClosedChannelException || future.getState() != NettyResponseFuture.STATE.NEW || StackTraceInspector.abortOnDisconnectException(cause))) { + + if (!requestSender.retry(future)) + return; + } + + LOGGER.debug("Failed to recover from connect exception: {} with channel {}", cause, channel); + + boolean printCause = cause != null && cause.getMessage() != null; + ConnectException e = new ConnectException(printCause ? cause.getMessage() + " to " + future.getUri().toUrl() : future.getUri().toUrl()); + if (cause != null) { + e.initCause(cause); } + future.abort(e); + } + + public final void operationComplete(ChannelFuture f) throws Exception { + Channel channel = f.getChannel(); + if (f.isSuccess()) + onFutureSuccess(channel); + else + onFutureFailure(channel, f.getCause()); } } From c23566801070c866ea2a28a96d5ae2da9505eb7a Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 15 Sep 2014 10:43:59 +0200 Subject: [PATCH 590/701] Clean up canRetry --- .../client/providers/netty/future/NettyResponseFuture.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/future/NettyResponseFuture.java b/src/main/java/com/ning/http/client/providers/netty/future/NettyResponseFuture.java index c227c7ceb8..62c034afdb 100755 --- a/src/main/java/com/ning/http/client/providers/netty/future/NettyResponseFuture.java +++ b/src/main/java/com/ning/http/client/providers/netty/future/NettyResponseFuture.java @@ -411,10 +411,7 @@ public boolean reuseChannel() { } public boolean canRetry() { - if (currentRetry.incrementAndGet() > maxRetry) { - return false; - } - return true; + return maxRetry >= 0 && currentRetry.incrementAndGet() <= maxRetry; } public SocketAddress getChannelRemoteAddress() { From 970236ad1790d5edd221d22f3e53dccbfd24d4ac Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 15 Sep 2014 10:50:44 +0200 Subject: [PATCH 591/701] stupid --- .../http/client/providers/netty/future/NettyResponseFuture.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/future/NettyResponseFuture.java b/src/main/java/com/ning/http/client/providers/netty/future/NettyResponseFuture.java index 62c034afdb..e4084e558e 100755 --- a/src/main/java/com/ning/http/client/providers/netty/future/NettyResponseFuture.java +++ b/src/main/java/com/ning/http/client/providers/netty/future/NettyResponseFuture.java @@ -411,7 +411,7 @@ public boolean reuseChannel() { } public boolean canRetry() { - return maxRetry >= 0 && currentRetry.incrementAndGet() <= maxRetry; + return maxRetry > 0 && currentRetry.incrementAndGet() <= maxRetry; } public SocketAddress getChannelRemoteAddress() { From ed7bddc8f38d06b4da30241e81f2c3c218f235fe Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 15 Sep 2014 12:26:54 +0200 Subject: [PATCH 592/701] typos +comments --- .../ning/http/client/providers/netty/handler/Processor.java | 5 +++-- .../client/providers/netty/request/NettyRequestSender.java | 3 ++- .../client/providers/netty/request/ProgressListener.java | 6 +++--- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/handler/Processor.java b/src/main/java/com/ning/http/client/providers/netty/handler/Processor.java index a9367c890e..994e307f02 100644 --- a/src/main/java/com/ning/http/client/providers/netty/handler/Processor.java +++ b/src/main/java/com/ning/http/client/providers/netty/handler/Processor.java @@ -40,8 +40,8 @@ public class Processor extends SimpleChannelUpstreamHandler { private static final Logger LOGGER = LoggerFactory.getLogger(Processor.class); - public static final IOException REMOTELY_CLOSED_EXCEPTION = new IOException("Remotely Closed"); - public static final IOException CHANNEL_CLOSED_EXCEPTION = new IOException("Channel Closed"); + public static final IOException REMOTELY_CLOSED_EXCEPTION = new IOException("Remotely closed"); + public static final IOException CHANNEL_CLOSED_EXCEPTION = new IOException("Channel closed"); static { REMOTELY_CLOSED_EXCEPTION.setStackTrace(new StackTraceElement[0]); CHANNEL_CLOSED_EXCEPTION.setStackTrace(new StackTraceElement[0]); @@ -146,6 +146,7 @@ public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Throwable cause = e.getCause(); NettyResponseFuture future = null; + // FIXME we can't get a PrematureChannelClosureException as we create the HttpClientCodec without setting failOnMissingResponse to true if (cause instanceof PrematureChannelClosureException || cause instanceof ClosedChannelException) return; diff --git a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java index 71f158db0e..0eb378bf6d 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java @@ -320,6 +320,7 @@ public void writeRequest(NettyResponseFuture future, Channel channel) { } } + // FIXME what happens to this second write if the first one failed? Should it be done in the ProgressListener? if (!future.isDontWriteBodyBecauseExpectContinue() && !httpRequest.getMethod().equals(HttpMethod.CONNECT) && nettyRequest.getBody() != null) nettyRequest.getBody().write(channel, future, config); @@ -421,7 +422,7 @@ public boolean retry(NettyResponseFuture future) { } catch (IOException iox) { future.setState(NettyResponseFuture.STATE.CLOSED); future.abort(iox); - LOGGER.error("Remotely Closed, unable to recover", iox); + LOGGER.error("Remotely closed, unable to recover", iox); return false; } diff --git a/src/main/java/com/ning/http/client/providers/netty/request/ProgressListener.java b/src/main/java/com/ning/http/client/providers/netty/request/ProgressListener.java index 555154cd22..6cdec4c060 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/ProgressListener.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/ProgressListener.java @@ -50,6 +50,8 @@ public ProgressListener(AsyncHttpClientConfig config,// private boolean abortOnThrowable(Throwable cause, Channel channel) { if (cause != null && future.getState() != NettyResponseFuture.STATE.NEW) { + // The write operation failed. If the channel was cached, it means it got asynchronously closed. + // Let's retry a second time. if (cause instanceof IllegalStateException) { LOGGER.debug(cause.getMessage(), cause); Channels.silentlyCloseChannel(channel); @@ -67,10 +69,8 @@ private boolean abortOnThrowable(Throwable cause, Channel channel) { } public void operationComplete(ChannelFuture cf) { - // The write operation failed. If the channel was cached, it means it got asynchronously closed. - // Let's retry a second time. - if (!abortOnThrowable(cf.getCause(), cf.getChannel())) { + if (!abortOnThrowable(cf.getCause(), cf.getChannel())) { future.touch(); /** From 44213cf9a5f37f8c862ac39981b180316399764f Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 15 Sep 2014 12:39:42 +0200 Subject: [PATCH 593/701] Don't report the full url in the ConnectException, close #700 --- .../client/providers/netty/request/NettyConnectListener.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/request/NettyConnectListener.java b/src/main/java/com/ning/http/client/providers/netty/request/NettyConnectListener.java index be1fb37176..dd90164d63 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/NettyConnectListener.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/NettyConnectListener.java @@ -13,6 +13,8 @@ */ package com.ning.http.client.providers.netty.request; +import static com.ning.http.util.AsyncHttpProviderUtils.getBaseUrl; + import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelFutureListener; @@ -137,7 +139,8 @@ private void onFutureFailure(Channel channel, Throwable cause) { LOGGER.debug("Failed to recover from connect exception: {} with channel {}", cause, channel); boolean printCause = cause != null && cause.getMessage() != null; - ConnectException e = new ConnectException(printCause ? cause.getMessage() + " to " + future.getUri().toUrl() : future.getUri().toUrl()); + String printedCause = printCause ? cause.getMessage() : getBaseUrl(future.getUri()); + ConnectException e = new ConnectException(printedCause); if (cause != null) { e.initCause(cause); } From 67f1c1004b63fe6dfb2921e9452bc087a1295fef Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 15 Sep 2014 12:42:38 +0200 Subject: [PATCH 594/701] [maven-release-plugin] prepare release async-http-client-1.9.0-BETA13 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index f4a8bbce5f..6966c11640 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.9.0-SNAPSHOT + 1.9.0-BETA13 jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From 48c9fa262653f14ad2ad3e9f99e08c22d6691c5f Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 15 Sep 2014 12:42:49 +0200 Subject: [PATCH 595/701] [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 6966c11640..f4a8bbce5f 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.9.0-BETA13 + 1.9.0-SNAPSHOT jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From 8137e421c6a13ff6f01e1085ac0f0dfe3d34da23 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 16 Sep 2014 08:26:38 +0200 Subject: [PATCH 596/701] Make sure channel is connected when trying to offer --- .../http/client/providers/netty/channel/ChannelManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java b/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java index 92b33d4c9e..88b6b6f694 100644 --- a/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java +++ b/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java @@ -247,7 +247,7 @@ public ChannelPipeline getPipeline() throws Exception { } public final void tryToOfferChannelToPool(Channel channel, boolean keepAlive, String partition) { - if (keepAlive && channel.isReadable()) { + if (channel.isConnected() && keepAlive && channel.isReadable()) { LOGGER.debug("Adding key: {} for channel {}", partition, channel); channelPool.offer(channel, partition); if (maxConnectionsPerHostEnabled) From f7c794117017f19f1e3c56a671a19d9bbf2500d7 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 16 Sep 2014 13:22:31 +0200 Subject: [PATCH 597/701] comments --- .../http/client/providers/netty/handler/HttpProtocol.java | 8 +++++--- .../http/client/providers/netty/handler/Processor.java | 2 ++ .../providers/netty/request/NettyRequestSender.java | 2 ++ 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/handler/HttpProtocol.java b/src/main/java/com/ning/http/client/providers/netty/handler/HttpProtocol.java index e8183aa266..cd53676a99 100644 --- a/src/main/java/com/ning/http/client/providers/netty/handler/HttpProtocol.java +++ b/src/main/java/com/ning/http/client/providers/netty/handler/HttpProtocol.java @@ -462,10 +462,11 @@ public void handle(final Channel channel, final NettyResponseFuture future, f AsyncHandler handler = future.getAsyncHandler(); try { - if (e instanceof HttpResponse && handleHttpResponse((HttpResponse) e, channel, future, handler)) - return; + if (e instanceof HttpResponse) { + if (handleHttpResponse((HttpResponse) e, channel, future, handler)) + return; - if (e instanceof HttpChunk) + } else if (e instanceof HttpChunk) handleChunk((HttpChunk) e, channel, future, handler); } catch (Exception t) { @@ -475,6 +476,7 @@ public void handle(final Channel channel, final NettyResponseFuture future, f return; } + // FIXME Weird: close channel in abort, then close again try { requestSender.abort(channel, future, t); } catch (Exception abortException) { diff --git a/src/main/java/com/ning/http/client/providers/netty/handler/Processor.java b/src/main/java/com/ning/http/client/providers/netty/handler/Processor.java index 994e307f02..980925e8c1 100644 --- a/src/main/java/com/ning/http/client/providers/netty/handler/Processor.java +++ b/src/main/java/com/ning/http/client/providers/netty/handler/Processor.java @@ -82,6 +82,7 @@ public void messageReceived(final ChannelHandlerContext ctx, MessageEvent e) thr if (HttpChunk.class.cast(message).isLast()) // process the AsyncCallable before passing the message to the protocol ac.call(); + // FIXME remove attribute? } else { LOGGER.info("Received unexpected message while expecting a chunk: " + message); ac.call(); @@ -94,6 +95,7 @@ public void messageReceived(final ChannelHandlerContext ctx, MessageEvent e) thr } else if (attribute != DiscardEvent.INSTANCE) { // unhandled message + // FIXME improve log LOGGER.trace("Closing an orphan channel {}", channel); Channels.silentlyCloseChannel(channel); } diff --git a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java index 0eb378bf6d..1867ef6c56 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java @@ -315,6 +315,7 @@ public void writeRequest(NettyResponseFuture future, Channel channel) { } catch (Throwable cause) { // FIXME why not notify? LOGGER.debug(cause.getMessage(), cause); + // FIXME what about the attribute? how could this fail? Channels.silentlyCloseChannel(channel); return; } @@ -390,6 +391,7 @@ public Timeout newTimeout(TimerTask task, long delay) { } public void abort(Channel channel, NettyResponseFuture future, Throwable t) { + if (channel != null) channelManager.closeChannel(channel); From bd6d7862dc520b8014eaf672d5eca37855d61d5c Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 16 Sep 2014 15:05:56 +0200 Subject: [PATCH 598/701] improve log --- .../ning/http/client/providers/netty/handler/Processor.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/handler/Processor.java b/src/main/java/com/ning/http/client/providers/netty/handler/Processor.java index 980925e8c1..ece8b293d9 100644 --- a/src/main/java/com/ning/http/client/providers/netty/handler/Processor.java +++ b/src/main/java/com/ning/http/client/providers/netty/handler/Processor.java @@ -71,9 +71,6 @@ public void messageReceived(final ChannelHandlerContext ctx, MessageEvent e) thr Channel channel = ctx.getChannel(); Object attribute = Channels.getAttribute(channel); - if (attribute == null) - LOGGER.debug("ChannelHandlerContext doesn't have any attribute"); - if (attribute instanceof Callback) { Object message = e.getMessage(); Callback ac = (Callback) attribute; @@ -95,8 +92,7 @@ public void messageReceived(final ChannelHandlerContext ctx, MessageEvent e) thr } else if (attribute != DiscardEvent.INSTANCE) { // unhandled message - // FIXME improve log - LOGGER.trace("Closing an orphan channel {}", channel); + LOGGER.debug("Orphan channel {} with attribute {} received message {}, closing", channel, attribute, e.getMessage()); Channels.silentlyCloseChannel(channel); } } From 601345d1e4473bd34681ab16cf7e090c52cadbcc Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 17 Sep 2014 14:55:10 +0200 Subject: [PATCH 599/701] Drop own StandardCharsets now we target JDK7, close #702 --- .../com/ning/http/client/ProxyServer.java | 4 +- src/main/java/com/ning/http/client/Realm.java | 16 +- .../consumers/AppendableBodyConsumer.java | 5 +- .../client/multipart/AbstractFilePart.java | 2 +- .../http/client/multipart/MultipartUtils.java | 9 +- .../com/ning/http/client/multipart/Part.java | 2 +- .../ning/http/client/multipart/PartBase.java | 2 +- .../http/client/multipart/StringPart.java | 4 +- .../com/ning/http/client/ntlm/NTLMEngine.java | 187 +++++++----------- .../oauth/OAuthSignatureCalculator.java | 4 +- .../http/client/oauth/ThreadSafeHMAC.java | 5 +- .../apache/ApacheAsyncHttpProvider.java | 6 +- .../providers/jdk/MultipartRequestEntity.java | 2 +- .../request/body/FeedableBodyGenerator.java | 9 +- .../providers/netty/ws/NettyWebSocket.java | 2 +- .../PropertiesBasedResumableProcessor.java | 8 +- .../http/util/AsyncHttpProviderUtils.java | 3 +- .../ning/http/util/AuthenticatorUtils.java | 3 +- .../com/ning/http/util/StandardCharsets.java | 28 --- .../java/com/ning/http/client/RealmTest.java | 5 +- .../client/async/AsyncProvidersBasicTest.java | 12 +- .../client/async/AsyncStreamHandlerTest.java | 1 - .../async/FastUnauthorizedUploadTest.java | 7 +- .../client/async/FilePartLargeFileTest.java | 8 +- .../client/async/MultipartUploadTest.java | 2 +- .../async/SimpleAsyncHttpClientTest.java | 2 +- .../client/multipart/MultipartBodyTest.java | 5 +- 27 files changed, 141 insertions(+), 202 deletions(-) delete mode 100644 src/main/java/com/ning/http/util/StandardCharsets.java diff --git a/src/main/java/com/ning/http/client/ProxyServer.java b/src/main/java/com/ning/http/client/ProxyServer.java index 57e006c5ef..79008ade9d 100644 --- a/src/main/java/com/ning/http/client/ProxyServer.java +++ b/src/main/java/com/ning/http/client/ProxyServer.java @@ -16,7 +16,7 @@ */ package com.ning.http.client; -import com.ning.http.util.StandardCharsets; +import static java.nio.charset.StandardCharsets.UTF_8; import java.util.ArrayList; import java.util.Collections; @@ -53,7 +53,7 @@ public String toString() { private final String password; private final int port; private final String url; - private String encoding = StandardCharsets.UTF_8.name(); + private String encoding = UTF_8.name(); private String ntlmDomain = System.getProperty("http.auth.ntlm.domain", ""); public ProxyServer(final Protocol protocol, final String host, final int port, String principal, String password) { diff --git a/src/main/java/com/ning/http/client/Realm.java b/src/main/java/com/ning/http/client/Realm.java index d6c9bd7c8a..7fa03b5ad7 100644 --- a/src/main/java/com/ning/http/client/Realm.java +++ b/src/main/java/com/ning/http/client/Realm.java @@ -16,11 +16,11 @@ */ package com.ning.http.client; +import static java.nio.charset.StandardCharsets.*; + import static com.ning.http.util.MiscUtils.isNonEmpty; import com.ning.http.client.uri.Uri; -import com.ning.http.util.StandardCharsets; - import java.io.UnsupportedEncodingException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; @@ -298,7 +298,7 @@ public static class RealmBuilder { private String methodName = "GET"; private boolean usePreemptive = false; private String ntlmDomain = System.getProperty("http.auth.ntlm.domain", ""); - private String enc = StandardCharsets.UTF_8.name(); + private String enc = UTF_8.name(); private String host = "localhost"; private boolean messageType2Received = false; private boolean useAbsoluteURI = true; @@ -530,7 +530,7 @@ public RealmBuilder clone(Realm clone) { private void newCnonce() { try { MessageDigest md = MessageDigest.getInstance("MD5"); - byte[] b = md.digest(String.valueOf(System.currentTimeMillis()).getBytes(StandardCharsets.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); @@ -577,7 +577,7 @@ private void newResponse() throws UnsupportedEncodingException { .append(realmName) .append(":") .append(password) - .toString().getBytes(StandardCharsets.ISO_8859_1)); + .toString().getBytes(ISO_8859_1)); byte[] ha1 = md.digest(); md.reset(); @@ -585,7 +585,7 @@ private void newResponse() throws UnsupportedEncodingException { //HA2 if qop is auth-int is methodName:url:md5(entityBody) md.update(new StringBuilder(methodName) .append(':') - .append(uri).toString().getBytes(StandardCharsets.ISO_8859_1)); + .append(uri).toString().getBytes(ISO_8859_1)); byte[] ha2 = md.digest(); if(qop==null || qop.equals("")) { @@ -593,7 +593,7 @@ private void newResponse() throws UnsupportedEncodingException { .append(':') .append(nonce) .append(':') - .append(toBase16(ha2)).toString().getBytes(StandardCharsets.ISO_8859_1)); + .append(toBase16(ha2)).toString().getBytes(ISO_8859_1)); } else { //qop ="auth" or "auth-int" @@ -607,7 +607,7 @@ private void newResponse() throws UnsupportedEncodingException { .append(':') .append(qop) .append(':') - .append(toBase16(ha2)).toString().getBytes(StandardCharsets.ISO_8859_1)); + .append(toBase16(ha2)).toString().getBytes(ISO_8859_1)); } byte[] digest = md.digest(); 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 25c6c41bd7..1cdbd8777c 100644 --- a/src/main/java/com/ning/http/client/consumers/AppendableBodyConsumer.java +++ b/src/main/java/com/ning/http/client/consumers/AppendableBodyConsumer.java @@ -12,8 +12,9 @@ */ package com.ning.http.client.consumers; +import static java.nio.charset.StandardCharsets.*; + import com.ning.http.client.BodyConsumer; -import com.ning.http.util.StandardCharsets; import java.io.Closeable; import java.io.IOException; @@ -34,7 +35,7 @@ public AppendableBodyConsumer(Appendable appendable, String encoding) { public AppendableBodyConsumer(Appendable appendable) { this.appendable = appendable; - this.encoding = StandardCharsets.UTF_8.name(); + this.encoding = UTF_8.name(); } @Override diff --git a/src/main/java/com/ning/http/client/multipart/AbstractFilePart.java b/src/main/java/com/ning/http/client/multipart/AbstractFilePart.java index 83e2a46b92..d800e006c5 100644 --- a/src/main/java/com/ning/http/client/multipart/AbstractFilePart.java +++ b/src/main/java/com/ning/http/client/multipart/AbstractFilePart.java @@ -12,7 +12,7 @@ */ package com.ning.http.client.multipart; -import static com.ning.http.util.StandardCharsets.US_ASCII; +import static java.nio.charset.StandardCharsets.*; import java.io.ByteArrayOutputStream; import java.io.IOException; diff --git a/src/main/java/com/ning/http/client/multipart/MultipartUtils.java b/src/main/java/com/ning/http/client/multipart/MultipartUtils.java index 07b0cc9a33..72eb673a44 100644 --- a/src/main/java/com/ning/http/client/multipart/MultipartUtils.java +++ b/src/main/java/com/ning/http/client/multipart/MultipartUtils.java @@ -15,12 +15,13 @@ */ package com.ning.http.client.multipart; +import static java.nio.charset.StandardCharsets.*; + import static com.ning.http.client.multipart.Part.CRLF_BYTES; import static com.ning.http.client.multipart.Part.EXTRA_BYTES; import static com.ning.http.util.MiscUtils.isNonEmpty; import com.ning.http.client.FluentCaseInsensitiveStringsMap; -import com.ning.http.util.StandardCharsets; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -48,7 +49,7 @@ public class MultipartUtils { * The pool of ASCII chars to be used for generating a multipart boundary. */ private static byte[] MULTIPART_CHARS = "-_1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" - .getBytes(StandardCharsets.US_ASCII); + .getBytes(US_ASCII); private MultipartUtils() { } @@ -74,7 +75,7 @@ public static MultipartBody newMultipartBody(List parts, FluentCaseInsensi // boundary defined in existing Content-Type contentType = contentTypeHeader; multipartBoundary = (contentTypeHeader.substring(boundaryLocation + "boundary=".length()).trim()) - .getBytes(StandardCharsets.US_ASCII); + .getBytes(US_ASCII); } else { // generate boundary and append it to existing Content-Type multipartBoundary = generateMultipartBoundary(); @@ -103,7 +104,7 @@ private static String computeContentType(String base, byte[] multipartBoundary) StringBuilder buffer = new StringBuilder(base); if (!base.endsWith(";")) buffer.append(";"); - return buffer.append(" boundary=").append(new String(multipartBoundary, StandardCharsets.US_ASCII)).toString(); + return buffer.append(" boundary=").append(new String(multipartBoundary, US_ASCII)).toString(); } public static long writeBytesToChannel(WritableByteChannel target, byte[] bytes) throws IOException { diff --git a/src/main/java/com/ning/http/client/multipart/Part.java b/src/main/java/com/ning/http/client/multipart/Part.java index 9486a41824..d744022766 100644 --- a/src/main/java/com/ning/http/client/multipart/Part.java +++ b/src/main/java/com/ning/http/client/multipart/Part.java @@ -12,7 +12,7 @@ */ package com.ning.http.client.multipart; -import static com.ning.http.util.StandardCharsets.US_ASCII; +import static java.nio.charset.StandardCharsets.US_ASCII; import java.io.IOException; import java.io.OutputStream; diff --git a/src/main/java/com/ning/http/client/multipart/PartBase.java b/src/main/java/com/ning/http/client/multipart/PartBase.java index 71da20c7e5..206838ca86 100644 --- a/src/main/java/com/ning/http/client/multipart/PartBase.java +++ b/src/main/java/com/ning/http/client/multipart/PartBase.java @@ -12,7 +12,7 @@ */ package com.ning.http.client.multipart; -import static com.ning.http.util.StandardCharsets.US_ASCII; +import static java.nio.charset.StandardCharsets.*; import java.io.IOException; import java.io.OutputStream; diff --git a/src/main/java/com/ning/http/client/multipart/StringPart.java b/src/main/java/com/ning/http/client/multipart/StringPart.java index d898b213ec..4d0fb1bf6b 100644 --- a/src/main/java/com/ning/http/client/multipart/StringPart.java +++ b/src/main/java/com/ning/http/client/multipart/StringPart.java @@ -12,7 +12,7 @@ */ package com.ning.http.client.multipart; -import com.ning.http.util.StandardCharsets; +import static java.nio.charset.StandardCharsets.*; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -30,7 +30,7 @@ public class StringPart extends PartBase { /** * Default charset of string parameters */ - public static final Charset DEFAULT_CHARSET = StandardCharsets.US_ASCII; + public static final Charset DEFAULT_CHARSET = US_ASCII; /** * Default transfer encoding of string parameters 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 853abd6c2c..6b64ec1dfd 100644 --- a/src/main/java/com/ning/http/client/ntlm/NTLMEngine.java +++ b/src/main/java/com/ning/http/client/ntlm/NTLMEngine.java @@ -101,6 +101,22 @@ public class NTLMEngine { public static final NTLMEngine INSTANCE = new NTLMEngine(); + private static byte[] getUnicodeLittleUnmarkedBytes(String s) throws NTLMEngineException { + try { + return s.getBytes("UnicodeLittleUnmarked"); + } catch (java.io.UnsupportedEncodingException e) { + throw new NTLMEngineException("UnicodeLittleUnmarked not supported! " + e.getMessage(), e); + } + } + + private static String fromUnicodeLittleUnmarkedBytes(byte[] bytes) throws NTLMEngineException { + try { + return new String(bytes, "UnicodeLittleUnmarked"); + } catch (UnsupportedEncodingException e) { + throw new NTLMEngineException(e.getMessage(), e); + } + } + /** * Returns the response for the given message. * @@ -112,14 +128,13 @@ public class NTLMEngine { * @return The response. * @throws NTLMEngineException If the messages cannot be retrieved. */ - final String getResponseFor(String message, String username, String password, - String host, String domain) throws NTLMEngineException { + final String getResponseFor(String message, String username, String password, String host, String domain) throws NTLMEngineException { final String response; if (isNonEmpty(message)) { Type2Message t2m = new Type2Message(message); - response = getType3Message(username, password, host, domain, t2m.getChallenge(), t2m - .getFlags(), t2m.getTarget(), t2m.getTargetInfo()); + response = getType3Message(username, password, host, domain, t2m.getChallenge(), t2m.getFlags(), t2m.getTarget(), + t2m.getTargetInfo()); } else { response = getType1Message(host, domain); } @@ -157,12 +172,10 @@ String getType1Message(String host, String domain) throws NTLMEngineException { * @return The type 3 message. * @throws NTLMEngineException If {@encrypt(byte[],byte[])} fails. */ - String getType3Message(String user, String password, String host, String domain, - byte[] nonce, int type2Flags, String target, byte[] targetInformation) - throws NTLMEngineException { + String getType3Message(String user, String password, String host, String domain, byte[] nonce, int type2Flags, String target, + byte[] targetInformation) throws NTLMEngineException { try { - return new Type3Message(domain, host, user, password, nonce, type2Flags, target, - targetInformation).getResponse(); + return new Type3Message(domain, host, user, password, nonce, type2Flags, target, targetInformation).getResponse(); } catch (UnsupportedEncodingException e) { throw new NTLMEngineException("Unsupported encoding", e); } @@ -209,8 +222,7 @@ private static String convertDomain(String domain) { private static int readULong(byte[] src, int index) throws NTLMEngineException { if (src.length < index + 4) throw new NTLMEngineException("NTLM authentication - buffer too small for DWORD"); - return (src[index] & 0xff) | ((src[index + 1] & 0xff) << 8) - | ((src[index + 2] & 0xff) << 16) | ((src[index + 3] & 0xff) << 24); + return (src[index] & 0xff) | ((src[index + 1] & 0xff) << 8) | ((src[index + 2] & 0xff) << 16) | ((src[index + 3] & 0xff) << 24); } private static int readUShort(byte[] src, int index) throws NTLMEngineException { @@ -223,8 +235,7 @@ private static byte[] readSecurityBuffer(byte[] src, int index) throws NTLMEngin int length = readUShort(src, index); int offset = readULong(src, index + 4); if (src.length < offset + length) - throw new NTLMEngineException( - "NTLM authentication - buffer too small for data item"); + throw new NTLMEngineException("NTLM authentication - buffer too small for data item"); byte[] buffer = new byte[length]; System.arraycopy(src, offset, buffer, 0, length); return buffer; @@ -268,8 +279,7 @@ private static byte[] makeNTLM2RandomChallenge() throws NTLMEngineException { * @param challenge The Type 2 challenge from the server. * @return The LM Response. */ - static byte[] getLMResponse(String password, byte[] challenge) - throws NTLMEngineException { + static byte[] getLMResponse(String password, byte[] challenge) throws NTLMEngineException { byte[] lmHash = lmHash(password); return lmResponse(lmHash, challenge); } @@ -282,8 +292,7 @@ static byte[] getLMResponse(String password, byte[] challenge) * @param challenge The Type 2 challenge from the server. * @return The NTLM Response. */ - static byte[] getNTLMResponse(String password, byte[] challenge) - throws NTLMEngineException { + static byte[] getNTLMResponse(String password, byte[] challenge) throws NTLMEngineException { byte[] ntlmHash = ntlmHash(password); return lmResponse(ntlmHash, challenge); } @@ -301,9 +310,8 @@ static byte[] getNTLMResponse(String password, byte[] challenge) * @param clientChallenge The random 8-byte client challenge. * @return The NTLMv2 Response. */ - static byte[] getNTLMv2Response(String target, String user, String password, - byte[] challenge, byte[] clientChallenge, byte[] targetInformation) - throws NTLMEngineException { + static byte[] getNTLMv2Response(String target, String user, String password, byte[] challenge, byte[] clientChallenge, + byte[] targetInformation) throws NTLMEngineException { byte[] ntlmv2Hash = ntlmv2Hash(target, user, password); byte[] blob = createBlob(clientChallenge, targetInformation); return lmv2Response(ntlmv2Hash, challenge, blob); @@ -320,8 +328,8 @@ static byte[] getNTLMv2Response(String target, String user, String password, * @param clientChallenge The random 8-byte client challenge. * @return The LMv2 Response. */ - static byte[] getLMv2Response(String target, String user, String password, - byte[] challenge, byte[] clientChallenge) throws NTLMEngineException { + static byte[] getLMv2Response(String target, String user, String password, byte[] challenge, byte[] clientChallenge) + throws NTLMEngineException { byte[] ntlmv2Hash = ntlmv2Hash(target, user, password); return lmv2Response(ntlmv2Hash, challenge, clientChallenge); } @@ -337,8 +345,7 @@ static byte[] getLMv2Response(String target, String user, String password, * field of the Type 3 message; the LM response field contains the * client challenge, null-padded to 24 bytes. */ - static byte[] getNTLM2SessionResponse(String password, byte[] challenge, - byte[] clientChallenge) throws NTLMEngineException { + static byte[] getNTLM2SessionResponse(String password, byte[] challenge, byte[] clientChallenge) throws NTLMEngineException { try { byte[] ntlmHash = ntlmHash(password); @@ -427,18 +434,13 @@ private static byte[] ntlmHash(String password) throws NTLMEngineException { * @return The NTLMv2 Hash, used in the calculation of the NTLMv2 and LMv2 * Responses. */ - private static byte[] ntlmv2Hash(String target, String user, String password) - throws NTLMEngineException { - try { - byte[] ntlmHash = ntlmHash(password); - HMACMD5 hmacMD5 = new HMACMD5(ntlmHash); - // Upper case username, mixed case target!! - hmacMD5.update(user.toUpperCase(Locale.ENGLISH).getBytes("UnicodeLittleUnmarked")); - hmacMD5.update(target.getBytes("UnicodeLittleUnmarked")); - return hmacMD5.getOutput(); - } catch (java.io.UnsupportedEncodingException e) { - throw new NTLMEngineException("Unicode not supported! " + e.getMessage(), e); - } + private static byte[] ntlmv2Hash(String target, String user, String password) throws NTLMEngineException { + byte[] ntlmHash = ntlmHash(password); + HMACMD5 hmacMD5 = new HMACMD5(ntlmHash); + // Upper case username, mixed case target!! + hmacMD5.update(getUnicodeLittleUnmarkedBytes(user.toUpperCase(Locale.ENGLISH))); + hmacMD5.update(getUnicodeLittleUnmarkedBytes(target)); + return hmacMD5.getOutput(); } /** @@ -482,8 +484,7 @@ private static byte[] lmResponse(byte[] hash, byte[] challenge) throws NTLMEngin * @return The response (either NTLMv2 or LMv2, depending on the client * data). */ - private static byte[] lmv2Response(byte[] hash, byte[] challenge, byte[] clientData) - throws NTLMEngineException { + private static byte[] lmv2Response(byte[] hash, byte[] challenge, byte[] clientData) throws NTLMEngineException { HMACMD5 hmacMD5 = new HMACMD5(hash); hmacMD5.update(challenge); hmacMD5.update(clientData); @@ -503,9 +504,9 @@ private static byte[] lmv2Response(byte[] hash, byte[] challenge, byte[] clientD * @return The blob, used in the calculation of the NTLMv2 Response. */ private static byte[] createBlob(byte[] clientChallenge, byte[] targetInformation) { - 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}; + 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(); time += 11644473600000l; // milliseconds from January 1, 1601 -> epoch. time *= 10000; // tenths of a microsecond. @@ -515,8 +516,7 @@ private static byte[] createBlob(byte[] clientChallenge, byte[] targetInformatio timestamp[i] = (byte) time; time >>>= 8; } - byte[] blob = new byte[blobSignature.length + reserved.length + timestamp.length + 8 - + unknown1.length + targetInformation.length]; + byte[] blob = new byte[blobSignature.length + reserved.length + timestamp.length + 8 + unknown1.length + targetInformation.length]; int offset = 0; System.arraycopy(blobSignature, 0, blob, offset, blobSignature.length); offset += blobSignature.length; @@ -565,8 +565,7 @@ private static Key createDESKey(byte[] bytes, int offset) { private static void oddParity(byte[] bytes) { for (int i = 0; i < bytes.length; i++) { byte b = bytes[i]; - boolean needsParity = (((b >>> 7) ^ (b >>> 6) ^ (b >>> 5) ^ (b >>> 4) ^ (b >>> 3) - ^ (b >>> 2) ^ (b >>> 1)) & 0x01) == 0; + boolean needsParity = (((b >>> 7) ^ (b >>> 6) ^ (b >>> 5) ^ (b >>> 4) ^ (b >>> 3) ^ (b >>> 2) ^ (b >>> 1)) & 0x01) == 0; if (needsParity) { bytes[i] |= (byte) 0x01; } else { @@ -607,16 +606,15 @@ static class NTLMMessage { int i = 0; while (i < SIGNATURE.length) { if (messageContents[i] != SIGNATURE[i]) - throw new NTLMEngineException( - "NTLM message expected - instead got unrecognized bytes"); + throw new NTLMEngineException("NTLM message expected - instead got unrecognized bytes"); i++; } // Check to be sure there's a type 2 message indicator next int type = readULong(SIGNATURE.length); if (type != expectedType) - throw new NTLMEngineException("NTLM type " + Integer.toString(expectedType) - + " message expected - instead got type " + Integer.toString(type)); + throw new NTLMEngineException("NTLM type " + Integer.toString(expectedType) + " message expected - instead got type " + + Integer.toString(type)); currentOutputPosition = messageContents.length; } @@ -762,18 +760,13 @@ static class Type1Message extends NTLMMessage { * Constructor. Include the arguments the message will need */ Type1Message(String domain, String host) throws NTLMEngineException { - super(); - try { - // Strip off domain name from the host! - host = convertHost(host); - // Use only the base domain name! - domain = convertDomain(domain); - - hostBytes = host.getBytes("UnicodeLittleUnmarked"); - domainBytes = domain.toUpperCase(Locale.ENGLISH).getBytes("UnicodeLittleUnmarked"); - } catch (java.io.UnsupportedEncodingException e) { - throw new NTLMEngineException("Unicode unsupported: " + e.getMessage(), e); - } + // Strip off domain name from the host! + host = convertHost(host); + // Use only the base domain name! + domain = convertDomain(domain); + + hostBytes = getUnicodeLittleUnmarkedBytes(host); + domainBytes = getUnicodeLittleUnmarkedBytes(domain.toUpperCase(Locale.ENGLISH)); } /** @@ -791,12 +784,11 @@ String getResponse() throws UnsupportedEncodingException { prepareResponse(finalLength, 1); // Flags. These are the complete set of flags we support. - addULong(FLAG_NEGOTIATE_NTLM | FLAG_NEGOTIATE_NTLM2 | FLAG_NEGOTIATE_SIGN - | FLAG_NEGOTIATE_SEAL | - /* - * FLAG_NEGOTIATE_ALWAYS_SIGN | FLAG_NEGOTIATE_KEY_EXCH | - */ - FLAG_UNICODE_ENCODING | FLAG_TARGET_DESIRED | FLAG_NEGOTIATE_128); + addULong(FLAG_NEGOTIATE_NTLM | FLAG_NEGOTIATE_NTLM2 | FLAG_NEGOTIATE_SIGN | FLAG_NEGOTIATE_SEAL | + /* + * FLAG_NEGOTIATE_ALWAYS_SIGN | FLAG_NEGOTIATE_KEY_EXCH | + */ + FLAG_UNICODE_ENCODING | FLAG_TARGET_DESIRED | FLAG_NEGOTIATE_128); // Domain length (two times). addUShort(domainBytes.length); @@ -842,9 +834,7 @@ static class Type2Message extends NTLMMessage { flags = readULong(20); if ((flags & FLAG_UNICODE_ENCODING) == 0) - throw new NTLMEngineException( - "NTLM type 2 message has flags that make no sense: " - + Integer.toString(flags)); + throw new NTLMEngineException("NTLM type 2 message has flags that make no sense: " + Integer.toString(flags)); // Do the target! target = null; // The TARGET_DESIRED flag is said to not have understood semantics @@ -853,11 +843,7 @@ static class Type2Message extends NTLMMessage { if (getMessageLength() >= 12 + 8) { byte[] bytes = readSecurityBuffer(12); if (bytes.length != 0) { - try { - target = new String(bytes, "UnicodeLittleUnmarked"); - } catch (java.io.UnsupportedEncodingException e) { - throw new NTLMEngineException(e.getMessage(), e); - } + target = fromUnicodeLittleUnmarkedBytes(bytes); } } @@ -919,9 +905,8 @@ static class Type3Message extends NTLMMessage { /** * Constructor. Pass the arguments we will need */ - Type3Message(String domain, String host, String user, String password, byte[] nonce, - int type2Flags, String target, byte[] targetInformation) - throws NTLMEngineException { + Type3Message(String domain, String host, String user, String password, byte[] nonce, int type2Flags, String target, + byte[] targetInformation) throws NTLMEngineException { // Save the flags this.type2Flags = type2Flags; @@ -935,8 +920,7 @@ static class Type3Message extends NTLMMessage { try { if (targetInformation != null && target != null) { byte[] clientChallenge = makeRandomChallenge(); - ntResp = getNTLMv2Response(target, user, password, nonce, clientChallenge, - targetInformation); + ntResp = getNTLMv2Response(target, user, password, nonce, clientChallenge, targetInformation); lmResp = getLMv2Response(target, user, password, nonce, clientChallenge); } else { if ((type2Flags & FLAG_NEGOTIATE_NTLM2) != 0) { @@ -962,13 +946,9 @@ static class Type3Message extends NTLMMessage { lmResp = getLMResponse(password, nonce); } - try { - domainBytes = domain.toUpperCase(Locale.ENGLISH).getBytes("UnicodeLittleUnmarked"); - hostBytes = host.getBytes("UnicodeLittleUnmarked"); - userBytes = user.getBytes("UnicodeLittleUnmarked"); - } catch (java.io.UnsupportedEncodingException e) { - throw new NTLMEngineException("Unicode not supported: " + e.getMessage(), e); - } + domainBytes = getUnicodeLittleUnmarkedBytes(domain.toUpperCase(Locale.ENGLISH)); + hostBytes = getUnicodeLittleUnmarkedBytes(host); + userBytes = getUnicodeLittleUnmarkedBytes(user); } /** @@ -1037,11 +1017,9 @@ String getResponse() throws UnsupportedEncodingException { // Flags. Currently: NEGOTIATE_NTLM + UNICODE_ENCODING + // TARGET_DESIRED + NEGOTIATE_128 - addULong(FLAG_NEGOTIATE_NTLM | FLAG_UNICODE_ENCODING | FLAG_TARGET_DESIRED - | FLAG_NEGOTIATE_128 | (type2Flags & FLAG_NEGOTIATE_NTLM2) - | (type2Flags & FLAG_NEGOTIATE_SIGN) | (type2Flags & FLAG_NEGOTIATE_SEAL) - | (type2Flags & FLAG_NEGOTIATE_KEY_EXCH) - | (type2Flags & FLAG_NEGOTIATE_ALWAYS_SIGN)); + addULong(FLAG_NEGOTIATE_NTLM | FLAG_UNICODE_ENCODING | FLAG_TARGET_DESIRED | FLAG_NEGOTIATE_128 + | (type2Flags & FLAG_NEGOTIATE_NTLM2) | (type2Flags & FLAG_NEGOTIATE_SIGN) | (type2Flags & FLAG_NEGOTIATE_SEAL) + | (type2Flags & FLAG_NEGOTIATE_KEY_EXCH) | (type2Flags & FLAG_NEGOTIATE_ALWAYS_SIGN)); // Add the actual data addBytes(lmResp); @@ -1153,8 +1131,7 @@ protected void processBuffer() { int[] d = new int[16]; for (int i = 0; i < 16; i++) { - d[i] = (dataBuffer[i * 4] & 0xff) + ((dataBuffer[i * 4 + 1] & 0xff) << 8) - + ((dataBuffer[i * 4 + 2] & 0xff) << 16) + d[i] = (dataBuffer[i * 4] & 0xff) + ((dataBuffer[i * 4 + 1] & 0xff) << 8) + ((dataBuffer[i * 4 + 2] & 0xff) << 16) + ((dataBuffer[i * 4 + 3] & 0xff) << 24); } @@ -1258,8 +1235,7 @@ static class HMACMD5 { } catch (Exception ex) { // Umm, the algorithm doesn't exist - throw an // NTLMEngineException! - throw new NTLMEngineException( - "Error getting md5 message digest implementation: " + ex.getMessage(), ex); + throw new NTLMEngineException("Error getting md5 message digest implementation: " + ex.getMessage(), ex); } // Initialize the pad buffers with the key @@ -1316,27 +1292,14 @@ void update(byte[] input, int offset, int length) { } - public String generateType1Msg( - final String domain, - final String workstation) throws NTLMEngineException { + public String generateType1Msg(final String domain, final String workstation) throws NTLMEngineException { return getType1Message(workstation, domain); } - public String generateType3Msg( - final String username, - final String password, - final String domain, - final String workstation, + public String generateType3Msg(final String username, final String password, final String domain, final String workstation, final String challenge) throws NTLMEngineException { Type2Message t2m = new Type2Message(challenge); - return getType3Message( - username, - password, - workstation, - domain, - t2m.getChallenge(), - t2m.getFlags(), - t2m.getTarget(), + return getType3Message(username, password, workstation, domain, t2m.getChallenge(), t2m.getFlags(), t2m.getTarget(), t2m.getTargetInfo()); } } 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 283f09380c..37ee5409a7 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 java.nio.charset.StandardCharsets.*; import static com.ning.http.util.MiscUtils.isNonEmpty; import com.ning.http.client.Param; @@ -24,7 +25,6 @@ import com.ning.http.client.SignatureCalculator; import com.ning.http.client.uri.Uri; import com.ning.http.util.Base64; -import com.ning.http.util.StandardCharsets; import com.ning.http.util.UTF8UrlEncoder; import java.util.ArrayList; @@ -152,7 +152,7 @@ else if (scheme.equals("https")) signedText.append('&'); UTF8UrlEncoder.appendEncoded(signedText, encodedParams); - byte[] rawBase = signedText.toString().getBytes(StandardCharsets.UTF_8); + byte[] rawBase = signedText.toString().getBytes(UTF_8); byte[] rawSignature = mac.digest(rawBase); // and finally, base64 encoded... phew! return Base64.encode(rawSignature); 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 2f47afc11c..7f3b0f0fbd 100644 --- a/src/main/java/com/ning/http/client/oauth/ThreadSafeHMAC.java +++ b/src/main/java/com/ning/http/client/oauth/ThreadSafeHMAC.java @@ -16,7 +16,8 @@ */ package com.ning.http.client.oauth; -import com.ning.http.util.StandardCharsets; +import static java.nio.charset.StandardCharsets.*; + import com.ning.http.util.UTF8UrlEncoder; import javax.crypto.Mac; @@ -41,7 +42,7 @@ public ThreadSafeHMAC(ConsumerKey consumerAuth, RequestToken userAuth) { UTF8UrlEncoder.appendEncoded(sb, consumerAuth.getSecret()); sb.append('&'); UTF8UrlEncoder.appendEncoded(sb, userAuth.getSecret()); - byte[] keyBytes = sb.toString().getBytes(StandardCharsets.UTF_8); + byte[] keyBytes = sb.toString().getBytes(UTF_8); SecretKeySpec signingKey = new SecretKeySpec(keyBytes, HMAC_SHA1_ALGORITHM); // Get an hmac_sha1 instance and initialize with the signing key 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 afd6232886..d983d25efa 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,7 @@ */ package com.ning.http.client.providers.apache; +import static java.nio.charset.StandardCharsets.*; import static com.ning.http.util.AsyncHttpProviderUtils.DEFAULT_CHARSET; import static com.ning.http.util.MiscUtils.closeSilently; import static com.ning.http.util.MiscUtils.isNonEmpty; @@ -81,7 +82,6 @@ import com.ning.http.client.uri.Uri; import com.ning.http.util.AsyncHttpProviderUtils; import com.ning.http.util.ProxyUtils; -import com.ning.http.util.StandardCharsets; import com.ning.http.util.UTF8UrlEncoder; import javax.net.SocketFactory; @@ -254,7 +254,7 @@ private HttpMethodBase createMethod(HttpClient client, Request request) throws I String bodyCharset = request.getBodyEncoding() == null ? DEFAULT_CHARSET.name() : request.getBodyEncoding(); - post.getParams().setContentCharset(StandardCharsets.ISO_8859_1.name()); + post.getParams().setContentCharset(ISO_8859_1.name()); if (request.getByteData() != null) { post.setRequestEntity(new ByteArrayRequestEntity(request.getByteData())); post.setRequestHeader("Content-Length", String.valueOf(request.getByteData().length)); @@ -280,7 +280,7 @@ private HttpMethodBase createMethod(HttpClient client, Request request) throws I } post.setRequestHeader("Content-Length", String.valueOf(sb.length())); - post.setRequestEntity(new StringRequestEntity(sb.toString(), "text/xml", StandardCharsets.ISO_8859_1.name())); + post.setRequestEntity(new StringRequestEntity(sb.toString(), "text/xml", ISO_8859_1.name())); if (!request.getHeaders().containsKey("Content-Type")) { post.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); diff --git a/src/main/java/com/ning/http/client/providers/jdk/MultipartRequestEntity.java b/src/main/java/com/ning/http/client/providers/jdk/MultipartRequestEntity.java index 634eddfe05..d64161469b 100644 --- a/src/main/java/com/ning/http/client/providers/jdk/MultipartRequestEntity.java +++ b/src/main/java/com/ning/http/client/providers/jdk/MultipartRequestEntity.java @@ -15,8 +15,8 @@ */ package com.ning.http.client.providers.jdk; +import static java.nio.charset.StandardCharsets.*; import static com.ning.http.util.MiscUtils.isNonEmpty; -import static com.ning.http.util.StandardCharsets.US_ASCII; import com.ning.http.client.FluentCaseInsensitiveStringsMap; import com.ning.http.client.multipart.MultipartUtils; diff --git a/src/main/java/com/ning/http/client/providers/netty/request/body/FeedableBodyGenerator.java b/src/main/java/com/ning/http/client/providers/netty/request/body/FeedableBodyGenerator.java index 14c9320c93..2e18712fb9 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/body/FeedableBodyGenerator.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/body/FeedableBodyGenerator.java @@ -13,9 +13,10 @@ */ package com.ning.http.client.providers.netty.request.body; +import static java.nio.charset.StandardCharsets.*; + import com.ning.http.client.Body; import com.ning.http.client.BodyGenerator; -import com.ning.http.util.StandardCharsets; import java.io.IOException; import java.nio.ByteBuffer; @@ -28,8 +29,8 @@ * If it happens, PartialBodyGenerator becomes responsible for finishing payload transferring asynchronously. */ public class FeedableBodyGenerator implements BodyGenerator { - private final static byte[] END_PADDING = "\r\n".getBytes(StandardCharsets.US_ASCII); - private final static byte[] ZERO = "0".getBytes(StandardCharsets.US_ASCII); + private final static byte[] END_PADDING = "\r\n".getBytes(US_ASCII); + private final static byte[] ZERO = "0".getBytes(US_ASCII); private final Queue queue = new ConcurrentLinkedQueue(); private final AtomicInteger queueSize = new AtomicInteger(); private FeedListener listener; @@ -87,7 +88,7 @@ public long read(final ByteBuffer buffer) throws IOException { } int capacity = buffer.remaining() - 10; // be safe (we'll have to add size, ending, etc.) int size = Math.min(nextPart.buffer.remaining(), capacity); - buffer.put(Integer.toHexString(size).getBytes(StandardCharsets.US_ASCII)); + buffer.put(Integer.toHexString(size).getBytes(US_ASCII)); buffer.put(END_PADDING); for (int i = 0; i < size; i++) { buffer.put(nextPart.buffer.get()); diff --git a/src/main/java/com/ning/http/client/providers/netty/ws/NettyWebSocket.java b/src/main/java/com/ning/http/client/providers/netty/ws/NettyWebSocket.java index ed5c970843..e5f27bcf7d 100644 --- a/src/main/java/com/ning/http/client/providers/netty/ws/NettyWebSocket.java +++ b/src/main/java/com/ning/http/client/providers/netty/ws/NettyWebSocket.java @@ -13,8 +13,8 @@ */ package com.ning.http.client.providers.netty.ws; +import static java.nio.charset.StandardCharsets.*; import static com.ning.http.client.providers.netty.util.ChannelBufferUtils.channelBuffer2bytes; -import static com.ning.http.util.StandardCharsets.UTF_8; import static org.jboss.netty.buffer.ChannelBuffers.wrappedBuffer; import org.jboss.netty.buffer.ChannelBuffer; 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 80fe979640..f2b944fd24 100644 --- a/src/main/java/com/ning/http/client/resumable/PropertiesBasedResumableProcessor.java +++ b/src/main/java/com/ning/http/client/resumable/PropertiesBasedResumableProcessor.java @@ -12,17 +12,15 @@ */ package com.ning.http.client.resumable; +import static java.nio.charset.StandardCharsets.*; import static com.ning.http.util.MiscUtils.closeSilently; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.ning.http.util.StandardCharsets; - import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; -import java.io.IOException; import java.util.Map; import java.util.Scanner; import java.util.concurrent.ConcurrentHashMap; @@ -69,7 +67,7 @@ public void save(Map map) { os = new FileOutputStream(f); for (Map.Entry e : properties.entrySet()) { - os.write((append(e)).getBytes(StandardCharsets.UTF_8)); + os.write((append(e)).getBytes(UTF_8)); } os.flush(); } catch (Throwable e) { @@ -88,7 +86,7 @@ private static String append(Map.Entry e) { public Map load() { Scanner scan = null; try { - scan = new Scanner(new File(TMP, storeName), StandardCharsets.UTF_8.name()); + scan = new Scanner(new File(TMP, storeName), UTF_8.name()); scan.useDelimiter("[=\n]"); String key; diff --git a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java index 2fcf77a4c3..4bf281c9b4 100644 --- a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java +++ b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java @@ -12,6 +12,7 @@ */ package com.ning.http.util; +import static java.nio.charset.StandardCharsets.*; import static com.ning.http.util.MiscUtils.isNonEmpty; import com.ning.http.client.AsyncHttpClientConfig; @@ -35,7 +36,7 @@ */ public class AsyncHttpProviderUtils { - public final static Charset DEFAULT_CHARSET = StandardCharsets.ISO_8859_1; + public final static Charset DEFAULT_CHARSET = ISO_8859_1; static final byte[] EMPTY_BYTE_ARRAY = "".getBytes(); diff --git a/src/main/java/com/ning/http/util/AuthenticatorUtils.java b/src/main/java/com/ning/http/util/AuthenticatorUtils.java index baf6f9af06..bdc8de9991 100644 --- a/src/main/java/com/ning/http/util/AuthenticatorUtils.java +++ b/src/main/java/com/ning/http/util/AuthenticatorUtils.java @@ -12,6 +12,7 @@ */ package com.ning.http.util; +import static java.nio.charset.StandardCharsets.*; import static com.ning.http.util.AsyncHttpProviderUtils.getNonEmptyPath; import static com.ning.http.util.MiscUtils.isNonEmpty; @@ -65,7 +66,7 @@ public static String computeDigestAuthentication(Realm realm) throws NoSuchAlgor append(builder, "cnonce", realm.getCnonce(), true); builder.setLength(builder.length() - 2); // remove tailing ", " - return new String(builder.toString().getBytes(StandardCharsets.ISO_8859_1)); + return new String(builder.toString().getBytes(ISO_8859_1)); } private static StringBuilder append(StringBuilder builder, String name, String value, boolean quoted) { diff --git a/src/main/java/com/ning/http/util/StandardCharsets.java b/src/main/java/com/ning/http/util/StandardCharsets.java deleted file mode 100644 index bcea14845e..0000000000 --- a/src/main/java/com/ning/http/util/StandardCharsets.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2014 AsyncHttpClient Project. 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.nio.charset.Charset; - -public final class StandardCharsets { - - public static final Charset US_ASCII = Charset.forName("US-ASCII"); - public static final Charset UTF_8 = Charset.forName("UTF-8"); - public static final Charset UTF_16 = Charset.forName("UTF-16"); - public static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1"); - public static final Charset UNICODE_LITTLE_UNMARKED = Charset.forName("UnicodeLittleUnmarked"); - - private StandardCharsets() { - } -} diff --git a/src/test/java/com/ning/http/client/RealmTest.java b/src/test/java/com/ning/http/client/RealmTest.java index 43be2b07b1..308da145c0 100644 --- a/src/test/java/com/ning/http/client/RealmTest.java +++ b/src/test/java/com/ning/http/client/RealmTest.java @@ -12,10 +12,11 @@ */ package com.ning.http.client; +import static java.nio.charset.StandardCharsets.*; + import com.ning.http.client.Realm.AuthScheme; import com.ning.http.client.Realm.RealmBuilder; import com.ning.http.client.uri.Uri; -import com.ning.http.util.StandardCharsets; import org.testng.Assert; @@ -111,7 +112,7 @@ public void testStrongDigest() { private String getMd5(String what) { try { MessageDigest md = MessageDigest.getInstance("MD5"); - md.update(what.getBytes(StandardCharsets.ISO_8859_1)); + md.update(what.getBytes(ISO_8859_1)); byte[] hash = md.digest(); BigInteger bi = new BigInteger(1, hash); String result = bi.toString(16); 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 638ca6444c..ea201b156c 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 java.nio.charset.StandardCharsets.*; import static com.ning.http.util.DateUtils.millisTime; import static com.ning.http.util.MiscUtils.isNonEmpty; import static org.testng.Assert.assertEquals; @@ -40,7 +41,6 @@ import com.ning.http.client.cookie.Cookie; import com.ning.http.client.multipart.Part; import com.ning.http.client.multipart.StringPart; -import com.ning.http.util.StandardCharsets; import java.io.ByteArrayInputStream; import java.io.IOException; @@ -63,7 +63,7 @@ import java.util.concurrent.atomic.AtomicReference; public abstract class AsyncProvidersBasicTest extends AbstractBasicTest { - private static final String UTF_8 = "text/html;charset=UTF-8"; + private static final String TEXT_HTML_UTF_8 = "text/html;charset=UTF-8"; @Test(groups = { "standalone", "default_provider", "async" }) public void asyncProviderEncodingTest() throws Throwable { @@ -203,7 +203,7 @@ public void asyncContentTypeGETTest() throws Throwable { public Response onCompleted(Response response) throws Exception { try { assertEquals(response.getStatusCode(), 200); - assertEquals(response.getContentType(), UTF_8); + assertEquals(response.getContentType(), TEXT_HTML_UTF_8); } finally { l.countDown(); } @@ -230,7 +230,7 @@ public void asyncHeaderGETTest() throws Throwable { public Response onCompleted(Response response) throws Exception { try { assertEquals(response.getStatusCode(), 200); - assertEquals(response.getContentType(), UTF_8); + assertEquals(response.getContentType(), TEXT_HTML_UTF_8); } finally { l.countDown(); } @@ -536,7 +536,7 @@ public void asyncDoPostBodyIsoTest() throws Throwable { 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(StandardCharsets.ISO_8859_1), "\u017D\u017D\u017D\u017D\u017D\u017D".getBytes(StandardCharsets.ISO_8859_1)); + assertEquals(r.getResponseBody().getBytes(ISO_8859_1), "\u017D\u017D\u017D\u017D\u017D\u017D".getBytes(ISO_8859_1)); } finally { client.close(); } @@ -677,7 +677,7 @@ public void asyncDoPostMultiPartTest() throws Throwable { try { final CountDownLatch l = new CountDownLatch(1); - Part p = new StringPart("foo", "bar", StandardCharsets.UTF_8); + Part p = new StringPart("foo", "bar", UTF_8); client.preparePost(getTargetUrl()).addBodyPart(p).execute(new AsyncCompletionHandlerAdapter() { 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 5336e23c15..51ab2b80bb 100644 --- a/src/test/java/com/ning/http/client/async/AsyncStreamHandlerTest.java +++ b/src/test/java/com/ning/http/client/async/AsyncStreamHandlerTest.java @@ -34,7 +34,6 @@ import com.ning.http.client.Response; import java.util.Arrays; -import java.util.Locale; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; diff --git a/src/test/java/com/ning/http/client/async/FastUnauthorizedUploadTest.java b/src/test/java/com/ning/http/client/async/FastUnauthorizedUploadTest.java index acbeb90e6f..7645cb42fd 100644 --- a/src/test/java/com/ning/http/client/async/FastUnauthorizedUploadTest.java +++ b/src/test/java/com/ning/http/client/async/FastUnauthorizedUploadTest.java @@ -12,6 +12,8 @@ */ package com.ning.http.client.async; +import static java.nio.charset.StandardCharsets.*; + import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.handler.AbstractHandler; import org.testng.Assert; @@ -21,7 +23,6 @@ import com.ning.http.client.AsyncHttpClient.BoundRequestBuilder; import com.ning.http.client.Response; import com.ning.http.client.multipart.FilePart; -import com.ning.http.util.StandardCharsets; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; @@ -49,7 +50,7 @@ public void handle(String target, Request baseRequest, HttpServletRequest req, H @Test(groups = { "standalone", "default_provider" }, enabled = true) public void testUnauthorizedWhileUploading() throws Exception { - byte[] bytes = "RatherLargeFileRatherLargeFileRatherLargeFileRatherLargeFile".getBytes(StandardCharsets.UTF_16); + byte[] bytes = "RatherLargeFileRatherLargeFileRatherLargeFileRatherLargeFile".getBytes(UTF_16); long repeats = (1024 * 1024 / bytes.length) + 1; File largeFile = FilePartLargeFileTest.createTempFile(bytes, (int) repeats); @@ -57,7 +58,7 @@ public void testUnauthorizedWhileUploading() throws Exception { try { BoundRequestBuilder rb = client.preparePut(getTargetUrl()); - rb.addBodyPart(new FilePart("test", largeFile, "application/octet-stream", StandardCharsets.UTF_8)); + rb.addBodyPart(new FilePart("test", largeFile, "application/octet-stream", UTF_8)); Response response = rb.execute().get(); Assert.assertEquals(401, response.getStatusCode()); 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 a9f748f147..f8a4be043e 100644 --- a/src/test/java/com/ning/http/client/async/FilePartLargeFileTest.java +++ b/src/test/java/com/ning/http/client/async/FilePartLargeFileTest.java @@ -12,6 +12,7 @@ */ package com.ning.http.client.async; +import static java.nio.charset.StandardCharsets.*; import static org.testng.FileAssert.fail; import org.eclipse.jetty.server.Request; @@ -24,7 +25,6 @@ import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.Response; import com.ning.http.client.multipart.FilePart; -import com.ning.http.util.StandardCharsets; import javax.servlet.ServletException; import javax.servlet.ServletInputStream; @@ -47,7 +47,7 @@ public void testPutImageFile() throws Exception { try { BoundRequestBuilder rb = client.preparePut(getTargetUrl()); - rb.addBodyPart(new FilePart("test", largeFile, "application/octet-stream", StandardCharsets.UTF_8)); + rb.addBodyPart(new FilePart("test", largeFile, "application/octet-stream", UTF_8)); Response response = rb.execute().get(); Assert.assertEquals(200, response.getStatusCode()); @@ -58,7 +58,7 @@ public void testPutImageFile() throws Exception { @Test(groups = { "standalone", "default_provider" }, enabled = true) public void testPutLargeTextFile() throws Exception { - byte[] bytes = "RatherLargeFileRatherLargeFileRatherLargeFileRatherLargeFile".getBytes(StandardCharsets.UTF_16); + byte[] bytes = "RatherLargeFileRatherLargeFileRatherLargeFileRatherLargeFile".getBytes(UTF_16); long repeats = (1024 * 1024 / bytes.length) + 1; File largeFile = createTempFile(bytes, (int) repeats); @@ -66,7 +66,7 @@ public void testPutLargeTextFile() throws Exception { try { BoundRequestBuilder rb = client.preparePut(getTargetUrl()); - rb.addBodyPart(new FilePart("test", largeFile, "application/octet-stream", StandardCharsets.UTF_8)); + rb.addBodyPart(new FilePart("test", largeFile, "application/octet-stream", UTF_8)); Response response = rb.execute().get(); Assert.assertEquals(200, response.getStatusCode()); 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 ea96b64412..f4c89c6aa2 100644 --- a/src/test/java/com/ning/http/client/async/MultipartUploadTest.java +++ b/src/test/java/com/ning/http/client/async/MultipartUploadTest.java @@ -12,7 +12,7 @@ */ package com.ning.http.client.async; -import static com.ning.http.util.StandardCharsets.*; +import static java.nio.charset.StandardCharsets.*; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNotNull; 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 68c7a67dd7..fe75357297 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,7 @@ */ package com.ning.http.client.async; -import static com.ning.http.util.StandardCharsets.UTF_8; +import static java.nio.charset.StandardCharsets.*; import static junit.framework.Assert.assertTrue; import static org.testng.Assert.assertEquals; diff --git a/src/test/java/com/ning/http/client/multipart/MultipartBodyTest.java b/src/test/java/com/ning/http/client/multipart/MultipartBodyTest.java index addc881f95..35abc7f550 100644 --- a/src/test/java/com/ning/http/client/multipart/MultipartBodyTest.java +++ b/src/test/java/com/ning/http/client/multipart/MultipartBodyTest.java @@ -12,7 +12,7 @@ */ package com.ning.http.client.multipart; -import static com.ning.http.util.StandardCharsets.UTF_8; +import static java.nio.charset.StandardCharsets.*; import org.testng.Assert; import org.testng.annotations.Test; @@ -23,7 +23,6 @@ import com.ning.http.client.multipart.FilePart; import com.ning.http.client.multipart.Part; import com.ning.http.client.multipart.StringPart; -import com.ning.http.util.StandardCharsets; import java.io.File; import java.io.IOException; @@ -44,7 +43,7 @@ public void testBasics() { parts.add(new FilePart("filePart", testFile)); // add a byte array - parts.add(new ByteArrayPart("baPart", "testMultiPart".getBytes(UTF_8), "application/test", StandardCharsets.UTF_8, "fileName")); + parts.add(new ByteArrayPart("baPart", "testMultiPart".getBytes(UTF_8), "application/test", UTF_8, "fileName")); // add a string parts.add(new StringPart("stringPart", "testString", UTF_8)); From 6a2f397522a79bab8753734c7f954872724bfb91 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 17 Sep 2014 15:15:55 +0200 Subject: [PATCH 600/701] clean up --- .../java/com/ning/http/client/ntlm/NTLMEngine.java | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) 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 6b64ec1dfd..502e874790 100644 --- a/src/main/java/com/ning/http/client/ntlm/NTLMEngine.java +++ b/src/main/java/com/ning/http/client/ntlm/NTLMEngine.java @@ -104,7 +104,7 @@ public class NTLMEngine { private static byte[] getUnicodeLittleUnmarkedBytes(String s) throws NTLMEngineException { try { return s.getBytes("UnicodeLittleUnmarked"); - } catch (java.io.UnsupportedEncodingException e) { + } catch (UnsupportedEncodingException e) { throw new NTLMEngineException("UnicodeLittleUnmarked not supported! " + e.getMessage(), e); } } @@ -415,14 +415,10 @@ private static byte[] lmHash(String password) throws NTLMEngineException { * the NTLM Response and the NTLMv2 and LMv2 Hashes. */ private static byte[] ntlmHash(String password) throws NTLMEngineException { - try { - byte[] unicodePassword = password.getBytes("UnicodeLittleUnmarked"); - MD4 md4 = new MD4(); - md4.update(unicodePassword); - return md4.getOutput(); - } catch (java.io.UnsupportedEncodingException e) { - throw new NTLMEngineException("Unicode not supported: " + e.getMessage(), e); - } + byte[] unicodePassword = getUnicodeLittleUnmarkedBytes(password); + MD4 md4 = new MD4(); + md4.update(unicodePassword); + return md4.getOutput(); } /** From cdb4ebe435cd2c3916c3ad0332081c85b0acd654 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 18 Sep 2014 09:59:13 +0200 Subject: [PATCH 601/701] Rename connectionTimeout into connectTimeout, close #704 --- .../http/client/AsyncHttpClientConfig.java | 22 +++++++++---------- .../client/AsyncHttpClientConfigBean.java | 4 ++-- .../client/AsyncHttpClientConfigDefaults.java | 4 ++-- .../http/client/SimpleAsyncHttpClient.java | 2 +- .../grizzly/GrizzlyAsyncHttpProvider.java | 4 ++-- .../providers/jdk/JDKAsyncHttpProvider.java | 2 +- .../netty/channel/ChannelManager.java | 4 ++-- .../http/client/async/AuthTimeoutTest.java | 16 +++++++------- .../ning/http/client/async/BodyChunkTest.java | 2 +- .../ning/http/client/async/ChunkingTest.java | 2 +- .../http/client/async/ConnectionPoolTest.java | 4 ++-- .../client/async/MaxConnectionsInThreads.java | 2 +- .../client/async/MaxTotalConnectionTest.java | 6 ++--- .../http/client/async/NoNullResponseTest.java | 2 +- .../http/client/async/PutLargeFileTest.java | 2 +- .../async/RedirectConnectionUsageTest.java | 2 +- .../client/async/RetryNonBlockingIssue.java | 6 ++--- .../grizzly/GrizzlyConnectionPoolTest.java | 2 +- .../GrizzlyNoTransferEncodingTest.java | 2 +- 19 files changed, 45 insertions(+), 45 deletions(-) diff --git a/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java b/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java index b86848b0ac..0784474230 100644 --- a/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java @@ -42,7 +42,7 @@ */ public class AsyncHttpClientConfig { - protected int connectionTimeout; + protected int connectTimeout; protected int maxConnections; protected int maxConnectionsPerHost; @@ -84,7 +84,7 @@ public class AsyncHttpClientConfig { protected AsyncHttpClientConfig() { } - private AsyncHttpClientConfig(int connectionTimeout,// + private AsyncHttpClientConfig(int connectTimeout,// int maxConnections,// int maxConnectionsPerHost,// int requestTimeout,// @@ -116,7 +116,7 @@ private AsyncHttpClientConfig(int connectionTimeout,// TimeConverter timeConverter,// AsyncHttpProviderConfig providerConfig) { - this.connectionTimeout = connectionTimeout; + this.connectTimeout = connectTimeout; this.maxConnections = maxConnections; this.maxConnectionsPerHost = maxConnectionsPerHost; this.requestTimeout = requestTimeout; @@ -172,8 +172,8 @@ public int getMaxConnectionsPerHost() { * * @return the maximum time in millisecond an {@link com.ning.http.client.AsyncHttpClient} can wait when connecting to a remote host */ - public int getConnectionTimeout() { - return connectionTimeout; + public int getConnectTimeout() { + return connectTimeout; } /** @@ -453,7 +453,7 @@ public boolean isAcceptAnyCertificate() { * Builder for an {@link AsyncHttpClient} */ public static class Builder { - private int connectionTimeout = defaultConnectionTimeout(); + private int connectTimeout = defaultConnectTimeout(); private int maxConnections = defaultMaxConnections(); private int maxConnectionsPerHost = defaultMaxConnectionsPerHost(); private int requestTimeout = defaultRequestTimeout(); @@ -515,11 +515,11 @@ public Builder setMaxConnectionsPerHost(int maxConnectionsPerHost) { /** * Set the maximum time in millisecond an {@link com.ning.http.client.AsyncHttpClient} can wait when connecting to a remote host * - * @param connectionTimeOut the maximum time in millisecond an {@link com.ning.http.client.AsyncHttpClient} can wait when connecting to a remote host + * @param connectTimeOut the maximum time in millisecond an {@link com.ning.http.client.AsyncHttpClient} can wait when connecting to a remote host * @return a {@link Builder} */ - public Builder setConnectionTimeout(int connectionTimeOut) { - this.connectionTimeout = connectionTimeOut; + public Builder setConnectTimeout(int connectTimeOut) { + this.connectTimeout = connectTimeOut; return this; } @@ -911,7 +911,7 @@ public Builder setAcceptAnyCertificate(boolean acceptAnyCertificate) { public Builder(AsyncHttpClientConfig prototype) { allowPoolingConnections = prototype.isAllowPoolingConnections(); providerConfig = prototype.getAsyncHttpProviderConfig(); - connectionTimeout = prototype.getConnectionTimeout(); + connectTimeout = prototype.getConnectTimeout(); pooledConnectionIdleTimeout = prototype.getPooledConnectionIdleTimeout(); readTimeout = prototype.getReadTimeout(); maxConnectionsPerHost = prototype.getMaxConnectionsPerHost(); @@ -976,7 +976,7 @@ public Thread newThread(Runnable r) { else if (hostnameVerifier == null) hostnameVerifier = new DefaultHostnameVerifier(); - return new AsyncHttpClientConfig(connectionTimeout,// + return new AsyncHttpClientConfig(connectTimeout,// maxConnections,// maxConnectionsPerHost,// requestTimeout,// diff --git a/src/main/java/com/ning/http/client/AsyncHttpClientConfigBean.java b/src/main/java/com/ning/http/client/AsyncHttpClientConfigBean.java index 301bfeda41..ccf9a901c9 100644 --- a/src/main/java/com/ning/http/client/AsyncHttpClientConfigBean.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClientConfigBean.java @@ -47,7 +47,7 @@ void configureFilters() { void configureDefaults() { maxConnections = defaultMaxConnections(); maxConnectionsPerHost = defaultMaxConnectionsPerHost(); - connectionTimeout = defaultConnectionTimeout(); + connectTimeout = defaultConnectTimeout(); webSocketTimeout = defaultWebSocketTimeout(); pooledConnectionIdleTimeout = defaultPooledConnectionIdleTimeout(); readTimeout = defaultReadTimeout(); @@ -95,7 +95,7 @@ public AsyncHttpClientConfigBean setMaxConnectionPerHost(int maxConnectionPerHos } public AsyncHttpClientConfigBean setConnectionTimeOut(int connectionTimeOut) { - this.connectionTimeout = connectionTimeOut; + this.connectTimeout = connectionTimeOut; return this; } diff --git a/src/main/java/com/ning/http/client/AsyncHttpClientConfigDefaults.java b/src/main/java/com/ning/http/client/AsyncHttpClientConfigDefaults.java index f0cd38456b..18ff013539 100644 --- a/src/main/java/com/ning/http/client/AsyncHttpClientConfigDefaults.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClientConfigDefaults.java @@ -29,8 +29,8 @@ public static int defaultMaxConnectionsPerHost() { return Integer.getInteger(ASYNC_CLIENT + "maxConnectionsPerHost", -1); } - public static int defaultConnectionTimeout() { - return Integer.getInteger(ASYNC_CLIENT + "connectionTimeout", 60 * 1000); + public static int defaultConnectTimeout() { + return Integer.getInteger(ASYNC_CLIENT + "connectTimeout", 5 * 1000); } public static int defaultPooledConnectionIdleTimeout() { diff --git a/src/main/java/com/ning/http/client/SimpleAsyncHttpClient.java b/src/main/java/com/ning/http/client/SimpleAsyncHttpClient.java index c6062df7ed..ee8f66ff3c 100644 --- a/src/main/java/com/ning/http/client/SimpleAsyncHttpClient.java +++ b/src/main/java/com/ning/http/client/SimpleAsyncHttpClient.java @@ -499,7 +499,7 @@ public Builder setMaximumConnectionsPerHost(int defaultMaxConnectionPerHost) { } public Builder setConnectionTimeout(int connectionTimeuot) { - configBuilder.setConnectionTimeout(connectionTimeuot); + configBuilder.setConnectTimeout(connectionTimeuot); return this; } 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 364fee7ab7..8d53d978c0 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 @@ -2441,7 +2441,7 @@ private Connection obtainConnection0(final Request request, 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.getConnectionTimeout(); + int cTimeout = provider.clientConfig.getConnectTimeout(); FutureImpl future = Futures.createSafeFuture(); CompletionHandler ch = Futures.toCompletionHandler(future, createConnectionCompletionHandler(request, requestFuture, null)); @@ -2922,7 +2922,7 @@ public static void main(String[] args) { e.printStackTrace(); } AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder() - .setConnectionTimeout(5000) + .setConnectTimeout(5000) .setSSLContext(sslContext).build(); AsyncHttpClient client = new AsyncHttpClient(new GrizzlyAsyncHttpProvider(config), config); try { 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 5e776d63c8..533c6464fa 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 @@ -428,7 +428,7 @@ private void configure(Uri uri, HttpURLConnection urlConnection, Request request int requestTimeout = AsyncHttpProviderUtils.requestTimeout(config, request); - urlConnection.setConnectTimeout(config.getConnectionTimeout()); + urlConnection.setConnectTimeout(config.getConnectTimeout()); if (requestTimeout != -1) urlConnection.setReadTimeout(requestTimeout); diff --git a/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java b/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java index 88b6b6f694..f3402ac935 100644 --- a/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java +++ b/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java @@ -179,8 +179,8 @@ public boolean remove(Object o) { DefaultChannelFuture.setUseDeadLockChecker(nettyConfig.isUseDeadLockChecker()); // FIXME isn't there a constant for this name??? - if (config.getConnectionTimeout() > 0) - nettyConfig.addProperty("connectTimeoutMillis", config.getConnectionTimeout()); + if (config.getConnectTimeout() > 0) + nettyConfig.addProperty("connectTimeoutMillis", config.getConnectTimeout()); for (Entry entry : nettyConfig.propertiesSet()) { String key = entry.getKey(); Object value = entry.getValue(); 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 d6a7174a2d..7f7291b302 100644 --- a/src/test/java/com/ning/http/client/async/AuthTimeoutTest.java +++ b/src/test/java/com/ning/http/client/async/AuthTimeoutTest.java @@ -125,7 +125,7 @@ public void handle(String s, Request r, HttpServletRequest request, HttpServletR @Test(groups = { "standalone", "default_provider" }, enabled = false) public void basicAuthTimeoutTest() throws Exception { setUpServer(Constraint.__BASIC_AUTH); - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setPooledConnectionIdleTimeout(2000).setConnectionTimeout(20000).setRequestTimeout(2000).build()); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setPooledConnectionIdleTimeout(2000).setConnectTimeout(20000).setRequestTimeout(2000).build()); try { Future f = execute(client, false); @@ -143,7 +143,7 @@ public void basicAuthTimeoutTest() throws Exception { @Test(groups = { "standalone", "default_provider" }, enabled = false) public void basicPreemptiveAuthTimeoutTest() throws Exception { setUpServer(Constraint.__BASIC_AUTH); - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setPooledConnectionIdleTimeout(2000).setConnectionTimeout(20000).setRequestTimeout(2000).build()); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setPooledConnectionIdleTimeout(2000).setConnectTimeout(20000).setRequestTimeout(2000).build()); try { Future f = execute(client, true); @@ -161,7 +161,7 @@ public void basicPreemptiveAuthTimeoutTest() throws Exception { @Test(groups = { "standalone", "default_provider" }, enabled = false) public void digestAuthTimeoutTest() throws Exception { setUpServer(Constraint.__DIGEST_AUTH); - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setPooledConnectionIdleTimeout(2000).setConnectionTimeout(20000).setRequestTimeout(2000).build()); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setPooledConnectionIdleTimeout(2000).setConnectTimeout(20000).setRequestTimeout(2000).build()); try { Future f = execute(client, false); @@ -179,7 +179,7 @@ public void digestAuthTimeoutTest() throws Exception { @Test(groups = { "standalone", "default_provider" }, enabled = false) public void digestPreemptiveAuthTimeoutTest() throws Exception { setUpServer(Constraint.__DIGEST_AUTH); - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setPooledConnectionIdleTimeout(2000).setConnectionTimeout(20000).setRequestTimeout(2000).build()); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setPooledConnectionIdleTimeout(2000).setConnectTimeout(20000).setRequestTimeout(2000).build()); try { Future f = execute(client, true); @@ -195,7 +195,7 @@ public void digestPreemptiveAuthTimeoutTest() throws Exception { @Test(groups = { "standalone", "default_provider" }, enabled = false) public void basicFutureAuthTimeoutTest() throws Exception { setUpServer(Constraint.__BASIC_AUTH); - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setPooledConnectionIdleTimeout(2000).setConnectionTimeout(20000).setRequestTimeout(2000).build()); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setPooledConnectionIdleTimeout(2000).setConnectTimeout(20000).setRequestTimeout(2000).build()); try { Future f = execute(client, false); @@ -211,7 +211,7 @@ public void basicFutureAuthTimeoutTest() throws Exception { @Test(groups = { "standalone", "default_provider" }, enabled = false) public void basicFuturePreemptiveAuthTimeoutTest() throws Exception { setUpServer(Constraint.__BASIC_AUTH); - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setPooledConnectionIdleTimeout(2000).setConnectionTimeout(20000).setRequestTimeout(2000).build()); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setPooledConnectionIdleTimeout(2000).setConnectTimeout(20000).setRequestTimeout(2000).build()); try { Future f = execute(client, true); @@ -227,7 +227,7 @@ public void basicFuturePreemptiveAuthTimeoutTest() throws Exception { @Test(groups = { "standalone", "default_provider" }, enabled = false) public void digestFutureAuthTimeoutTest() throws Exception { setUpServer(Constraint.__DIGEST_AUTH); - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setPooledConnectionIdleTimeout(2000).setConnectionTimeout(20000).setRequestTimeout(2000).build()); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setPooledConnectionIdleTimeout(2000).setConnectTimeout(20000).setRequestTimeout(2000).build()); try { Future f = execute(client, false); @@ -243,7 +243,7 @@ public void digestFutureAuthTimeoutTest() throws Exception { @Test(groups = { "standalone", "default_provider" }, enabled = false) public void digestFuturePreemptiveAuthTimeoutTest() throws Exception { setUpServer(Constraint.__DIGEST_AUTH); - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setPooledConnectionIdleTimeout(2000).setConnectionTimeout(20000).setRequestTimeout(2000).build()); + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setPooledConnectionIdleTimeout(2000).setConnectTimeout(20000).setRequestTimeout(2000).build()); try { Future f = execute(client, true); 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 07457fc589..2547981859 100644 --- a/src/test/java/com/ning/http/client/async/BodyChunkTest.java +++ b/src/test/java/com/ning/http/client/async/BodyChunkTest.java @@ -34,7 +34,7 @@ public abstract class BodyChunkTest extends AbstractBasicTest { @Test(groups = { "standalone", "default_provider" }) public void negativeContentTypeTest() throws Throwable { AsyncHttpClientConfig.Builder confbuilder = new AsyncHttpClientConfig.Builder(); - confbuilder = confbuilder.setConnectionTimeout(100); + confbuilder = confbuilder.setConnectTimeout(100); confbuilder = confbuilder.setMaxConnections(50); confbuilder = confbuilder.setRequestTimeout(5 * 60 * 1000); // 5 minutes 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 941feddf29..0f3ac0fd80 100644 --- a/src/test/java/com/ning/http/client/async/ChunkingTest.java +++ b/src/test/java/com/ning/http/client/async/ChunkingTest.java @@ -78,7 +78,7 @@ private void doTest(boolean customChunkedInputStream) throws Exception { .setAllowPoolingConnections(true)// .setMaxConnectionsPerHost(1)// .setMaxConnections(1)// - .setConnectionTimeout(1000)// + .setConnectTimeout(1000)// .setRequestTimeout(1000)// .setFollowRedirect(true); 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 781d841ce0..708f847295 100644 --- a/src/test/java/com/ning/http/client/async/ConnectionPoolTest.java +++ b/src/test/java/com/ning/http/client/async/ConnectionPoolTest.java @@ -134,7 +134,7 @@ public Response onCompleted(Response response) throws Exception { @Test(groups = { "standalone", "default_provider" }) public void multipleMaxConnectionOpenTest() throws Throwable { - AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setAllowPoolingConnections(true).setConnectionTimeout(5000).setMaxConnections(1).build(); + AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setAllowPoolingConnections(true).setConnectTimeout(5000).setMaxConnections(1).build(); AsyncHttpClient client = getAsyncHttpClient(cg); try { String body = "hello there"; @@ -162,7 +162,7 @@ public void multipleMaxConnectionOpenTest() throws Throwable { @Test(groups = { "standalone", "default_provider" }) public void multipleMaxConnectionOpenTestWithQuery() throws Throwable { - AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setAllowPoolingConnections(true).setConnectionTimeout(5000).setMaxConnections(1).build(); + AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setAllowPoolingConnections(true).setConnectTimeout(5000).setMaxConnections(1).build(); AsyncHttpClient client = getAsyncHttpClient(cg); try { String body = "hello there"; 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 3b131d8b03..ab4e34a1bc 100644 --- a/src/test/java/com/ning/http/client/async/MaxConnectionsInThreads.java +++ b/src/test/java/com/ning/http/client/async/MaxConnectionsInThreads.java @@ -48,7 +48,7 @@ public void testMaxConnectionsWithinThreads() { String[] urls = new String[] { servletEndpointUri.toString(), servletEndpointUri.toString() }; - final AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setConnectionTimeout(1000).setRequestTimeout(5000).setAllowPoolingConnections(true).setMaxConnections(1).setMaxConnectionsPerHost(1).build()); + final AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setConnectTimeout(1000).setRequestTimeout(5000).setAllowPoolingConnections(true).setMaxConnections(1).setMaxConnectionsPerHost(1).build()); try { final Boolean[] caughtError = new Boolean[] { Boolean.FALSE }; 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 73827900ab..51a937dbdd 100644 --- a/src/test/java/com/ning/http/client/async/MaxTotalConnectionTest.java +++ b/src/test/java/com/ning/http/client/async/MaxTotalConnectionTest.java @@ -37,7 +37,7 @@ public abstract class MaxTotalConnectionTest extends AbstractBasicTest { public void testMaxTotalConnectionsExceedingException() { String[] urls = new String[] { "http://google.com", "http://github.com/" }; - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setConnectionTimeout(1000) + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setConnectTimeout(1000) .setRequestTimeout(5000).setAllowPoolingConnections(false).setMaxConnections(1).setMaxConnectionsPerHost(1) .build()); @@ -62,7 +62,7 @@ public void testMaxTotalConnectionsExceedingException() { public void testMaxTotalConnections() throws IOException { String[] urls = new String[] { "http://google.com", "http://lenta.ru" }; - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setConnectionTimeout(1000) + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setConnectTimeout(1000) .setRequestTimeout(5000).setAllowPoolingConnections(false).setMaxConnections(2).setMaxConnectionsPerHost(1) .build()); try { @@ -83,7 +83,7 @@ public void testMaxTotalConnections() throws IOException { public void testMaxTotalConnectionsCorrectExceptionHandling() throws InterruptedException, ExecutionException { String[] urls = new String[] { "http://google.com", "http://github.com/" }; - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setConnectionTimeout(1000) + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setConnectTimeout(1000) .setRequestTimeout(5000).setAllowPoolingConnections(false).setMaxConnections(1).setMaxConnectionsPerHost(1) .build()); try { 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 cb224c0b44..62840ef0f9 100644 --- a/src/test/java/com/ning/http/client/async/NoNullResponseTest.java +++ b/src/test/java/com/ning/http/client/async/NoNullResponseTest.java @@ -54,7 +54,7 @@ public void multipleSslRequestsWithDelayAndKeepAlive() throws Throwable { } private AsyncHttpClient create() throws GeneralSecurityException { - final AsyncHttpClientConfig.Builder configBuilder = new AsyncHttpClientConfig.Builder().setFollowRedirect(true).setSSLContext(getSSLContext()).setAllowPoolingConnections(true).setConnectionTimeout(10000) + final AsyncHttpClientConfig.Builder configBuilder = new AsyncHttpClientConfig.Builder().setFollowRedirect(true).setSSLContext(getSSLContext()).setAllowPoolingConnections(true).setConnectTimeout(10000) .setPooledConnectionIdleTimeout(60000).setRequestTimeout(10000).setMaxConnectionsPerHost(-1).setMaxConnections(-1); return getAsyncHttpClient(configBuilder.build()); } 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 71d6516399..af0387ed93 100644 --- a/src/test/java/com/ning/http/client/async/PutLargeFileTest.java +++ b/src/test/java/com/ning/http/client/async/PutLargeFileTest.java @@ -44,7 +44,7 @@ public void testPutLargeFile() throws Exception { long repeats = (1024 * 1024 * 100 / bytes.length) + 1; largeFile = createTempFile(bytes, (int) repeats); int timeout = (int) (largeFile.length() / 1000); - AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder().setConnectionTimeout(timeout).build(); + AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder().setConnectTimeout(timeout).build(); AsyncHttpClient client = getAsyncHttpClient(config); try { BoundRequestBuilder rb = client.preparePut(getTargetUrl()); 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 4e692f9f5f..6cd5366bb5 100644 --- a/src/test/java/com/ning/http/client/async/RedirectConnectionUsageTest.java +++ b/src/test/java/com/ning/http/client/async/RedirectConnectionUsageTest.java @@ -107,7 +107,7 @@ public void testGetRedirectFinalUrl() { .setAllowPoolingConnections(true)// .setMaxConnectionsPerHost(1)// .setMaxConnections(1)// - .setConnectionTimeout(1000)// + .setConnectTimeout(1000)// .setRequestTimeout(1000)// .setFollowRedirect(true); 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 2aa93db35e..fb61f95954 100644 --- a/src/test/java/com/ning/http/client/async/RetryNonBlockingIssue.java +++ b/src/test/java/com/ning/http/client/async/RetryNonBlockingIssue.java @@ -130,7 +130,7 @@ public void testRetryNonBlocking() throws IOException, InterruptedException, AsyncHttpClientConfig.Builder bc = new AsyncHttpClientConfig.Builder()// .setAllowPoolingConnections(true)// .setMaxConnections(100)// - .setConnectionTimeout(60000)// + .setConnectTimeout(60000)// .setRequestTimeout(30000); AsyncHttpClient client = new AsyncHttpClient(bc.build()); @@ -164,7 +164,7 @@ public void testRetryNonBlockingAsyncConnect() throws IOException, InterruptedEx AsyncHttpClientConfig.Builder bc = new AsyncHttpClientConfig.Builder()// .setAllowPoolingConnections(true)// .setMaxConnections(100)// - .setConnectionTimeout(60000)// + .setConnectTimeout(60000)// .setRequestTimeout(30000); AsyncHttpClient client = new AsyncHttpClient(bc.build()); List> res = new ArrayList>(); @@ -197,7 +197,7 @@ public void testRetryBlocking() throws IOException, InterruptedException, AsyncHttpClientConfig.Builder bc = new AsyncHttpClientConfig.Builder()// .setAllowPoolingConnections(true)// .setMaxConnections(100)// - .setConnectionTimeout(30000)// + .setConnectTimeout(30000)// .setRequestTimeout(30000); AsyncHttpClient client = new AsyncHttpClient(bc.build()); List> res = new 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 7c57936768..3593da4c0d 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 @@ -65,7 +65,7 @@ public void testMaxTotalConnectionsException() { @Override @Test public void multipleMaxConnectionOpenTest() throws Throwable { - AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setAllowPoolingConnections(true).setConnectionTimeout(5000).setMaxConnections(1).build(); + AsyncHttpClientConfig cg = new AsyncHttpClientConfig.Builder().setAllowPoolingConnections(true).setConnectTimeout(5000).setMaxConnections(1).build(); AsyncHttpClient c = getAsyncHttpClient(cg); try { String body = "hello there"; diff --git a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyNoTransferEncodingTest.java b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyNoTransferEncodingTest.java index 70f8213673..9ebdc03939 100644 --- a/src/test/java/com/ning/http/client/async/grizzly/GrizzlyNoTransferEncodingTest.java +++ b/src/test/java/com/ning/http/client/async/grizzly/GrizzlyNoTransferEncodingTest.java @@ -86,7 +86,7 @@ public void testNoTransferEncoding() throws Exception { AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder() .setFollowRedirect(false) - .setConnectionTimeout(15000) + .setConnectTimeout(15000) .setRequestTimeout(15000) .setAllowPoolingConnections(false) .setDisableUrlEncodingForBoundedRequests(true) From c12022328994672ee2ae4200c540b986cb4bc20c Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 18 Sep 2014 10:41:57 +0200 Subject: [PATCH 602/701] append previous commit, see #704 --- .../java/com/ning/http/client/AsyncHttpClient.java | 2 +- .../ning/http/client/AsyncHttpClientConfigBean.java | 4 ++-- .../com/ning/http/client/SimpleAsyncHttpClient.java | 4 ++-- .../providers/netty/request/NettyRequestSender.java | 13 ++++++------- .../netty/request/timeout/ReadTimeoutTimerTask.java | 2 +- .../request/timeout/RequestTimeoutTimerTask.java | 2 +- 6 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/main/java/com/ning/http/client/AsyncHttpClient.java b/src/main/java/com/ning/http/client/AsyncHttpClient.java index f2d1f409bb..4724f5b4e7 100755 --- a/src/main/java/com/ning/http/client/AsyncHttpClient.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClient.java @@ -142,7 +142,7 @@ * Response r = f.get(); * *

      - * An instance of this class will cache every HTTP 1.1 connections and close them when the {@link AsyncHttpClientConfig#getIdleConnectionTimeout()} + * An instance of this class will cache every HTTP 1.1 connections and close them when the {@link AsyncHttpClientConfig#getReadTimeout()} * expires. This object can hold many persistent connections to different host. */ public class AsyncHttpClient implements Closeable { diff --git a/src/main/java/com/ning/http/client/AsyncHttpClientConfigBean.java b/src/main/java/com/ning/http/client/AsyncHttpClientConfigBean.java index ccf9a901c9..0942213640 100644 --- a/src/main/java/com/ning/http/client/AsyncHttpClientConfigBean.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClientConfigBean.java @@ -109,8 +109,8 @@ public AsyncHttpClientConfigBean setStrict302Handling(boolean strict302Handling) return this; } - public AsyncHttpClientConfigBean setIdleConnectionTimeout(int idleConnectionTimeout) { - this.readTimeout = idleConnectionTimeout; + public AsyncHttpClientConfigBean setReadTimeout(int readTimeout) { + this.readTimeout = readTimeout; return this; } diff --git a/src/main/java/com/ning/http/client/SimpleAsyncHttpClient.java b/src/main/java/com/ning/http/client/SimpleAsyncHttpClient.java index ee8f66ff3c..e911abb324 100644 --- a/src/main/java/com/ning/http/client/SimpleAsyncHttpClient.java +++ b/src/main/java/com/ning/http/client/SimpleAsyncHttpClient.java @@ -498,8 +498,8 @@ public Builder setMaximumConnectionsPerHost(int defaultMaxConnectionPerHost) { return this; } - public Builder setConnectionTimeout(int connectionTimeuot) { - configBuilder.setConnectTimeout(connectionTimeuot); + public Builder setConnectTimeout(int connectTimeout) { + configBuilder.setConnectTimeout(connectTimeout); return this; } diff --git a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java index 1867ef6c56..b5dabbadf0 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java @@ -375,13 +375,12 @@ private void scheduleTimeouts(NettyResponseFuture nettyResponseFuture) { timeoutsHolder.requestTimeout = requestTimeout; } - int readTimeout = config.getReadTimeout(); - if (readTimeout != -1 && readTimeout < requestTimeoutInMs) { - // no need for a idleConnectionTimeout that's less than the - // requestTimeoutInMs - Timeout idleConnectionTimeout = newTimeout(new ReadTimeoutTimerTask(nettyResponseFuture, this, timeoutsHolder, - requestTimeoutInMs, readTimeout), readTimeout); - timeoutsHolder.readTimeout = idleConnectionTimeout; + int readTimeoutValue = config.getReadTimeout(); + if (readTimeoutValue != -1 && readTimeoutValue < requestTimeoutInMs) { + // no need for a readTimeout that's less than the requestTimeout + Timeout readTimeout = newTimeout(new ReadTimeoutTimerTask(nettyResponseFuture, this, timeoutsHolder, + requestTimeoutInMs, readTimeoutValue), readTimeoutValue); + timeoutsHolder.readTimeout = readTimeout; } nettyResponseFuture.setTimeoutsHolder(timeoutsHolder); } diff --git a/src/main/java/com/ning/http/client/providers/netty/request/timeout/ReadTimeoutTimerTask.java b/src/main/java/com/ning/http/client/providers/netty/request/timeout/ReadTimeoutTimerTask.java index d314298921..9df2f906e3 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/timeout/ReadTimeoutTimerTask.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/timeout/ReadTimeoutTimerTask.java @@ -51,7 +51,7 @@ public void run(Timeout timeout) throws Exception { long durationBeforeCurrentReadTimeout = currentReadTimeoutInstant - now; if (durationBeforeCurrentReadTimeout <= 0L) { - // idleConnectionTimeout reached + // readTimeout reached String message = "Read timeout to " + remoteAddress + " of " + readTimeout + " ms"; long durationSinceLastTouch = now - nettyResponseFuture.getLastTouch(); expire(message, durationSinceLastTouch); diff --git a/src/main/java/com/ning/http/client/providers/netty/request/timeout/RequestTimeoutTimerTask.java b/src/main/java/com/ning/http/client/providers/netty/request/timeout/RequestTimeoutTimerTask.java index c7ea6490be..d57000296a 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/timeout/RequestTimeoutTimerTask.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/timeout/RequestTimeoutTimerTask.java @@ -37,7 +37,7 @@ public void run(Timeout timeout) throws Exception { if (done.getAndSet(true) || requestSender.isClosed()) return; - // in any case, cancel possible idleConnectionTimeout sibling + // in any case, cancel possible readTimeout sibling timeoutsHolder.cancel(); if (nettyResponseFuture.isDone()) From 1c9adeb21734cc7b251721a5097d34865b661c0e Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 18 Sep 2014 10:45:46 +0200 Subject: [PATCH 603/701] Remove NettyResponseFuture.hasExpired, close #705 --- .../netty/future/NettyResponseFuture.java | 27 ------------------- 1 file changed, 27 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/future/NettyResponseFuture.java b/src/main/java/com/ning/http/client/providers/netty/future/NettyResponseFuture.java index e4084e558e..7e299d153f 100755 --- a/src/main/java/com/ning/http/client/providers/netty/future/NettyResponseFuture.java +++ b/src/main/java/com/ning/http/client/providers/netty/future/NettyResponseFuture.java @@ -55,8 +55,6 @@ public enum STATE { NEW, POOLED, RECONNECTED, CLOSED, } - private volatile boolean requestTimeoutReached; - private volatile boolean idleConnectionTimeoutReached; private final long start = millisTime(); private final ConnectionPoolPartitioning connectionPoolPartitioning; private final ProxyServer proxyServer; @@ -265,31 +263,6 @@ public void setAsyncHandler(AsyncHandler asyncHandler) { this.asyncHandler = asyncHandler; } - /** - * Is the Future still valid - * - * @return true if response has expired and should be terminated. - */ - public boolean hasExpired() { - return requestTimeoutReached || idleConnectionTimeoutReached; - } - - public void setRequestTimeoutReached() { - this.requestTimeoutReached = true; - } - - public boolean isRequestTimeoutReached() { - return requestTimeoutReached; - } - - public void setIdleConnectionTimeoutReached() { - this.idleConnectionTimeoutReached = true; - } - - public boolean isIdleConnectionTimeoutReached() { - return idleConnectionTimeoutReached; - } - public void cancelTimeouts() { if (timeoutsHolder != null) { timeoutsHolder.cancel(); From 66ac5d57ee86cf66ede97fcb4a4e84bc6521a1fb Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 18 Sep 2014 10:59:35 +0200 Subject: [PATCH 604/701] Don't create a FilterContext when there's no RequestFilters, close #706 --- .../com/ning/http/client/AsyncHttpClient.java | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/ning/http/client/AsyncHttpClient.java b/src/main/java/com/ning/http/client/AsyncHttpClient.java index 4724f5b4e7..10957d03fe 100755 --- a/src/main/java/com/ning/http/client/AsyncHttpClient.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClient.java @@ -485,10 +485,15 @@ public BoundRequestBuilder prepareRequest(Request request) { @SuppressWarnings({ "rawtypes", "unchecked" }) public ListenableFuture executeRequest(Request request, AsyncHandler handler) throws IOException { - FilterContext fc = new FilterContext.FilterContextBuilder().asyncHandler(handler).request(request).build(); - fc = preProcessRequest(fc); - - return httpProvider.execute(fc.getRequest(), fc.getAsyncHandler()); + if (config.getRequestFilters().isEmpty()) { + return httpProvider.execute(request, handler); + + } else { + FilterContext fc = new FilterContext.FilterContextBuilder().asyncHandler(handler).request(request).build(); + fc = preProcessRequest(fc); + + return httpProvider.execute(fc.getRequest(), fc.getAsyncHandler()); + } } /** @@ -498,11 +503,8 @@ public ListenableFuture executeRequest(Request request, AsyncHandler h * @return a {@link Future} of type Response * @throws IOException */ - @SuppressWarnings({ "rawtypes", "unchecked" }) public ListenableFuture executeRequest(Request request) throws IOException { - FilterContext fc = new FilterContext.FilterContextBuilder().asyncHandler(new AsyncCompletionHandlerBase()).request(request).build(); - fc = preProcessRequest(fc); - return httpProvider.execute(fc.getRequest(), fc.getAsyncHandler()); + return executeRequest(request, new AsyncCompletionHandlerBase()); } /** From 21ee8613eb4d55518eae2a4f4797431a3d67b11e Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 18 Sep 2014 11:22:18 +0200 Subject: [PATCH 605/701] Cache the Too many connections exception #707 --- .../providers/netty/request/NettyRequestSender.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java index b5dabbadf0..7e80ecc040 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java @@ -69,6 +69,7 @@ public final class NettyRequestSender { private final Timer nettyTimer; private final AtomicBoolean closed; private final NettyRequestFactory requestFactory; + private final IOException tooManyConnections; public NettyRequestSender(AsyncHttpClientConfig config,// NettyAsyncHttpProviderConfig nettyConfig,// @@ -80,6 +81,11 @@ public NettyRequestSender(AsyncHttpClientConfig config,// this.nettyTimer = nettyTimer; this.closed = closed; requestFactory = new NettyRequestFactory(config, nettyConfig); + if (config.getMaxConnections() > 0) { + tooManyConnections = new IOException(String.format("Too many connections %s", config.getMaxConnections())); + tooManyConnections.setStackTrace(new StackTraceElement[] {}); + } else + tooManyConnections = null; } public ListenableFuture sendRequest(final Request request,// @@ -495,13 +501,12 @@ public boolean preemptChannel(AsyncHandler asyncHandler, String poolKey) thro if (channelManager.preemptChannel(poolKey)) { channelPreempted = true; } else { - IOException ex = new IOException(String.format("Too many connections %s", config.getMaxConnections())); try { - asyncHandler.onThrowable(ex); + asyncHandler.onThrowable(tooManyConnections); } catch (Exception e) { LOGGER.warn("asyncHandler.onThrowable crashed", e); } - throw ex; + throw tooManyConnections; } return channelPreempted; } From 7987b1b658bc3116078d555eaf361ca6bf82b5e4 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 18 Sep 2014 11:25:31 +0200 Subject: [PATCH 606/701] comments --- .../http/client/providers/netty/channel/ChannelManager.java | 2 +- .../http/client/providers/netty/handler/HttpProtocol.java | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java b/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java index f3402ac935..b36c67ba91 100644 --- a/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java +++ b/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java @@ -427,7 +427,7 @@ public final Callback newDrainCallback(final NettyResponseFuture future, fina return new Callback(future) { @Override - public void call() throws Exception { + public void call() { tryToOfferChannelToPool(channel, keepAlive, poolKey); } }; diff --git a/src/main/java/com/ning/http/client/providers/netty/handler/HttpProtocol.java b/src/main/java/com/ning/http/client/providers/netty/handler/HttpProtocol.java index cd53676a99..cf443dd686 100644 --- a/src/main/java/com/ning/http/client/providers/netty/handler/HttpProtocol.java +++ b/src/main/java/com/ning/http/client/providers/netty/handler/HttpProtocol.java @@ -243,7 +243,7 @@ private boolean exitAfterHandling401(// logger.debug("Sending authentication to {}", request.getUri()); Callback callback = new Callback(future) { - public void call() throws Exception { + public void call() throws IOException { channelManager.drainChannel(channel, future); requestSender.sendNextRequest(nextRequest, future); } @@ -254,6 +254,7 @@ public void call() throws Exception { // before executing the next request. Channels.setAttribute(channel, callback); else + // call might crash with an IOException callback.call(); return true; @@ -470,6 +471,7 @@ public void handle(final Channel channel, final NettyResponseFuture future, f handleChunk((HttpChunk) e, channel, future, handler); } catch (Exception t) { + // e.g. an IOException when trying to open a connection and send the next request if (hasIOExceptionFilters// && t instanceof IOException// && requestSender.applyIoExceptionFiltersAndReplayRequest(future, IOException.class.cast(t), channel)) { From 89402e03b1045b63fa46aabf4cc20814c79d7a15 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 18 Sep 2014 11:42:16 +0200 Subject: [PATCH 607/701] comment --- .../client/providers/netty/request/NettyRequestSender.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java index 7e80ecc040..ae4baf78a7 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java @@ -214,8 +214,11 @@ private ListenableFuture sendRequestWithCachedChannel(Request request, Ur try { writeRequest(future, channel); } catch (Exception ex) { + // write request isn't supposed to throw Exceptions LOGGER.debug("writeRequest failure", ex); if (ex.getMessage() != null && ex.getMessage().contains("SSLEngine")) { + // FIXME what is this for? https://github.com/AsyncHttpClient/async-http-client/commit/a847c3d4523ccc09827743e15b17e6bab59c553b + // can such an exception happen as we write async? LOGGER.debug("SSLEngine failure", ex); future = null; } else { From 61d55925bec0414b4eb16e399e26d922720de0b1 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 18 Sep 2014 12:23:19 +0200 Subject: [PATCH 608/701] Make Realm and ProxyServer encoding Charsets instead of Strings, close #708 --- .../com/ning/http/client/ProxyServer.java | 11 +++---- src/main/java/com/ning/http/client/Realm.java | 30 ++++++++++--------- .../http/client/SimpleAsyncHttpClient.java | 5 ++-- .../grizzly/GrizzlyAsyncHttpProvider.java | 7 +---- .../ning/http/util/AuthenticatorUtils.java | 9 +++--- .../java/com/ning/http/client/RealmTest.java | 4 +-- 6 files changed, 32 insertions(+), 34 deletions(-) diff --git a/src/main/java/com/ning/http/client/ProxyServer.java b/src/main/java/com/ning/http/client/ProxyServer.java index 79008ade9d..30a5594dac 100644 --- a/src/main/java/com/ning/http/client/ProxyServer.java +++ b/src/main/java/com/ning/http/client/ProxyServer.java @@ -18,6 +18,7 @@ import static java.nio.charset.StandardCharsets.UTF_8; +import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -53,7 +54,7 @@ public String toString() { private final String password; private final int port; private final String url; - private String encoding = UTF_8.name(); + private Charset charset = 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) { @@ -101,13 +102,13 @@ public String getPassword() { return password; } - public ProxyServer setEncoding(String encoding) { - this.encoding = encoding; + public ProxyServer setCharset(Charset charset) { + this.charset = charset; return this; } - public String getEncoding() { - return encoding; + public Charset getCharset() { + return charset; } public ProxyServer addNonProxyHost(String uri) { diff --git a/src/main/java/com/ning/http/client/Realm.java b/src/main/java/com/ning/http/client/Realm.java index 7fa03b5ad7..a072d78f1b 100644 --- a/src/main/java/com/ning/http/client/Realm.java +++ b/src/main/java/com/ning/http/client/Realm.java @@ -16,12 +16,14 @@ */ package com.ning.http.client; -import static java.nio.charset.StandardCharsets.*; - import static com.ning.http.util.MiscUtils.isNonEmpty; +import static java.nio.charset.StandardCharsets.ISO_8859_1; +import static java.nio.charset.StandardCharsets.UTF_8; import com.ning.http.client.uri.Uri; + import java.io.UnsupportedEncodingException; +import java.nio.charset.Charset; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; @@ -46,7 +48,7 @@ public class Realm { private final Uri uri; private final String methodName; private final boolean usePreemptiveAuth; - private final String enc; + private final Charset charset; private final String host; private final boolean messageType2Received; private final boolean useAbsoluteURI; @@ -78,7 +80,7 @@ private Realm(AuthScheme scheme, String method, boolean usePreemptiveAuth, String ntlmDomain, - String enc, + Charset charset, String host, boolean messageType2Received, String opaque, @@ -101,7 +103,7 @@ private Realm(AuthScheme scheme, this.methodName = method; this.usePreemptiveAuth = usePreemptiveAuth; this.ntlmDomain = ntlmDomain; - this.enc = enc; + this.charset = charset; this.host = host; this.messageType2Received = messageType2Received; this.useAbsoluteURI = useAbsoluteURI; @@ -162,8 +164,8 @@ public Uri getUri() { return uri; } - public String getEncoding() { - return enc; + public Charset getCharset() { + return charset; } public String getMethodName() { @@ -298,7 +300,7 @@ public static class RealmBuilder { private String methodName = "GET"; private boolean usePreemptive = false; private String ntlmDomain = System.getProperty("http.auth.ntlm.domain", ""); - private String enc = UTF_8.name(); + private Charset charset = UTF_8; private String host = "localhost"; private boolean messageType2Received = false; private boolean useAbsoluteURI = true; @@ -512,7 +514,7 @@ public RealmBuilder clone(Realm clone) { setNonce(clone.getNonce()); setPassword(clone.getPassword()); setPrincipal(clone.getPrincipal()); - setEnconding(clone.getEncoding()); + setCharset(clone.getCharset()); setOpaque(clone.getOpaque()); setQop(clone.getQop()); setScheme(clone.getScheme()); @@ -556,12 +558,12 @@ private String match(String headerLine, String token) { return value.startsWith("\"") ? value.substring(1) : value; } - public String getEncoding() { - return enc; + public Charset getCharset() { + return charset; } - public RealmBuilder setEnconding(String enc) { - this.enc = enc; + public RealmBuilder setCharset(Charset charset) { + this.charset = charset; return this; } @@ -672,7 +674,7 @@ public Realm build() { methodName, usePreemptive, ntlmDomain, - enc, + charset, host, messageType2Received, opaque, diff --git a/src/main/java/com/ning/http/client/SimpleAsyncHttpClient.java b/src/main/java/com/ning/http/client/SimpleAsyncHttpClient.java index e911abb324..0f06ef15a1 100644 --- a/src/main/java/com/ning/http/client/SimpleAsyncHttpClient.java +++ b/src/main/java/com/ning/http/client/SimpleAsyncHttpClient.java @@ -25,6 +25,7 @@ import javax.net.ssl.SSLContext; import java.io.IOException; +import java.nio.charset.Charset; import java.util.Collection; import java.util.List; import java.util.Map; @@ -573,8 +574,8 @@ public Builder setRealmUsePreemptiveAuth(boolean usePreemptiveAuth) { return this; } - public Builder setRealmEnconding(String enc) { - realm().setEnconding(enc); + public Builder setRealmCharset(Charset charset) { + realm().setCharset(charset); return this; } 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 8d53d978c0..babe950e3a 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,7 +129,6 @@ import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; -import java.io.UnsupportedEncodingException; import java.net.InetSocketAddress; import java.net.URI; import java.net.URISyntaxException; @@ -1586,11 +1585,7 @@ public boolean handleStatus(final HttpResponsePacket responsePacket, 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) { - } + req.getHeaders().add(Header.Authorization.toString(), AuthenticatorUtils.computeBasicAuthentication(realm)); } else if (lowerCaseAuth.startsWith("digest")) { req.getHeaders().remove(Header.Authorization.toString()); try { diff --git a/src/main/java/com/ning/http/util/AuthenticatorUtils.java b/src/main/java/com/ning/http/util/AuthenticatorUtils.java index bdc8de9991..23233e0941 100644 --- a/src/main/java/com/ning/http/util/AuthenticatorUtils.java +++ b/src/main/java/com/ning/http/util/AuthenticatorUtils.java @@ -20,19 +20,18 @@ import com.ning.http.client.Realm; import com.ning.http.client.uri.Uri; -import java.io.UnsupportedEncodingException; import java.security.NoSuchAlgorithmException; public final class AuthenticatorUtils { - public static String computeBasicAuthentication(Realm realm) throws UnsupportedEncodingException { + public static String computeBasicAuthentication(Realm realm) { String s = realm.getPrincipal() + ":" + realm.getPassword(); - return "Basic " + Base64.encode(s.getBytes(realm.getEncoding())); + return "Basic " + Base64.encode(s.getBytes(realm.getCharset())); } - public static String computeBasicAuthentication(ProxyServer proxyServer) throws UnsupportedEncodingException { + public static String computeBasicAuthentication(ProxyServer proxyServer) { String s = proxyServer.getPrincipal() + ":" + proxyServer.getPassword(); - return "Basic " + Base64.encode(s.getBytes(proxyServer.getEncoding())); + return "Basic " + Base64.encode(s.getBytes(proxyServer.getCharset())); } private static String computeRealmURI(Realm realm) { diff --git a/src/test/java/com/ning/http/client/RealmTest.java b/src/test/java/com/ning/http/client/RealmTest.java index 308da145c0..0243fad878 100644 --- a/src/test/java/com/ning/http/client/RealmTest.java +++ b/src/test/java/com/ning/http/client/RealmTest.java @@ -30,7 +30,7 @@ public class RealmTest { public void testClone() { RealmBuilder builder = new RealmBuilder(); builder.setPrincipal("user").setPassword("pass"); - builder.setEnconding("enc").setUsePreemptiveAuth(true); + builder.setCharset(UTF_16).setUsePreemptiveAuth(true); builder.setRealmName("realm").setAlgorithm("algo"); builder.setScheme(AuthScheme.BASIC); Realm orig = builder.build(); @@ -38,7 +38,7 @@ public void testClone() { Realm clone = new RealmBuilder().clone(orig).build(); Assert.assertEquals(clone.getPrincipal(), orig.getPrincipal()); Assert.assertEquals(clone.getPassword(), orig.getPassword()); - Assert.assertEquals(clone.getEncoding(), orig.getEncoding()); + Assert.assertEquals(clone.getCharset(), orig.getCharset()); Assert.assertEquals(clone.getUsePreemptiveAuth(), orig.getUsePreemptiveAuth()); Assert.assertEquals(clone.getRealmName(), orig.getRealmName()); Assert.assertEquals(clone.getAlgorithm(), orig.getAlgorithm()); From 9c569f705da308e3da8c90d68dfb83202f4aeb6f Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 18 Sep 2014 16:50:35 +0200 Subject: [PATCH 609/701] minor clean up --- .../grizzly/GrizzlyAsyncHttpProvider.java | 9 ++------- .../providers/jdk/JDKAsyncHttpProvider.java | 8 ++------ .../netty/request/NettyRequestFactory.java | 10 ++-------- .../ning/http/util/AuthenticatorUtils.java | 19 +++++++++++-------- 4 files changed, 17 insertions(+), 29 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 babe950e3a..12dd129513 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 @@ -133,7 +133,6 @@ import java.net.URI; import java.net.URISyntaxException; import java.net.URLEncoder; -import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.util.Collection; import java.util.HashMap; @@ -1588,12 +1587,8 @@ public boolean handleStatus(final HttpResponsePacket responsePacket, req.getHeaders().add(Header.Authorization.toString(), AuthenticatorUtils.computeBasicAuthentication(realm)); } else if (lowerCaseAuth.startsWith("digest")) { req.getHeaders().remove(Header.Authorization.toString()); - try { - req.getHeaders().add(Header.Authorization.toString(), - AuthenticatorUtils.computeDigestAuthentication(realm)); - } catch (NoSuchAlgorithmException e) { - throw new IllegalStateException("Digest authentication not supported", e); - } + req.getHeaders().add(Header.Authorization.toString(), + AuthenticatorUtils.computeDigestAuthentication(realm)); } else { throw new IllegalStateException("Unsupported authorization method: " + auth); } 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 533c6464fa..283a97df6e 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 @@ -493,12 +493,8 @@ private void configure(Uri uri, HttpURLConnection urlConnection, Request request break; case DIGEST: if (isNonEmpty(realm.getNonce())) { - try { - urlConnection.setRequestProperty("Authorization", - AuthenticatorUtils.computeDigestAuthentication(realm)); - } catch (NoSuchAlgorithmException e) { - throw new SecurityException(e); - } + urlConnection.setRequestProperty("Authorization", + AuthenticatorUtils.computeDigestAuthentication(realm)); } break; case NTLM: diff --git a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestFactory.java b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestFactory.java index 900f8cdc3e..dbfdc15300 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestFactory.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestFactory.java @@ -56,7 +56,6 @@ import java.io.IOException; import java.nio.charset.Charset; -import java.security.NoSuchAlgorithmException; import java.util.List; import java.util.Map.Entry; @@ -104,13 +103,8 @@ private String authorizationHeader(Request request, Uri uri, ProxyServer proxySe authorizationHeader = computeBasicAuthentication(realm); break; case DIGEST: - if (isNonEmpty(realm.getNonce())) { - try { - authorizationHeader = computeDigestAuthentication(realm); - } catch (NoSuchAlgorithmException e) { - throw new SecurityException(e); - } - } + if (isNonEmpty(realm.getNonce())) + authorizationHeader = computeDigestAuthentication(realm); break; case NTLM: String domain; diff --git a/src/main/java/com/ning/http/util/AuthenticatorUtils.java b/src/main/java/com/ning/http/util/AuthenticatorUtils.java index 23233e0941..f2c32381de 100644 --- a/src/main/java/com/ning/http/util/AuthenticatorUtils.java +++ b/src/main/java/com/ning/http/util/AuthenticatorUtils.java @@ -12,28 +12,31 @@ */ package com.ning.http.util; -import static java.nio.charset.StandardCharsets.*; import static com.ning.http.util.AsyncHttpProviderUtils.getNonEmptyPath; import static com.ning.http.util.MiscUtils.isNonEmpty; +import static java.nio.charset.StandardCharsets.ISO_8859_1; import com.ning.http.client.ProxyServer; import com.ning.http.client.Realm; import com.ning.http.client.uri.Uri; -import java.security.NoSuchAlgorithmException; +import java.nio.charset.Charset; public final class AuthenticatorUtils { public static String computeBasicAuthentication(Realm realm) { - String s = realm.getPrincipal() + ":" + realm.getPassword(); - return "Basic " + Base64.encode(s.getBytes(realm.getCharset())); + return computeBasicAuthentication(realm.getPrincipal(), realm.getPassword(), realm.getCharset()); } public static String computeBasicAuthentication(ProxyServer proxyServer) { - String s = proxyServer.getPrincipal() + ":" + proxyServer.getPassword(); - return "Basic " + Base64.encode(s.getBytes(proxyServer.getCharset())); + return computeBasicAuthentication(proxyServer.getPrincipal(), proxyServer.getPassword(), proxyServer.getCharset()); } - + + private static String computeBasicAuthentication(String principal, String password, Charset charset) { + String s = principal + ":" + password; + return "Basic " + Base64.encode(s.getBytes(charset)); + } + private static String computeRealmURI(Realm realm) { Uri uri = realm.getUri(); if (realm.isTargetProxy()) { @@ -48,7 +51,7 @@ private static String computeRealmURI(Realm realm) { } } - public static String computeDigestAuthentication(Realm realm) throws NoSuchAlgorithmException { + public static String computeDigestAuthentication(Realm realm) { StringBuilder builder = new StringBuilder().append("Digest "); append(builder, "username", realm.getPrincipal(), true); From 299c11227ce7923b29a2aaf59eb23984cd14bf40 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 18 Sep 2014 18:30:06 +0200 Subject: [PATCH 610/701] Nofity of "real" request in AsyncHandlerExtensions.onSendRequest, close #709 --- .../java/com/ning/http/client/AsyncHandlerExtensions.java | 4 +++- .../client/providers/grizzly/GrizzlyAsyncHttpProvider.java | 4 ---- .../client/providers/netty/request/NettyRequestSender.java | 2 +- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/ning/http/client/AsyncHandlerExtensions.java b/src/main/java/com/ning/http/client/AsyncHandlerExtensions.java index f4d06f3316..bcfe4cd171 100644 --- a/src/main/java/com/ning/http/client/AsyncHandlerExtensions.java +++ b/src/main/java/com/ning/http/client/AsyncHandlerExtensions.java @@ -50,8 +50,10 @@ public interface AsyncHandlerExtensions { * Notify the callback when a request is about to be written on the wire. * If the original request causes multiple requests to be sent, for example, because of authorization or retry, * it will be notified multiple times. + * + * @param request the real request object (underlying provider model) */ - void onSendRequest(); + void onSendRequest(Object request); /** * Notify the callback every time a request is being retried. 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 12dd129513..fc4a9c781a 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 @@ -82,7 +82,6 @@ import org.slf4j.LoggerFactory; import com.ning.http.client.AsyncHandler; -import com.ning.http.client.AsyncHandlerExtensions; import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.AsyncHttpProvider; @@ -1171,9 +1170,6 @@ protected void onHttpHeadersEncoded(HttpHeader httpHeader, FilterChainContext ct if (handler instanceof TransferCompletionHandler) { ((TransferCompletionHandler) handler).onHeaderWriteCompleted(); } - if (handler instanceof AsyncHandlerExtensions) { - ((AsyncHandlerExtensions) handler).onSendRequest(); - } } @Override diff --git a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java index ae4baf78a7..fa14bc1847 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java @@ -319,7 +319,7 @@ public void writeRequest(NettyResponseFuture future, Channel channel) { if (!future.isHeadersAlreadyWrittenOnContinue()) { try { if (future.getAsyncHandler() instanceof AsyncHandlerExtensions) - AsyncHandlerExtensions.class.cast(future.getAsyncHandler()).onSendRequest(); + AsyncHandlerExtensions.class.cast(future.getAsyncHandler()).onSendRequest(nettyRequest); channel.write(httpRequest).addListener(new ProgressListener(config, future.getAsyncHandler(), future, true)); } catch (Throwable cause) { // FIXME why not notify? From 5da78ecf97a8eb4f1de77fd97c46b9bc3650e913 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 18 Sep 2014 21:13:03 +0200 Subject: [PATCH 611/701] Too many connections shouldn't be thrown by execute, close #703 --- .../netty/request/NettyRequestSender.java | 40 ++++++------------- 1 file changed, 13 insertions(+), 27 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java index fa14bc1847..7db6da03a6 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java @@ -252,20 +252,22 @@ private ListenableFuture sendRequestWithNewChannel(// ClientBootstrap bootstrap = channelManager.getBootstrap(request.getUri().getScheme(), useProxy, useSSl); boolean channelPreempted = false; - String poolKey = null; - - // Do not throw an exception when we need an extra connection for a redirect. - if (!reclaimCache) { - // only compute when maxConnectionPerHost is enabled - // FIXME clean up - if (config.getMaxConnectionsPerHost() > 0) - poolKey = channelManager.getPartitionId(future); + String poolKey = null; + try { + // Do not throw an exception when we need an extra connection for a redirect. + if (!reclaimCache) { + // only compute when maxConnectionPerHost is enabled + // FIXME clean up + if (config.getMaxConnectionsPerHost() > 0) + poolKey = channelManager.getPartitionId(future); - channelPreempted = preemptChannel(asyncHandler, poolKey); - } + if (!channelManager.preemptChannel(poolKey)) + throw tooManyConnections; - try { + channelPreempted = true; + } + if (asyncHandler instanceof AsyncHandlerExtensions) AsyncHandlerExtensions.class.cast(asyncHandler).onOpenConnection(); @@ -498,22 +500,6 @@ public Channel pollAndVerifyCachedChannel(Uri uri, ProxyServer proxy, Connection return channel; } - public boolean preemptChannel(AsyncHandler asyncHandler, String poolKey) throws IOException { - - boolean channelPreempted = false; - if (channelManager.preemptChannel(poolKey)) { - channelPreempted = true; - } else { - try { - asyncHandler.onThrowable(tooManyConnections); - } catch (Exception e) { - LOGGER.warn("asyncHandler.onThrowable crashed", e); - } - throw tooManyConnections; - } - return channelPreempted; - } - @SuppressWarnings({ "rawtypes", "unchecked" }) public void replayRequest(final NettyResponseFuture future, FilterContext fc, Channel channel) throws IOException { From d1dff59b6b50252944ac0112467aef57abb994d4 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 18 Sep 2014 21:16:13 +0200 Subject: [PATCH 612/701] format --- .../client/providers/netty/request/NettyRequestSender.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java index 7db6da03a6..c03a117483 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java @@ -252,8 +252,8 @@ private ListenableFuture sendRequestWithNewChannel(// ClientBootstrap bootstrap = channelManager.getBootstrap(request.getUri().getScheme(), useProxy, useSSl); boolean channelPreempted = false; - String poolKey = null; + try { // Do not throw an exception when we need an extra connection for a redirect. if (!reclaimCache) { @@ -267,7 +267,7 @@ private ListenableFuture sendRequestWithNewChannel(// channelPreempted = true; } - + if (asyncHandler instanceof AsyncHandlerExtensions) AsyncHandlerExtensions.class.cast(asyncHandler).onOpenConnection(); From 1ad8a35dfe7ab4c18b0d9d9262f2786d58f3394f Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 18 Sep 2014 21:42:41 +0200 Subject: [PATCH 613/701] Always create tooManyConnections --- .../client/providers/netty/request/NettyRequestSender.java | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java index c03a117483..3a5d1c93e8 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java @@ -81,11 +81,8 @@ public NettyRequestSender(AsyncHttpClientConfig config,// this.nettyTimer = nettyTimer; this.closed = closed; requestFactory = new NettyRequestFactory(config, nettyConfig); - if (config.getMaxConnections() > 0) { - tooManyConnections = new IOException(String.format("Too many connections %s", config.getMaxConnections())); - tooManyConnections.setStackTrace(new StackTraceElement[] {}); - } else - tooManyConnections = null; + tooManyConnections = new IOException(String.format("Too many connections %s", config.getMaxConnections())); + tooManyConnections.setStackTrace(new StackTraceElement[] {}); } public ListenableFuture sendRequest(final Request request,// From 0c683d4964cf9b9203dd619cbf2dfbfc38e2511d Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 18 Sep 2014 21:44:39 +0200 Subject: [PATCH 614/701] Fix ConnectionPool tests --- .../http/client/async/ConnectionPoolTest.java | 31 +++++++++++-------- .../async/netty/NettyConnectionPoolTest.java | 3 +- 2 files changed, 20 insertions(+), 14 deletions(-) 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 708f847295..6890ab42d0 100644 --- a/src/test/java/com/ning/http/client/async/ConnectionPoolTest.java +++ b/src/test/java/com/ning/http/client/async/ConnectionPoolTest.java @@ -21,6 +21,8 @@ import static org.testng.Assert.fail; import java.io.IOException; +import java.util.ArrayList; +import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CountDownLatch; @@ -37,6 +39,7 @@ import com.ning.http.client.AsyncCompletionHandlerBase; import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClientConfig; +import com.ning.http.client.ListenableFuture; import com.ning.http.client.Response; public abstract class ConnectionPoolTest extends AbstractBasicTest { @@ -65,29 +68,30 @@ public void testMaxTotalConnections() { } @Test(groups = { "standalone", "default_provider" }) - public void testMaxTotalConnectionsException() { + public void testMaxTotalConnectionsException() throws IOException { AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setAllowPoolingConnections(true).setMaxConnections(1).build()); try { String url = getTargetUrl(); - int i; + + List> futures = new ArrayList<>(); + for (int i = 0; i < 5; i++) { + log.info("{} requesting url [{}]...", i, url); + futures.add(client.prepareGet(url).execute()); + } + Exception exception = null; - for (i = 0; i < 20; i++) { + for (ListenableFuture future : futures) { try { - log.info("{} requesting url [{}]...", i, url); - - if (i < 5) { - client.prepareGet(url).execute().get(); - } else { - client.prepareGet(url).execute(); - } + future.get(); } catch (Exception ex) { exception = ex; break; } } + assertNotNull(exception); - assertNotNull(exception.getMessage()); - assertEquals(exception.getMessage(), "Too many connections 1"); + assertNotNull(exception.getCause()); + assertEquals(exception.getCause().getMessage(), "Too many connections 1"); } finally { client.close(); } @@ -154,7 +158,8 @@ public void multipleMaxConnectionOpenTest() throws Throwable { exception = ex; } assertNotNull(exception); - assertEquals(exception.getMessage(), "Too many connections 1"); + assertNotNull(exception.getCause()); + assertEquals(exception.getCause().getMessage(), "Too many connections 1"); } finally { client.close(); } diff --git a/src/test/java/com/ning/http/client/async/netty/NettyConnectionPoolTest.java b/src/test/java/com/ning/http/client/async/netty/NettyConnectionPoolTest.java index a470cbf2bd..1039335e4f 100644 --- a/src/test/java/com/ning/http/client/async/netty/NettyConnectionPoolTest.java +++ b/src/test/java/com/ning/http/client/async/netty/NettyConnectionPoolTest.java @@ -68,7 +68,8 @@ public boolean isOpen() { exception = ex; } assertNotNull(exception); - assertEquals(exception.getMessage(), "Too many connections -1"); + assertNotNull(exception.getCause()); + assertEquals(exception.getCause().getMessage(), "Too many connections -1"); } finally { client.close(); } From f5fe4aa110f825d783f79f459beae2dab4f421db Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 18 Sep 2014 21:55:37 +0200 Subject: [PATCH 615/701] Fix test --- .../client/providers/netty/handler/Processor.java | 5 ++--- .../ning/http/util/AsyncHttpProviderUtils.java | 6 ++++++ .../ning/http/client/async/RetryRequestTest.java | 15 ++++++++++----- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/handler/Processor.java b/src/main/java/com/ning/http/client/providers/netty/handler/Processor.java index ece8b293d9..ff02910d6f 100644 --- a/src/main/java/com/ning/http/client/providers/netty/handler/Processor.java +++ b/src/main/java/com/ning/http/client/providers/netty/handler/Processor.java @@ -32,6 +32,7 @@ import com.ning.http.client.providers.netty.future.NettyResponseFuture; import com.ning.http.client.providers.netty.future.StackTraceInspector; import com.ning.http.client.providers.netty.request.NettyRequestSender; +import com.ning.http.util.AsyncHttpProviderUtils; import java.io.IOException; import java.nio.channels.ClosedChannelException; @@ -40,10 +41,8 @@ public class Processor extends SimpleChannelUpstreamHandler { private static final Logger LOGGER = LoggerFactory.getLogger(Processor.class); - public static final IOException REMOTELY_CLOSED_EXCEPTION = new IOException("Remotely closed"); public static final IOException CHANNEL_CLOSED_EXCEPTION = new IOException("Channel closed"); static { - REMOTELY_CLOSED_EXCEPTION.setStackTrace(new StackTraceElement[0]); CHANNEL_CLOSED_EXCEPTION.setStackTrace(new StackTraceElement[0]); } @@ -134,7 +133,7 @@ public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws channelManager.closeChannel(channel); else if (!requestSender.retry(future)) - requestSender.abort(channel, future, REMOTELY_CLOSED_EXCEPTION); + requestSender.abort(channel, future, AsyncHttpProviderUtils.REMOTELY_CLOSED_EXCEPTION); } } diff --git a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java index 4bf281c9b4..a0e8206466 100644 --- a/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java +++ b/src/main/java/com/ning/http/util/AsyncHttpProviderUtils.java @@ -36,6 +36,12 @@ */ public class AsyncHttpProviderUtils { + public static final IOException REMOTELY_CLOSED_EXCEPTION = new IOException("Remotely closed"); + + static { + REMOTELY_CLOSED_EXCEPTION.setStackTrace(new StackTraceElement[] {}); + } + public final static Charset DEFAULT_CHARSET = ISO_8859_1; static final byte[] EMPTY_BYTE_ARRAY = "".getBytes(); 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 f1c870d74b..7dd050516d 100644 --- a/src/test/java/com/ning/http/client/async/RetryRequestTest.java +++ b/src/test/java/com/ning/http/client/async/RetryRequestTest.java @@ -12,20 +12,25 @@ */ package com.ning.http.client.async; -import com.ning.http.client.AsyncHttpClient; -import com.ning.http.client.AsyncHttpClientConfig; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNotNull; +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.AsyncHttpClient; +import com.ning.http.client.AsyncHttpClientConfig; +import com.ning.http.util.AsyncHttpProviderUtils; + import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; + import java.io.IOException; import java.io.OutputStream; -import static org.testng.Assert.*; - public abstract class RetryRequestTest extends AbstractBasicTest { public static class SlowAndBigHandler extends AbstractHandler { @@ -76,7 +81,7 @@ public void testMaxRetry() throws Throwable { } catch (Exception t) { assertNotNull(t.getCause()); assertEquals(t.getCause().getClass(), IOException.class); - if (!t.getCause().getMessage().startsWith("Remotely Closed")) { + if (t.getCause() != AsyncHttpProviderUtils.REMOTELY_CLOSED_EXCEPTION) { fail(); } } finally { From 5e2fde29c531928cac7a28230cf4e7dbe15813fd Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 18 Sep 2014 22:23:30 +0200 Subject: [PATCH 616/701] Fix test --- .../client/async/MaxTotalConnectionTest.java | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) 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 51a937dbdd..bb1a3d7190 100644 --- a/src/test/java/com/ning/http/client/async/MaxTotalConnectionTest.java +++ b/src/test/java/com/ning/http/client/async/MaxTotalConnectionTest.java @@ -17,6 +17,7 @@ import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClientConfig; +import com.ning.http.client.ListenableFuture; import com.ning.http.client.Response; import org.slf4j.Logger; @@ -34,7 +35,7 @@ public abstract class MaxTotalConnectionTest extends AbstractBasicTest { protected final Logger log = LoggerFactory.getLogger(AbstractBasicTest.class); @Test(groups = { "standalone", "default_provider" }) - public void testMaxTotalConnectionsExceedingException() { + public void testMaxTotalConnectionsExceedingException() throws IOException { String[] urls = new String[] { "http://google.com", "http://github.com/" }; AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setConnectTimeout(1000) @@ -42,16 +43,24 @@ public void testMaxTotalConnectionsExceedingException() { .build()); try { - boolean caughtError = false; + List> futures = new ArrayList<>(); for (int i = 0; i < urls.length; i++) { + futures.add(client.prepareGet(urls[i]).execute()); + } + + boolean caughtError = false; + int i; + for (i = 0; i < urls.length; i++) { try { - client.prepareGet(urls[i]).execute(); - } catch (IOException e) { + futures.get(i).get(); + } catch (Exception e) { // assert that 2nd request fails, because maxTotalConnections=1 - Assert.assertEquals(1, i); caughtError = true; + break; } } + + Assert.assertEquals(1, i); Assert.assertTrue(caughtError); } finally { client.close(); From 5d54518502c37c3d140e001eccaa8e4522d38d66 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 18 Sep 2014 22:29:49 +0200 Subject: [PATCH 617/701] enforceCompression default to true, close #711 --- .../com/ning/http/client/AsyncHttpClientConfigDefaults.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/ning/http/client/AsyncHttpClientConfigDefaults.java b/src/main/java/com/ning/http/client/AsyncHttpClientConfigDefaults.java index 18ff013539..f5d8cc76e0 100644 --- a/src/main/java/com/ning/http/client/AsyncHttpClientConfigDefaults.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClientConfigDefaults.java @@ -62,7 +62,7 @@ public static int defaultMaxRedirects() { } public static boolean defaultCompressionEnforced() { - return Boolean.getBoolean(ASYNC_CLIENT + "compressionEnforced"); + return getBoolean(ASYNC_CLIENT + "compressionEnforced", true); } public static String defaultUserAgent() { From c65c51bcfb3a2584ddc1bed7bf14a4a4ac956807 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 18 Sep 2014 22:32:06 +0200 Subject: [PATCH 618/701] Fix test --- .../providers/grizzly/GrizzlyAsyncHttpProvider.java | 8 +------- 1 file changed, 1 insertion(+), 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 fc4a9c781a..a56d32e08c 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 @@ -163,12 +163,6 @@ public class GrizzlyAsyncHttpProvider implements AsyncHttpProvider { Grizzly.DEFAULT_ATTRIBUTE_BUILDER.createAttribute(HttpTransactionContext.class.getName()); private final static NTLMEngine ntlmEngine = new NTLMEngine(); - public static final IOException REMOTELY_CLOSED_EXCEPTION = new IOException("Remotely Closed"); - - static { - REMOTELY_CLOSED_EXCEPTION.setStackTrace(new StackTraceElement[] {}); - } - private final BodyHandlerFactory bodyHandlerFactory = new BodyHandlerFactory(); private final TCPNIOTransport clientTransport; @@ -628,7 +622,7 @@ public void onClosed(Closeable closeable, CloseType type) throws IOException { fc.fireEventUpstream(c, new GracefulCloseEvent(HttpTransactionContext.this), null); } else if (CloseType.REMOTELY.equals(type)) { - abort(REMOTELY_CLOSED_EXCEPTION); + abort(AsyncHttpProviderUtils.REMOTELY_CLOSED_EXCEPTION); } } }; From 2bbc90fd048172861b12fc31edf13e1140764626 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 18 Sep 2014 23:03:12 +0200 Subject: [PATCH 619/701] Revert enforcing compression --- .../com/ning/http/client/AsyncHttpClientConfigDefaults.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/ning/http/client/AsyncHttpClientConfigDefaults.java b/src/main/java/com/ning/http/client/AsyncHttpClientConfigDefaults.java index f5d8cc76e0..fb62211e3b 100644 --- a/src/main/java/com/ning/http/client/AsyncHttpClientConfigDefaults.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClientConfigDefaults.java @@ -62,7 +62,7 @@ public static int defaultMaxRedirects() { } public static boolean defaultCompressionEnforced() { - return getBoolean(ASYNC_CLIENT + "compressionEnforced", true); + return getBoolean(ASYNC_CLIENT + "compressionEnforced", false); } public static String defaultUserAgent() { From f4e53623ed786e32e5f262467bcce6758caf053e Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 18 Sep 2014 23:06:39 +0200 Subject: [PATCH 620/701] [maven-release-plugin] prepare release async-http-client-1.9.0-BETA14 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index f4a8bbce5f..e28e719e18 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.9.0-SNAPSHOT + 1.9.0-BETA14 jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From bf2cef551e0dca53bf4164ff910794ecbc3e4fd7 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 18 Sep 2014 23:06:44 +0200 Subject: [PATCH 621/701] [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 e28e719e18..f4a8bbce5f 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.9.0-BETA14 + 1.9.0-SNAPSHOT jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From ceac4dafcd4331c9b0637dac81e638e4441ac63a Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 22 Sep 2014 11:30:58 +0200 Subject: [PATCH 622/701] StringPart won't let configure contentType, close #713 --- .../http/client/multipart/StringPart.java | 50 ++++++++++++------- .../client/async/AsyncProvidersBasicTest.java | 4 +- .../client/async/MultipartUploadTest.java | 9 ++-- .../client/multipart/MultipartBodyTest.java | 2 +- 4 files changed, 38 insertions(+), 27 deletions(-) diff --git a/src/main/java/com/ning/http/client/multipart/StringPart.java b/src/main/java/com/ning/http/client/multipart/StringPart.java index 4d0fb1bf6b..633fa47a87 100644 --- a/src/main/java/com/ning/http/client/multipart/StringPart.java +++ b/src/main/java/com/ning/http/client/multipart/StringPart.java @@ -43,28 +43,40 @@ public class StringPart extends PartBase { private final byte[] content; private final String value; - public StringPart(String name, String value, Charset charset) { - this(name, value, charset, null); - } - private static Charset charsetOrDefault(Charset charset) { return charset == null ? DEFAULT_CHARSET : charset; } + + private static String contentTypeOrDefault(String contentType) { + return contentType == null ? DEFAULT_CONTENT_TYPE : contentType; + } + + private static String transferEncodingOrDefault(String transferEncoding) { + return transferEncoding == null ? DEFAULT_TRANSFER_ENCODING : transferEncoding; + } + + public StringPart(String name, String value) { + this(name, value, null); + } - /** - * 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 contentId - * the content id - */ - public StringPart(String name, String value, Charset charset, String contentId) { - super(name, DEFAULT_CONTENT_TYPE, charsetOrDefault(charset), contentId, DEFAULT_TRANSFER_ENCODING); + public StringPart(String name, String value, String contentType) { + this(name, value, contentType, null); + } + + public StringPart(String name, String value, String contentType, Charset charset) { + this(name, value, contentType, charset, null); + } + + public StringPart(String name, String value, String contentType, Charset charset, String fileName) { + this(name, value, contentType, charset, fileName, null); + } + + public StringPart(String name, String value, String contentType, Charset charset, String fileName, String contentId) { + this(name, value, contentType, charset, fileName, contentId, null); + } + + public StringPart(String name, String value, String contentType, Charset charset, String fileName, String contentId, String transferEncoding) { + super(name, contentTypeOrDefault(contentType), charsetOrDefault(charset), contentId, transferEncodingOrDefault(transferEncoding)); if (value == null) throw new NullPointerException("value"); @@ -72,7 +84,7 @@ public StringPart(String name, String value, Charset charset, String contentId) // See RFC 2048, 2.8. "8bit Data" throw new IllegalArgumentException("NULs may not be present in string parts"); - content = value.getBytes(charsetOrDefault(charset)); + content = value.getBytes(getCharset()); this.value = value; } 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 ea201b156c..4458f87eeb 100755 --- a/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java +++ b/src/test/java/com/ning/http/client/async/AsyncProvidersBasicTest.java @@ -677,7 +677,7 @@ public void asyncDoPostMultiPartTest() throws Throwable { try { final CountDownLatch l = new CountDownLatch(1); - Part p = new StringPart("foo", "bar", UTF_8); + Part p = new StringPart("foo", "bar"); client.preparePost(getTargetUrl()).addBodyPart(p).execute(new AsyncCompletionHandlerAdapter() { @@ -707,7 +707,7 @@ public Response onCompleted(Response response) throws Exception { @Test(groups = { "standalone", "default_provider", "async" }) public void asyncDoPostBasicGZIPTest() throws Throwable { - AsyncHttpClientConfig cf = new AsyncHttpClientConfig.Builder().build(); + AsyncHttpClientConfig cf = new AsyncHttpClientConfig.Builder().setCompressionEnforced(true).build(); AsyncHttpClient client = getAsyncHttpClient(cf); try { final CountDownLatch l = new CountDownLatch(1); 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 f4c89c6aa2..dab38f7cc5 100644 --- a/src/test/java/com/ning/http/client/async/MultipartUploadTest.java +++ b/src/test/java/com/ning/http/client/async/MultipartUploadTest.java @@ -42,7 +42,6 @@ import com.ning.http.client.multipart.ByteArrayPart; import com.ning.http.client.multipart.FilePart; import com.ning.http.client.multipart.StringPart; -import com.ning.http.util.AsyncHttpProviderUtils; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; @@ -221,12 +220,12 @@ public void testSendingSmallFilesAndByteArray() { builder.setUrl(servletEndpointRedirectUrl + "/upload/bob"); builder.addBodyPart(new FilePart("file1", testResource1File, "text/plain", UTF_8)); builder.addBodyPart(new FilePart("file2", testResource2File, "application/x-gzip", null)); - builder.addBodyPart(new StringPart("Name", "Dominic", UTF_8)); + builder.addBodyPart(new StringPart("Name", "Dominic")); builder.addBodyPart(new FilePart("file3", testResource3File, "text/plain", UTF_8)); - builder.addBodyPart(new StringPart("Age", "3", AsyncHttpProviderUtils.DEFAULT_CHARSET)); - builder.addBodyPart(new StringPart("Height", "shrimplike", AsyncHttpProviderUtils.DEFAULT_CHARSET)); - builder.addBodyPart(new StringPart("Hair", "ridiculous", AsyncHttpProviderUtils.DEFAULT_CHARSET)); + builder.addBodyPart(new StringPart("Age", "3")); + builder.addBodyPart(new StringPart("Height", "shrimplike")); + builder.addBodyPart(new StringPart("Hair", "ridiculous")); builder.addBodyPart(new ByteArrayPart("file4", expectedContents.getBytes(UTF_8), "text/plain", UTF_8, "bytearray.txt")); diff --git a/src/test/java/com/ning/http/client/multipart/MultipartBodyTest.java b/src/test/java/com/ning/http/client/multipart/MultipartBodyTest.java index 35abc7f550..09d4cb8934 100644 --- a/src/test/java/com/ning/http/client/multipart/MultipartBodyTest.java +++ b/src/test/java/com/ning/http/client/multipart/MultipartBodyTest.java @@ -46,7 +46,7 @@ public void testBasics() { parts.add(new ByteArrayPart("baPart", "testMultiPart".getBytes(UTF_8), "application/test", UTF_8, "fileName")); // add a string - parts.add(new StringPart("stringPart", "testString", UTF_8)); + parts.add(new StringPart("stringPart", "testString")); compareContentLength(parts); } From 2b769769d8f82d0afbae4c978937b28341540bb0 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 22 Sep 2014 11:48:29 +0200 Subject: [PATCH 623/701] StringPart doesn't have a filename --- .../com/ning/http/client/multipart/StringPart.java | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/ning/http/client/multipart/StringPart.java b/src/main/java/com/ning/http/client/multipart/StringPart.java index 633fa47a87..eac3f700f7 100644 --- a/src/main/java/com/ning/http/client/multipart/StringPart.java +++ b/src/main/java/com/ning/http/client/multipart/StringPart.java @@ -67,15 +67,11 @@ public StringPart(String name, String value, String contentType, Charset charset this(name, value, contentType, charset, null); } - public StringPart(String name, String value, String contentType, Charset charset, String fileName) { - this(name, value, contentType, charset, fileName, null); + public StringPart(String name, String value, String contentType, Charset charset, String contentId) { + this(name, value, contentType, charset, contentId, null); } - public StringPart(String name, String value, String contentType, Charset charset, String fileName, String contentId) { - this(name, value, contentType, charset, fileName, contentId, null); - } - - public StringPart(String name, String value, String contentType, Charset charset, String fileName, String contentId, String transferEncoding) { + public StringPart(String name, String value, String contentType, Charset charset, String contentId, String transferEncoding) { super(name, contentTypeOrDefault(contentType), charsetOrDefault(charset), contentId, transferEncodingOrDefault(transferEncoding)); if (value == null) throw new NullPointerException("value"); @@ -87,7 +83,7 @@ public StringPart(String name, String value, String contentType, Charset charset content = value.getBytes(getCharset()); this.value = value; } - + /** * Writes the data to the given OutputStream. * From 05695d2c7686e2be88335701b58c149fd2497975 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 22 Sep 2014 14:35:54 +0200 Subject: [PATCH 624/701] [maven-release-plugin] prepare release async-http-client-1.9.0-BETA15 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index f4a8bbce5f..77dbdb075e 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.9.0-SNAPSHOT + 1.9.0-BETA15 jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From d77406f92a82ebac8f98a3ffb1c09ea4c41ddd73 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 22 Sep 2014 14:35:59 +0200 Subject: [PATCH 625/701] [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 77dbdb075e..f4a8bbce5f 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.9.0-BETA15 + 1.9.0-SNAPSHOT jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From 1a8b84a569c6092906b205aaaf4d28563769e8be Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 23 Sep 2014 09:45:07 +0200 Subject: [PATCH 626/701] No need to throw exception hostnameVerifier failure, close #715 --- .../client/providers/netty/request/NettyConnectListener.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/request/NettyConnectListener.java b/src/main/java/com/ning/http/client/providers/netty/request/NettyConnectListener.java index dd90164d63..b722af79e3 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/NettyConnectListener.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/NettyConnectListener.java @@ -113,7 +113,6 @@ public void operationComplete(ChannelFuture handshakeFuture) throws Exception { abortChannelPreemption(poolKey); ConnectException exception = new ConnectException("HostnameVerifier exception"); future.abort(exception); - throw exception; } } } From 6f9a97e6173d55e5111fd2699323503b343453e3 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 23 Sep 2014 09:46:09 +0200 Subject: [PATCH 627/701] minor clean up --- .../client/providers/netty/request/NettyConnectListener.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/request/NettyConnectListener.java b/src/main/java/com/ning/http/client/providers/netty/request/NettyConnectListener.java index b722af79e3..c859c133b1 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/NettyConnectListener.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/NettyConnectListener.java @@ -111,8 +111,7 @@ public void operationComplete(ChannelFuture handshakeFuture) throws Exception { writeRequest(channel, poolKey); } else { abortChannelPreemption(poolKey); - ConnectException exception = new ConnectException("HostnameVerifier exception"); - future.abort(exception); + future.abort(new ConnectException("HostnameVerifier exception")); } } } From 22f4fcb7e3d0b39b38f4e1c8a2c0ab83636796bc Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 24 Sep 2014 08:11:40 +0200 Subject: [PATCH 628/701] Prevent overwriting the host header with the host from the URI, close #716 --- .../client/providers/netty/request/NettyRequestFactory.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestFactory.java b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestFactory.java index dbfdc15300..1e2545536b 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestFactory.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestFactory.java @@ -297,9 +297,8 @@ public NettyRequest newNettyRequest(Request request, Uri uri, boolean forceConne headers.set(HttpHeaders.Names.CONNECTION, keepAliveHeaderValue(config)); } - String hostHeader = hostHeader(request, uri); - if (hostHeader != null) - headers.set(HttpHeaders.Names.HOST, hostHeader); + if (!headers.contains(HttpHeaders.Names.HOST)) + headers.set(HttpHeaders.Names.HOST, hostHeader(request, uri)); Realm realm = request.getRealm() != null ? request.getRealm() : config.getRealm(); String authorizationHeader = authorizationHeader(request, uri, proxyServer, realm); From 3397bfd425bce293e166a7fae22c756d98991467 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 24 Sep 2014 10:45:51 +0200 Subject: [PATCH 629/701] Provide a way to configure ChannelPipelines, close #717 --- .../netty/NettyAsyncHttpProviderConfig.java | 43 +++++++++++++++++++ .../netty/channel/ChannelManager.java | 16 +++++++ 2 files changed, 59 insertions(+) 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 f2cfcb3430..5ca089d45d 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 @@ -14,6 +14,7 @@ package com.ning.http.client.providers.netty; import org.jboss.netty.channel.Channel; +import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory; import org.jboss.netty.util.Timer; @@ -101,6 +102,11 @@ public Set> propertiesSet() { */ private ExecutorService bossExecutorService; + private AdditionalPipelineInitializer httpAdditionalPipelineInitializer; + private AdditionalPipelineInitializer wsAdditionalPipelineInitializer; + private AdditionalPipelineInitializer httpsAdditionalPipelineInitializer; + private AdditionalPipelineInitializer wssAdditionalPipelineInitializer; + /** * Allow configuring Netty's HttpClientCodecs. */ @@ -152,6 +158,38 @@ public ExecutorService getBossExecutorService() { public void setBossExecutorService(ExecutorService bossExecutorService) { this.bossExecutorService = bossExecutorService; } + + public AdditionalPipelineInitializer getHttpAdditionalPipelineInitializer() { + return httpAdditionalPipelineInitializer; + } + + public void setHttpAdditionalPipelineInitializer(AdditionalPipelineInitializer httpAdditionalPipelineInitializer) { + this.httpAdditionalPipelineInitializer = httpAdditionalPipelineInitializer; + } + + public AdditionalPipelineInitializer getWsAdditionalPipelineInitializer() { + return wsAdditionalPipelineInitializer; + } + + public void setWsAdditionalPipelineInitializer(AdditionalPipelineInitializer wsAdditionalPipelineInitializer) { + this.wsAdditionalPipelineInitializer = wsAdditionalPipelineInitializer; + } + + public AdditionalPipelineInitializer getHttpsAdditionalPipelineInitializer() { + return httpsAdditionalPipelineInitializer; + } + + public void setHttpsAdditionalPipelineInitializer(AdditionalPipelineInitializer httpsAdditionalPipelineInitializer) { + this.httpsAdditionalPipelineInitializer = httpsAdditionalPipelineInitializer; + } + + public AdditionalPipelineInitializer getWssAdditionalPipelineInitializer() { + return wssAdditionalPipelineInitializer; + } + + public void setWssAdditionalPipelineInitializer(AdditionalPipelineInitializer wssAdditionalPipelineInitializer) { + this.wssAdditionalPipelineInitializer = wssAdditionalPipelineInitializer; + } public int getHttpClientCodecMaxInitialLineLength() { return httpClientCodecMaxInitialLineLength; @@ -261,6 +299,11 @@ public static interface NettyWebSocketFactory { NettyWebSocket newNettyWebSocket(Channel channel, NettyAsyncHttpProviderConfig nettyConfig); } + public static interface AdditionalPipelineInitializer { + + void initPipeline(ChannelPipeline pipeline) throws Exception; + } + public class DefaultNettyWebSocketFactory implements NettyWebSocketFactory { @Override diff --git a/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java b/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java index b36c67ba91..90d209fda8 100644 --- a/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java +++ b/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java @@ -207,6 +207,10 @@ public ChannelPipeline getPipeline() throws Exception { pipeline.addLast(INFLATER_HANDLER, new HttpContentDecompressor()); pipeline.addLast(CHUNKED_WRITER_HANDLER, new ChunkedWriteHandler()); pipeline.addLast(HTTP_PROCESSOR, httpProcessor); + + if (nettyConfig.getHttpAdditionalPipelineInitializer() != null) + nettyConfig.getHttpAdditionalPipelineInitializer().initPipeline(pipeline); + return pipeline; } }); @@ -217,6 +221,10 @@ public ChannelPipeline getPipeline() throws Exception { ChannelPipeline pipeline = pipeline(); pipeline.addLast(HTTP_HANDLER, newHttpClientCodec()); pipeline.addLast(WS_PROCESSOR, wsProcessor); + + if (nettyConfig.getWsAdditionalPipelineInitializer() != null) + nettyConfig.getWsAdditionalPipelineInitializer().initPipeline(pipeline); + return pipeline; } }); @@ -230,6 +238,10 @@ public ChannelPipeline getPipeline() throws Exception { pipeline.addLast(INFLATER_HANDLER, new HttpContentDecompressor()); pipeline.addLast(CHUNKED_WRITER_HANDLER, new ChunkedWriteHandler()); pipeline.addLast(HTTP_PROCESSOR, httpProcessor); + + if (nettyConfig.getHttpsAdditionalPipelineInitializer() != null) + nettyConfig.getHttpsAdditionalPipelineInitializer().initPipeline(pipeline); + return pipeline; } }); @@ -241,6 +253,10 @@ public ChannelPipeline getPipeline() throws Exception { pipeline.addLast(SSL_HANDLER, new SslInitializer(ChannelManager.this)); pipeline.addLast(HTTP_HANDLER, newHttpClientCodec()); pipeline.addLast(WS_PROCESSOR, wsProcessor); + + if (nettyConfig.getWssAdditionalPipelineInitializer() != null) + nettyConfig.getWssAdditionalPipelineInitializer().initPipeline(pipeline); + return pipeline; } }); From 117a43b0602aae91e04575aad47c4d8d88baf283 Mon Sep 17 00:00:00 2001 From: oleksiys Date: Wed, 24 Sep 2014 23:49:31 +0200 Subject: [PATCH 630/701] [1.9.x] + fix the test to echo only read part of the byte[] --- src/test/java/com/ning/http/client/async/BasicHttpsTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 8a55b4a1fb..030d55e6b1 100644 --- a/src/test/java/com/ning/http/client/async/BasicHttpsTest.java +++ b/src/test/java/com/ning/http/client/async/BasicHttpsTest.java @@ -134,7 +134,7 @@ public void handle(String pathInContext, Request r, HttpServletRequest httpReque pos += read; } - httpResponse.getOutputStream().write(bytes); + httpResponse.getOutputStream().write(bytes, 0, pos + 1); // (pos + 1) because last read added -1 } httpResponse.setStatus(200); From b9f7eda62e3383d44c7ed030296b49f5b1003e5b Mon Sep 17 00:00:00 2001 From: oleksiys Date: Thu, 25 Sep 2014 00:56:39 -0700 Subject: [PATCH 631/701] [1.9.x] remove deprecated compression logic --- .../grizzly/GrizzlyAsyncHttpProvider.java | 54 +++++++++---------- 1 file changed, 24 insertions(+), 30 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 a56d32e08c..a418ed9bd2 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 @@ -1417,7 +1417,6 @@ protected boolean onHttpHeaderParsed(final HttpHeader httpHeader, return false; } - @SuppressWarnings({"unchecked"}) @Override protected boolean onHttpPacketParsed(HttpHeader httpHeader, FilterChainContext ctx) { @@ -1922,24 +1921,20 @@ public boolean doHandle(final FilterChainContext ctx, final byte[] data = request.getByteData(); final Buffer gBuffer = Buffers.wrap(mm, data); if (requestPacket.getContentLength() == -1) { - if (!clientConfig.isCompressionEnforced()) { - requestPacket.setContentLengthLong(data.length); - } + requestPacket.setContentLengthLong(data.length); } - final HttpContent content = requestPacket.httpContentBuilder().content(gBuffer).build(); - content.setLast(true); + final HttpContent content = requestPacket.httpContentBuilder() + .content(gBuffer) + .last(true) + .build(); ctx.write(content, ((!requestPacket.isCommitted()) ? ctx.getTransportContext().getCompletionHandler() : null)); return true; } @Override protected long getContentLength(final Request request) { - if (request.getContentLength() >= 0) { - return request.getContentLength(); - } - - return clientConfig.isCompressionEnforced() - ? -1 + return request.getContentLength() >= 0 + ? request.getContentLength() : request.getByteData().length; } } @@ -1969,12 +1964,12 @@ public boolean doHandle(final FilterChainContext ctx, final MemoryManager mm = ctx.getMemoryManager(); final Buffer gBuffer = Buffers.wrap(mm, data); if (requestPacket.getContentLength() == -1) { - if (!clientConfig.isCompressionEnforced()) { - requestPacket.setContentLengthLong(data.length); - } + requestPacket.setContentLengthLong(data.length); } - final HttpContent content = requestPacket.httpContentBuilder().content(gBuffer).build(); - content.setLast(true); + final HttpContent content = requestPacket.httpContentBuilder() + .content(gBuffer) + .last(true) + .build(); ctx.write(content, ((!requestPacket.isCommitted()) ? ctx.getTransportContext().getCompletionHandler() : null)); return true; } @@ -2017,11 +2012,13 @@ public boolean doHandle(final FilterChainContext ctx, final byte[] data = sb.toString().getBytes(charset); final MemoryManager mm = ctx.getMemoryManager(); final Buffer gBuffer = Buffers.wrap(mm, data); - final HttpContent content = requestPacket.httpContentBuilder().content(gBuffer).build(); - if (requestPacket.getContentLength() == -1 && !clientConfig.isCompressionEnforced()) { + final HttpContent content = requestPacket.httpContentBuilder() + .content(gBuffer) + .last(true) + .build(); + if (requestPacket.getContentLength() == -1) { requestPacket.setContentLengthLong(data.length); } - content.setLast(true); ctx.write(content, ((!requestPacket.isCommitted()) ? ctx.getTransportContext().getCompletionHandler() : null)); } @@ -2069,9 +2066,11 @@ public boolean doHandle(final FilterChainContext ctx, } buffer.trim(); if (buffer.hasRemaining()) { - final HttpContent content = requestPacket.httpContentBuilder().content(buffer).build(); + final HttpContent content = requestPacket.httpContentBuilder() + .content(buffer) + .last(true) + .build(); buffer.allowBufferDispose(false); - content.setLast(true); ctx.write(content, ((!requestPacket.isCommitted()) ? ctx.getTransportContext().getCompletionHandler() : null)); } @@ -2171,8 +2170,7 @@ public boolean doHandle(final FilterChainContext ctx, final File f = request.getFile(); requestPacket.setContentLengthLong(f.length()); final HttpTransactionContext context = HttpTransactionContext.get(ctx.getConnection()); - if (clientConfig.isCompressionEnforced() || !SEND_FILE_SUPPORT || - requestPacket.isSecure()) { + if (!SEND_FILE_SUPPORT || requestPacket.isSecure()) { final FileInputStream fis = new FileInputStream(request.getFile()); final MemoryManager mm = ctx.getMemoryManager(); @@ -2227,12 +2225,8 @@ public void updated(WriteResult result) { @Override protected long getContentLength(final Request request) { - if (request.getContentLength() >= 0) { - return request.getContentLength(); - } - - return clientConfig.isCompressionEnforced() - ? -1 + return request.getContentLength() >= 0 + ? request.getContentLength() : request.getFile().length(); } } // END FileBodyHandler From 9a880b3cae263f5173407249df54efb1bbad9063 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 25 Sep 2014 11:40:46 +0200 Subject: [PATCH 632/701] Get rid of Apache Client 3 provider, close #719 --- pom.xml | 20 - .../apache/ApacheAsyncHttpProvider.java | 829 ------------------ .../apache/ApacheAsyncHttpProviderConfig.java | 52 -- .../providers/apache/ApacheResponse.java | 87 -- .../apache/ApacheResponseBodyPart.java | 57 -- .../apache/ApacheResponseFuture.java | 208 ----- .../apache/ApacheResponseHeaders.java | 65 -- .../apache/ApacheResponseStatus.java | 80 -- .../ning/http/client/async/ProviderUtil.java | 9 - 9 files changed, 1407 deletions(-) delete mode 100644 src/main/java/com/ning/http/client/providers/apache/ApacheAsyncHttpProvider.java delete mode 100644 src/main/java/com/ning/http/client/providers/apache/ApacheAsyncHttpProviderConfig.java delete mode 100644 src/main/java/com/ning/http/client/providers/apache/ApacheResponse.java delete mode 100644 src/main/java/com/ning/http/client/providers/apache/ApacheResponseBodyPart.java delete mode 100644 src/main/java/com/ning/http/client/providers/apache/ApacheResponseFuture.java delete mode 100644 src/main/java/com/ning/http/client/providers/apache/ApacheResponseHeaders.java delete mode 100644 src/main/java/com/ning/http/client/providers/apache/ApacheResponseStatus.java diff --git a/pom.xml b/pom.xml index f4a8bbce5f..ad4bf1e4b6 100644 --- a/pom.xml +++ b/pom.xml @@ -191,26 +191,6 @@ 1.2.2 test - - - - commons-httpclient - commons-httpclient - 3.1 - true - - - commons-lang - commons-lang - 2.4 - true - - - commons-logging - commons-logging - 1.1.1 - true - 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 deleted file mode 100644 index d983d25efa..0000000000 --- a/src/main/java/com/ning/http/client/providers/apache/ApacheAsyncHttpProvider.java +++ /dev/null @@ -1,829 +0,0 @@ -/* - * 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.providers.apache; - -import static java.nio.charset.StandardCharsets.*; -import static com.ning.http.util.AsyncHttpProviderUtils.DEFAULT_CHARSET; -import static com.ning.http.util.MiscUtils.closeSilently; -import static com.ning.http.util.MiscUtils.isNonEmpty; - -import org.apache.commons.httpclient.CircularRedirectException; -import org.apache.commons.httpclient.Credentials; -import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler; -import org.apache.commons.httpclient.Header; -import org.apache.commons.httpclient.HttpClient; -import org.apache.commons.httpclient.HttpMethodBase; -import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager; -import org.apache.commons.httpclient.NoHttpResponseException; -import org.apache.commons.httpclient.ProxyHost; -import org.apache.commons.httpclient.UsernamePasswordCredentials; -import org.apache.commons.httpclient.auth.AuthScope; -import org.apache.commons.httpclient.cookie.CookiePolicy; -import org.apache.commons.httpclient.methods.ByteArrayRequestEntity; -import org.apache.commons.httpclient.methods.DeleteMethod; -import org.apache.commons.httpclient.methods.EntityEnclosingMethod; -import org.apache.commons.httpclient.methods.GetMethod; -import org.apache.commons.httpclient.methods.HeadMethod; -import org.apache.commons.httpclient.methods.InputStreamRequestEntity; -import org.apache.commons.httpclient.methods.OptionsMethod; -import org.apache.commons.httpclient.methods.PostMethod; -import org.apache.commons.httpclient.methods.PutMethod; -import org.apache.commons.httpclient.methods.StringRequestEntity; -import org.apache.commons.httpclient.methods.multipart.ByteArrayPartSource; -import org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity; -import org.apache.commons.httpclient.methods.multipart.PartSource; -import org.apache.commons.httpclient.params.HttpClientParams; -import org.apache.commons.httpclient.params.HttpConnectionParams; -import org.apache.commons.httpclient.params.HttpMethodParams; -import org.apache.commons.httpclient.protocol.Protocol; -import org.apache.commons.httpclient.protocol.ProtocolSocketFactory; -import org.apache.commons.httpclient.util.IdleConnectionTimeoutThread; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -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.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.Param; -import com.ning.http.client.ProgressAsyncHandler; -import com.ning.http.client.ProxyServer; -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.cookie.CookieEncoder; -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.listener.TransferCompletionHandler; -import com.ning.http.client.multipart.ByteArrayPart; -import com.ning.http.client.multipart.FilePart; -import com.ning.http.client.multipart.Part; -import com.ning.http.client.multipart.StringPart; -import com.ning.http.client.resumable.ResumableAsyncHandler; -import com.ning.http.client.uri.Uri; -import com.ning.http.util.AsyncHttpProviderUtils; -import com.ning.http.util.ProxyUtils; -import com.ning.http.util.UTF8UrlEncoder; - -import javax.net.SocketFactory; -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLHandshakeException; -import javax.net.ssl.SSLSocketFactory; -import javax.net.ssl.TrustManager; -import javax.net.ssl.X509TrustManager; - -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.net.ConnectException; -import java.net.InetAddress; -import java.net.Socket; -import java.net.UnknownHostException; -import java.nio.ByteBuffer; -import java.security.KeyManagementException; -import java.security.NoSuchAlgorithmException; -import java.security.SecureRandom; -import java.security.cert.CertificateException; -import java.security.cert.X509Certificate; -import java.util.List; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ThreadFactory; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.zip.GZIPInputStream; - -/** - * An {@link com.ning.http.client.AsyncHttpProvider} for Apache Http Client 3.1 - */ -public class ApacheAsyncHttpProvider implements AsyncHttpProvider { - private final static Logger logger = LoggerFactory.getLogger(ApacheAsyncHttpProvider.class); - - private final AsyncHttpClientConfig config; - private final AtomicBoolean isClose = new AtomicBoolean(false); - private IdleConnectionTimeoutThread idleConnectionTimeoutThread; - private final AtomicInteger maxConnections = new AtomicInteger(); - private final MultiThreadedHttpConnectionManager connectionManager; - private final HttpClientParams params; - private final ScheduledExecutorService reaper; - - static { - final SocketFactory factory = new TrustingSSLSocketFactory(); - Protocol.registerProtocol("https", new Protocol("https", new ProtocolSocketFactory() { - public Socket createSocket(String string, int i, InetAddress inetAddress, int i1) throws IOException { - return factory.createSocket(string, i, inetAddress, i1); - } - - public Socket createSocket(String string, int i, InetAddress inetAddress, int i1, HttpConnectionParams httpConnectionParams) - throws IOException { - return factory.createSocket(string, i, inetAddress, i1); - } - - public Socket createSocket(String string, int i) throws IOException { - return factory.createSocket(string, i); - } - }, 443)); - } - - public ApacheAsyncHttpProvider(AsyncHttpClientConfig config) { - this.config = config; - connectionManager = new MultiThreadedHttpConnectionManager(); - - params = new HttpClientParams(); - params.setParameter(HttpMethodParams.SINGLE_COOKIE_HEADER, Boolean.TRUE); - params.setCookiePolicy(CookiePolicy.BROWSER_COMPATIBILITY); - params.setParameter(HttpMethodParams.RETRY_HANDLER, new DefaultHttpMethodRetryHandler()); - - reaper = getReaper(config.getAsyncHttpProviderConfig()); - } - - private ScheduledExecutorService getReaper(AsyncHttpProviderConfig providerConfig) { - - ScheduledExecutorService reaper = null; - if (providerConfig instanceof ApacheAsyncHttpProvider) { - reaper = ApacheAsyncHttpProviderConfig.class.cast(providerConfig).getReaper(); - } - - 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; - } - }); - - return reaper; - } - - public ListenableFuture execute(Request request, AsyncHandler handler) throws IOException { - if (isClose.get()) { - throw new IOException("Closed"); - } - - if (handler instanceof ResumableAsyncHandler) { - request = ResumableAsyncHandler.class.cast(handler).adjustRequestRange(request); - } - - if (config.getMaxConnections() > -1 && (maxConnections.get() + 1) > config.getMaxConnections()) { - throw new IOException(String.format("Too many connections %s", config.getMaxConnections())); - } - - if (idleConnectionTimeoutThread != null) { - idleConnectionTimeoutThread.shutdown(); - idleConnectionTimeoutThread = null; - } - - int requestTimeout = AsyncHttpProviderUtils.requestTimeout(config, request); - if (config.getReadTimeout() > 0 && requestTimeout != -1 && requestTimeout < config.getReadTimeout()) { - idleConnectionTimeoutThread = new IdleConnectionTimeoutThread(); - idleConnectionTimeoutThread.setConnectionTimeout(config.getReadTimeout()); - idleConnectionTimeoutThread.addConnectionManager(connectionManager); - idleConnectionTimeoutThread.start(); - } - - HttpClient httpClient = new HttpClient(params, connectionManager); - - Realm realm = request.getRealm() != null ? request.getRealm() : config.getRealm(); - if (realm != null) { - httpClient.getParams().setAuthenticationPreemptive(realm.getUsePreemptiveAuth()); - Credentials defaultcreds = new UsernamePasswordCredentials(realm.getPrincipal(), realm.getPassword()); - httpClient.getState().setCredentials(new AuthScope(null, -1, AuthScope.ANY_REALM), defaultcreds); - } - - HttpMethodBase method = createMethod(httpClient, request); - ApacheResponseFuture f = new ApacheResponseFuture(handler, requestTimeout, request, method); - f.touch(); - - f.setInnerFuture(config.executorService().submit(new ApacheClientRunnable(request, handler, method, f, httpClient))); - maxConnections.incrementAndGet(); - return f; - } - - public void close() { - reaper.shutdown(); - if (idleConnectionTimeoutThread != null) { - idleConnectionTimeoutThread.shutdown(); - idleConnectionTimeoutThread = null; - } - if (connectionManager != null) { - try { - connectionManager.shutdown(); - } catch (Exception e) { - logger.error("Error shutting down connection manager", e); - } - } - } - - public Response prepareResponse(HttpResponseStatus status, HttpResponseHeaders headers, List bodyParts) { - return new ApacheResponse(status, headers, bodyParts); - } - - private HttpMethodBase createMethod(HttpClient client, Request request) throws IOException, FileNotFoundException { - String methodName = request.getMethod(); - HttpMethodBase method = null; - if (methodName.equalsIgnoreCase("POST") || methodName.equalsIgnoreCase("PUT")) { - EntityEnclosingMethod post = methodName.equalsIgnoreCase("POST") ? new PostMethod(request.getUrl()) : new PutMethod(request.getUrl()); - - String bodyCharset = request.getBodyEncoding() == null ? DEFAULT_CHARSET.name() : request.getBodyEncoding(); - - post.getParams().setContentCharset(ISO_8859_1.name()); - if (request.getByteData() != null) { - post.setRequestEntity(new ByteArrayRequestEntity(request.getByteData())); - post.setRequestHeader("Content-Length", String.valueOf(request.getByteData().length)); - } else if (request.getStringData() != null) { - post.setRequestEntity(new StringRequestEntity(request.getStringData(), "text/xml", bodyCharset)); - post.setRequestHeader("Content-Length", String.valueOf(request.getStringData().getBytes(bodyCharset).length)); - } else if (request.getStreamData() != null) { - InputStreamRequestEntity r = new InputStreamRequestEntity(request.getStreamData()); - post.setRequestEntity(r); - post.setRequestHeader("Content-Length", String.valueOf(r.getContentLength())); - - } else if (isNonEmpty(request.getFormParams())) { - StringBuilder sb = new StringBuilder(); - for (final Param param : request.getFormParams()) { - final String name = param.getName(); - final String value = param.getValue(); - if (sb.length() > 0) { - sb.append("&"); - } - UTF8UrlEncoder.appendEncoded(sb, name); - sb.append("="); - UTF8UrlEncoder.appendEncoded(sb, value); - } - - post.setRequestHeader("Content-Length", String.valueOf(sb.length())); - post.setRequestEntity(new StringRequestEntity(sb.toString(), "text/xml", ISO_8859_1.name())); - - if (!request.getHeaders().containsKey("Content-Type")) { - post.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); - } - } else if (isNonEmpty(request.getParts())) { - MultipartRequestEntity mre = createMultipartRequestEntity(bodyCharset, request.getParts(), post.getParams()); - post.setRequestEntity(mre); - post.setRequestHeader("Content-Type", mre.getContentType()); - post.setRequestHeader("Content-Length", String.valueOf(mre.getContentLength())); - } else if (request.getFile() != null) { - File file = request.getFile(); - if (!file.isFile()) { - throw new IOException(String.format(Thread.currentThread() - + "File %s is not a file or doesn't exist", file.getAbsolutePath())); - } - post.setRequestHeader("Content-Length", String.valueOf(file.length())); - - FileInputStream fis = new FileInputStream(file); - try { - InputStreamRequestEntity r = new InputStreamRequestEntity(fis); - post.setRequestEntity(r); - post.setRequestHeader("Content-Length", String.valueOf(r.getContentLength())); - } finally { - fis.close(); - } - } else if (request.getBodyGenerator() != null) { - Body body = request.getBodyGenerator().createBody(); - try { - int length = (int) body.getContentLength(); - if (length < 0) { - length = (int) request.getContentLength(); - } - - // TODO: This is suboptimal - if (length >= 0) { - post.setRequestHeader("Content-Length", String.valueOf(length)); - - // This is totally sub optimal - byte[] bytes = new byte[length]; - ByteBuffer buffer = ByteBuffer.wrap(bytes); - for (; ; ) { - buffer.clear(); - if (body.read(buffer) < 0) { - break; - } - } - post.setRequestEntity(new ByteArrayRequestEntity(bytes)); - } - } finally { - closeSilently(body); - } - } - - if (request.getHeaders().getFirstValue("Expect") != null - && request.getHeaders().getFirstValue("Expect").equalsIgnoreCase("100-Continue")) { - post.setUseExpectHeader(true); - } - method = post; - } else if (methodName.equalsIgnoreCase("DELETE")) { - method = new DeleteMethod(request.getUrl()); - } else if (methodName.equalsIgnoreCase("HEAD")) { - method = new HeadMethod(request.getUrl()); - } else if (methodName.equalsIgnoreCase("GET")) { - method = new GetMethod(request.getUrl()); - } else if (methodName.equalsIgnoreCase("OPTIONS")) { - method = new OptionsMethod(request.getUrl()); - } else { - throw new IllegalStateException(String.format("Invalid Method", methodName)); - } - - ProxyServer proxyServer = ProxyUtils.getProxyServer(config, request); - if (proxyServer != null) { - - if (proxyServer.getPrincipal() != null) { - Credentials defaultcreds = new UsernamePasswordCredentials(proxyServer.getPrincipal(), proxyServer.getPassword()); - client.getState().setProxyCredentials(new AuthScope(null, -1, AuthScope.ANY_REALM), defaultcreds); - } - - ProxyHost proxyHost = proxyServer == null ? null : new ProxyHost(proxyServer.getHost(), proxyServer.getPort()); - client.getHostConfiguration().setProxyHost(proxyHost); - } - if(request.getLocalAddress()!=null) { - client.getHostConfiguration().setLocalAddress(request.getLocalAddress()); - } - - method.setFollowRedirects(false); - if (isNonEmpty(request.getCookies())) { - method.setRequestHeader("Cookie", CookieEncoder.encode(request.getCookies())); - } - - if (request.getHeaders() != null) { - for (String name : request.getHeaders().keySet()) { - if (!"host".equalsIgnoreCase(name)) { - for (String value : request.getHeaders().get(name)) { - method.setRequestHeader(name, value); - } - } - } - } - - if (request.getHeaders().getFirstValue("User-Agent") != null) { - method.setRequestHeader("User-Agent", request.getHeaders().getFirstValue("User-Agent")); - } else if (config.getUserAgent() != null) { - method.setRequestHeader("User-Agent", config.getUserAgent()); - } - - Header acceptableEncodingHeader = method.getRequestHeader("Accept-Encoding"); - if (acceptableEncodingHeader != null) { - String acceptableEncodings = acceptableEncodingHeader.getValue(); - if (acceptableEncodings.indexOf("gzip") == -1) { - StringBuilder buf = new StringBuilder(acceptableEncodings); - if (buf.length() > 1) { - buf.append(","); - } - buf.append("gzip"); - method.setRequestHeader("Accept-Encoding", buf.toString()); - } - } else if (config.isCompressionEnforced()) { - method.setRequestHeader("Accept-Encoding", "gzip"); - } - - if (request.getVirtualHost() != null) { - - String vs = request.getVirtualHost(); - int index = vs.indexOf(":"); - if (index > 0) { - vs = vs.substring(0, index); - } - method.getParams().setVirtualHost(vs); - } - - return method; - } - - private final static int computeAndSetContentLength(Request request, HttpMethodBase m) { - int lenght = (int) request.getContentLength(); - if (lenght == -1 && m.getRequestHeader("Content-Length") != null) { - lenght = Integer.valueOf(m.getRequestHeader("Content-Length").getValue()); - } - - if (lenght != -1) { - m.setRequestHeader("Content-Length", String.valueOf(lenght)); - } - return lenght; - } - - public class ApacheClientRunnable implements Callable { - - private final AsyncHandler asyncHandler; - private HttpMethodBase method; - private final ApacheResponseFuture future; - private Request request; - private final HttpClient httpClient; - private int currentRedirectCount; - private AtomicBoolean isAuth = new AtomicBoolean(false); - private boolean terminate = true; - - public ApacheClientRunnable(Request request, AsyncHandler asyncHandler, HttpMethodBase method, ApacheResponseFuture future, HttpClient httpClient) { - this.asyncHandler = asyncHandler; - this.method = method; - this.future = future; - this.request = request; - this.httpClient = httpClient; - } - - public T call() { - terminate = true; - AsyncHandler.STATE state = AsyncHandler.STATE.ABORT; - try { - Uri uri = request.getUri(); - - int delay = AsyncHttpProviderUtils.requestTimeout(config, future.getRequest()); - if (delay != -1) { - ReaperFuture reaperFuture = new ReaperFuture(future); - Future scheduledFuture = reaper.scheduleAtFixedRate(reaperFuture, delay, 500, TimeUnit.MILLISECONDS); - reaperFuture.setScheduledFuture(scheduledFuture); - future.setReaperFuture(reaperFuture); - } - - if (asyncHandler instanceof TransferCompletionHandler) { - throw new IllegalStateException(TransferCompletionHandler.class.getName() + "not supported by this provider"); - } - - int statusCode = 200; - try { - statusCode = httpClient.executeMethod(method); - } catch (CircularRedirectException ex) { - // Quite ugly, but this is needed to unify - statusCode = 302; - currentRedirectCount = config.getMaxRedirects(); - } - - ApacheResponseStatus status = new ApacheResponseStatus(uri, config, method); - FilterContext fc = new FilterContext.FilterContextBuilder().asyncHandler(asyncHandler).request(request).responseStatus(status).build(); - for (ResponseFilter asyncFilter : config.getResponseFilters()) { - fc = asyncFilter.filter(fc); - if (fc == null) { - throw new NullPointerException("FilterContext is null"); - } - } - - // The request has changed - if (fc.replayRequest()) { - request = fc.getRequest(); - method = createMethod(httpClient, request); - terminate = false; - return call(); - } - - logger.debug("\n\nRequest {}\n\nResponse {}\n", request, method); - - if (AsyncHttpProviderUtils.followRedirect(config, request) && (statusCode == 302 || statusCode == 301)) { - - isAuth.set(false); - - if (currentRedirectCount++ < config.getMaxRedirects()) { - String location = method.getResponseHeader("Location").getValue(); - Uri rediUri = Uri.create(uri, location); - - if (!rediUri.equals(uri)) { - RequestBuilder builder = new RequestBuilder(request); - - logger.debug("Redirecting to {}", rediUri); - - request = builder.setUri(rediUri).build(); - method = createMethod(httpClient, request); - terminate = false; - return call(); - } - } else { - throw new MaxRedirectException("Maximum redirect reached: " + config.getMaxRedirects()); - } - } - - state = asyncHandler.onStatusReceived(status); - if (state == AsyncHandler.STATE.CONTINUE) { - state = asyncHandler.onHeadersReceived(new ApacheResponseHeaders(method)); - } - - if (state == AsyncHandler.STATE.CONTINUE) { - InputStream is = method.getResponseBodyAsStream(); - if (is != null) { - Header h = method.getResponseHeader("Content-Encoding"); - if (h != null) { - String contentEncoding = h.getValue(); - boolean isGZipped = contentEncoding == null ? false : "gzip".equalsIgnoreCase(contentEncoding); - if (isGZipped) { - is = new GZIPInputStream(is); - } - } - - int byteToRead = (int) method.getResponseContentLength(); - InputStream stream = is; - if (byteToRead <= 0) { - int[] lengthWrapper = new int[1]; - byte[] bytes = AsyncHttpProviderUtils.readFully(is, lengthWrapper); - stream = new ByteArrayInputStream(bytes, 0, lengthWrapper[0]); - byteToRead = lengthWrapper[0]; - } - - if (byteToRead > 0) { - int minBytes = Math.min(8192, byteToRead); - byte[] bytes = new byte[minBytes]; - int leftBytes = minBytes < 8192 ? minBytes : byteToRead; - int read = 0; - while (leftBytes > -1) { - - try { - read = stream.read(bytes); - } catch (IOException ex) { - logger.warn("Connection closed", ex); - read = -1; - } - - if (read == -1) { - break; - } - - future.touch(); - - byte[] b = new byte[read]; - System.arraycopy(bytes, 0, b, 0, read); - leftBytes -= read; - - asyncHandler.onBodyPartReceived(new ApacheResponseBodyPart(b, leftBytes > -1)); - - } - } - } - - if (method.getName().equalsIgnoreCase("HEAD")) { - asyncHandler.onBodyPartReceived(new ApacheResponseBodyPart("".getBytes(), true)); - } - } - - if (asyncHandler instanceof ProgressAsyncHandler) { - ProgressAsyncHandler progressAsyncHandler = (ProgressAsyncHandler) asyncHandler; - progressAsyncHandler.onHeaderWriteCompleted(); - progressAsyncHandler.onContentWriteCompleted(); - } - - try { - return asyncHandler.onCompleted(); - } catch (Throwable t) { - RuntimeException ex = new RuntimeException(); - ex.initCause(t); - throw ex; - } - } catch (Throwable t) { - - if (t instanceof IOException && !config.getIOExceptionFilters().isEmpty()) { - FilterContext fc = new FilterContext.FilterContextBuilder().asyncHandler(asyncHandler) - .request(future.getRequest()).ioException(IOException.class.cast(t)).build(); - - try { - fc = handleIoException(fc); - } catch (FilterException e) { - if (config.getMaxConnections() != -1) { - maxConnections.decrementAndGet(); - } - future.done(); - method.releaseConnection(); - } - - if (fc.replayRequest()) { - request = fc.getRequest(); - return call(); - } - } - - if (method.isAborted()) { - return null; - } - - logger.debug(t.getMessage(), t); - - try { - future.abort(filterException(t)); - } catch (Throwable t2) { - logger.error(t2.getMessage(), t2); - } - } finally { - if (terminate) { - if (config.getMaxConnections() != -1) { - maxConnections.decrementAndGet(); - } - future.done(); - - // Crappy Apache HttpClient who blocks forever here with large files. - config.executorService().submit(new Runnable() { - - public void run() { - method.releaseConnection(); - } - }); - } - } - return null; - } - - private Throwable filterException(Throwable t) { - if (t instanceof UnknownHostException) { - t = new ConnectException(t.getMessage()); - - } else if (t instanceof NoHttpResponseException) { - int responseTimeout = AsyncHttpProviderUtils.requestTimeout(config, request); - t = new TimeoutException(String.format("No response received after %s", responseTimeout)); - - } else if (t instanceof SSLHandshakeException) { - Throwable t2 = new ConnectException(); - t2.initCause(t); - t = t2; - } - - return t; - } - - private FilterContext handleIoException(FilterContext fc) throws FilterException { - for (IOExceptionFilter asyncFilter : config.getIOExceptionFilters()) { - fc = asyncFilter.filter(fc); - if (fc == null) { - throw new NullPointerException("FilterContext is null"); - } - } - return fc; - } - } - - private MultipartRequestEntity createMultipartRequestEntity(String charset, List params, HttpMethodParams methodParams) throws FileNotFoundException { - org.apache.commons.httpclient.methods.multipart.Part[] parts = new org.apache.commons.httpclient.methods.multipart.Part[params.size()]; - int i = 0; - - for (Part part : params) { - if (part instanceof StringPart) { - parts[i] = new org.apache.commons.httpclient.methods.multipart.StringPart(part.getName(), - ((StringPart) part).getValue(), - charset); - } else if (part instanceof FilePart) { - parts[i] = new org.apache.commons.httpclient.methods.multipart.FilePart(part.getName(), - ((FilePart) part).getFile(), - ((FilePart) part).getContentType(), - ((FilePart) part).getCharset().name()); - - } else if (part instanceof ByteArrayPart) { - PartSource source = new ByteArrayPartSource(((ByteArrayPart) part).getFileName(), ((ByteArrayPart) part).getBytes()); - parts[i] = new org.apache.commons.httpclient.methods.multipart.FilePart(part.getName(), - source, - ((ByteArrayPart) part).getContentType(), - ((ByteArrayPart) part).getCharset().name()); - - } else if (part == null) { - throw new NullPointerException("Part cannot be null"); - } else { - throw new IllegalArgumentException(String.format("Unsupported part type for multipart parameter %s", - part.getName())); - } - ++i; - } - return new MultipartRequestEntity(parts, methodParams); - } - - private static class TrustingSSLSocketFactory extends SSLSocketFactory { - private SSLSocketFactory delegate; - - private TrustingSSLSocketFactory() { - try { - SSLContext sslcontext = SSLContext.getInstance("SSL"); - - sslcontext.init(null, new TrustManager[]{new TrustEveryoneTrustManager()}, new SecureRandom()); - delegate = sslcontext.getSocketFactory(); - } catch (KeyManagementException e) { - throw new IllegalStateException(); - } catch (NoSuchAlgorithmException e) { - throw new IllegalStateException(); - } - } - - @Override - public Socket createSocket(String s, int i) throws IOException, UnknownHostException { - return delegate.createSocket(s, i); - } - - @Override - public Socket createSocket(String s, int i, InetAddress inetAddress, int i1) throws IOException, UnknownHostException { - return delegate.createSocket(s, i, inetAddress, i1); - } - - @Override - public Socket createSocket(InetAddress inetAddress, int i) throws IOException { - return delegate.createSocket(inetAddress, i); - } - - @Override - public Socket createSocket(InetAddress inetAddress, int i, InetAddress inetAddress1, int i1) throws IOException { - return delegate.createSocket(inetAddress, i, inetAddress1, i1); - } - - @Override - public String[] getDefaultCipherSuites() { - return delegate.getDefaultCipherSuites(); - } - - @Override - public String[] getSupportedCipherSuites() { - return delegate.getSupportedCipherSuites(); - } - - @Override - public Socket createSocket(Socket socket, String s, int i, boolean b) throws IOException { - return delegate.createSocket(socket, s, i, b); - } - } - - private static class TrustEveryoneTrustManager implements X509TrustManager { - - @Override - public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException { - // do nothing - } - - @Override - public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException { - // do nothing - } - - @Override - public X509Certificate[] getAcceptedIssuers() { - return new X509Certificate[0]; - } - } - - private final class ReaperFuture implements Future, Runnable { - private Future scheduledFuture; - private ApacheResponseFuture apacheResponseFuture; - - public ReaperFuture(ApacheResponseFuture apacheResponseFuture) { - this.apacheResponseFuture = apacheResponseFuture; - } - - public void setScheduledFuture(Future scheduledFuture) { - this.scheduledFuture = scheduledFuture; - } - - @Override - public synchronized boolean cancel(boolean mayInterruptIfRunning) { - //cleanup references to allow gc to reclaim memory independently - //of this Future lifecycle - this.apacheResponseFuture = null; - return this.scheduledFuture.cancel(mayInterruptIfRunning); - } - - @Override - public Object get() throws InterruptedException, ExecutionException { - return this.scheduledFuture.get(); - } - - @Override - public Object get(long timeout, TimeUnit unit) - throws InterruptedException, ExecutionException, - TimeoutException { - return this.scheduledFuture.get(timeout, unit); - } - - @Override - public boolean isCancelled() { - return this.scheduledFuture.isCancelled(); - } - - @Override - public boolean isDone() { - return this.scheduledFuture.isDone(); - } - - @Override - public synchronized void run() { - if (this.apacheResponseFuture != null && this.apacheResponseFuture.hasExpired()) { - logger.debug("Request Timeout expired for " + this.apacheResponseFuture); - - int requestTimeout = AsyncHttpProviderUtils.requestTimeout(config, this.apacheResponseFuture.getRequest()); - apacheResponseFuture.abort(new TimeoutException(String.format("No response received after %s", requestTimeout))); - - this.apacheResponseFuture = null; - } - } - } -} diff --git a/src/main/java/com/ning/http/client/providers/apache/ApacheAsyncHttpProviderConfig.java b/src/main/java/com/ning/http/client/providers/apache/ApacheAsyncHttpProviderConfig.java deleted file mode 100644 index 280ffad7c2..0000000000 --- a/src/main/java/com/ning/http/client/providers/apache/ApacheAsyncHttpProviderConfig.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * 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.providers.apache; - -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ScheduledExecutorService; - -import com.ning.http.client.AsyncHttpProviderConfig; - -public class ApacheAsyncHttpProviderConfig implements AsyncHttpProviderConfig { - - private final ConcurrentHashMap properties = new ConcurrentHashMap(); - - private ScheduledExecutorService reaper; - - public AsyncHttpProviderConfig addProperty(String name, String value) { - properties.put(name, value); - return this; - } - - public String getProperty(String name) { - return properties.get(name); - } - - public String removeProperty(String name) { - return properties.remove(name); - } - - public Set> propertiesSet() { - return properties.entrySet(); - } - - public void setReaper(ScheduledExecutorService reaper) { - this.reaper = reaper; - } - - public ScheduledExecutorService getReaper() { - return reaper; - } -} 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 deleted file mode 100644 index 2d765d82f6..0000000000 --- a/src/main/java/com/ning/http/client/providers/apache/ApacheResponse.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * 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.providers.apache; - -import com.ning.http.client.HttpResponseBodyPart; -import com.ning.http.client.HttpResponseHeaders; -import com.ning.http.client.HttpResponseStatus; -import com.ning.http.client.ResponseBase; -import com.ning.http.client.cookie.Cookie; -import com.ning.http.client.cookie.CookieDecoder; -import com.ning.http.util.AsyncHttpProviderUtils; - -import java.io.IOException; -import java.io.InputStream; -import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -public class ApacheResponse extends ResponseBase { - - public ApacheResponse(HttpResponseStatus status, HttpResponseHeaders headers, List bodyParts) { - super(status, headers, bodyParts); - } - - @Override - public byte[] getResponseBodyAsBytes() throws IOException { - return AsyncHttpProviderUtils.contentToByte(bodyParts); - } - - @Override - public ByteBuffer getResponseBodyAsByteBuffer() throws IOException { - return ByteBuffer.wrap(getResponseBodyAsBytes()); - } - - @Override - public String getResponseBody() throws IOException { - return getResponseBody(null); - } - - @Override - public String getResponseBody(String charset) throws IOException { - return AsyncHttpProviderUtils.contentToString(bodyParts, calculateCharset(charset)); - } - - @Override - public InputStream getResponseBodyAsStream() throws IOException { - return AsyncHttpProviderUtils.contentToInputStream(bodyParts); - } - - @Override - public String getResponseBodyExcerpt(int maxLength) throws IOException { - return getResponseBodyExcerpt(maxLength, null); - } - - @Override - public String getResponseBodyExcerpt(int maxLength, String charset) throws IOException { - String response = AsyncHttpProviderUtils.contentToString(bodyParts, calculateCharset(charset)); - return response.length() <= maxLength ? response : response.substring(0, maxLength); - } - - @Override - protected List buildCookies() { - 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 = CookieDecoder.decode(value); - localCookies.add(cookie); - } - } - } - return localCookies; - } -} diff --git a/src/main/java/com/ning/http/client/providers/apache/ApacheResponseBodyPart.java b/src/main/java/com/ning/http/client/providers/apache/ApacheResponseBodyPart.java deleted file mode 100644 index 87633f8c34..0000000000 --- a/src/main/java/com/ning/http/client/providers/apache/ApacheResponseBodyPart.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * 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.providers.apache; - -import com.ning.http.client.HttpResponseBodyPart; - -import java.io.IOException; -import java.io.OutputStream; -import java.nio.ByteBuffer; - -/** - * A callback class used when an HTTP response body is received. - */ -public class ApacheResponseBodyPart extends HttpResponseBodyPart { - - private final byte[] chunk; - - public ApacheResponseBodyPart(byte[] chunk, boolean last) { - super(last); - this.chunk = chunk; - } - - /** - * Return the response body's part bytes received. - * - * @return the response body's part bytes received. - */ - public byte[] getBodyPartBytes() { - return chunk; - } - - @Override - public int writeTo(OutputStream outputStream) throws IOException { - outputStream.write(chunk); - return chunk.length; - } - - @Override - public ByteBuffer getBodyByteBuffer() { - return ByteBuffer.wrap(chunk); - } - - @Override - public int length() { - return chunk != null ? chunk.length : 0; - } -} 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 deleted file mode 100644 index 343913e92b..0000000000 --- a/src/main/java/com/ning/http/client/providers/apache/ApacheResponseFuture.java +++ /dev/null @@ -1,208 +0,0 @@ -/* - * 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.providers.apache; - -import static com.ning.http.util.DateUtils.millisTime; - -import com.ning.http.client.AsyncHandler; -import com.ning.http.client.Request; -import com.ning.http.client.listenable.AbstractListenableFuture; - -import org.apache.commons.httpclient.HttpMethodBase; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.concurrent.CancellationException; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicLong; -import java.util.concurrent.atomic.AtomicReference; - - -public class ApacheResponseFuture extends AbstractListenableFuture { - - private final static Logger logger = LoggerFactory.getLogger(ApacheResponseFuture.class); - - private Future innerFuture; - private final AsyncHandler asyncHandler; - private final int responseTimeoutInMs; - private final AtomicBoolean cancelled = new AtomicBoolean(false); - 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(millisTime()); - private final AtomicBoolean contentProcessed = new AtomicBoolean(false); - private final Request request; - private final HttpMethodBase method; - private Future reaperFuture; - - public ApacheResponseFuture(AsyncHandler asyncHandler, int responseTimeoutInMs, Request request, HttpMethodBase method) { - this.asyncHandler = asyncHandler; - this.responseTimeoutInMs = responseTimeoutInMs == -1 ? Integer.MAX_VALUE : responseTimeoutInMs; - this.request = request; - this.method = method; - } - - protected void setInnerFuture(Future innerFuture) { - this.innerFuture = innerFuture; - } - - public void done() { - isDone.set(true); - if (reaperFuture != null) { - reaperFuture.cancel(true); - } - runListeners(); - } - - /** - * TODO. - * - * @param v The new content - */ - public void content(V v) { - } - - protected void setReaperFuture(Future reaperFuture) { - if (this.reaperFuture != null) { - this.reaperFuture.cancel(true); - } - this.reaperFuture = reaperFuture; - } - - @Override - public String toString() { - return "ApacheResponseFuture{" + - "innerFuture=" + innerFuture + - ", asyncHandler=" + asyncHandler + - ", responseTimeoutInMs=" + responseTimeoutInMs + - ", cancelled=" + cancelled + - ", timedOut=" + timedOut + - ", isDone=" + isDone + - ", exception=" + exception + - ", touch=" + touch + - ", contentProcessed=" + contentProcessed + - ", request=" + request + - ", method=" + method + - ", reaperFuture=" + reaperFuture + - '}'; - } - - public void abort(Throwable t) { - exception.set(t); - if (innerFuture != null) { - innerFuture.cancel(true); - } - - if (method != null) { - method.abort(); - } - - if (reaperFuture != null) { - reaperFuture.cancel(true); - } - if (!timedOut.get() && !cancelled.get()) { - try { - asyncHandler.onThrowable(t); - } catch (Throwable t2) { - logger.debug("asyncHandler.onThrowable", t2); - } - } - runListeners(); - } - - public boolean cancel(boolean mayInterruptIfRunning) { - if (!cancelled.get() && innerFuture != null) { - method.abort(); - try { - asyncHandler.onThrowable(new CancellationException()); - } catch (Throwable t) { - logger.debug("asyncHandler.onThrowable", t); - } - cancelled.set(true); - if (reaperFuture != null) { - reaperFuture.cancel(true); - } - runListeners(); - return innerFuture.cancel(mayInterruptIfRunning); - } else { - runListeners(); - return false; - } - } - - public boolean isCancelled() { - if (innerFuture != null) { - return innerFuture.isCancelled(); - } else { - return false; - } - } - - public boolean isDone() { - contentProcessed.set(true); - return innerFuture.isDone(); - } - - public V get() throws InterruptedException, ExecutionException { - try { - return get(responseTimeoutInMs, TimeUnit.MILLISECONDS); - } catch (TimeoutException e) { - throw new ExecutionException(e); - } - } - - public V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { - V content = null; - try { - if (innerFuture != null) { - content = innerFuture.get(timeout, unit); - } - } catch (TimeoutException t) { - if (!contentProcessed.get() && timeout != -1 && ((millisTime() - touch.get()) <= responseTimeoutInMs)) { - return get(timeout, unit); - } - - if (exception.get() == null) { - timedOut.set(true); - throw new ExecutionException(new TimeoutException(String.format("No response received after %s", responseTimeoutInMs))); - } - } catch (CancellationException ce) { - } - - if (exception.get() != null) { - throw new ExecutionException(exception.get()); - } - return content; - } - - /** - * Is the Future still valid - * - * @return true if response has expired and should be terminated. - */ - public boolean hasExpired() { - return responseTimeoutInMs != -1 && ((millisTime() - touch.get()) >= responseTimeoutInMs); - } - - public void touch() { - touch.set(millisTime()); - } - - public Request getRequest() { - return request; - } -} diff --git a/src/main/java/com/ning/http/client/providers/apache/ApacheResponseHeaders.java b/src/main/java/com/ning/http/client/providers/apache/ApacheResponseHeaders.java deleted file mode 100644 index 3bfedfa6dd..0000000000 --- a/src/main/java/com/ning/http/client/providers/apache/ApacheResponseHeaders.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * 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.providers.apache; - -import org.apache.commons.httpclient.Header; -import org.apache.commons.httpclient.HttpMethodBase; - -import com.ning.http.client.FluentCaseInsensitiveStringsMap; -import com.ning.http.client.HttpResponseHeaders; - -/** - * A class that represent the HTTP headers. - */ -public class ApacheResponseHeaders extends HttpResponseHeaders { - - private final HttpMethodBase method; - private final FluentCaseInsensitiveStringsMap headers; - - public ApacheResponseHeaders(HttpMethodBase method) { - super(false); - this.method = method; - headers = computerHeaders(); - } - - private FluentCaseInsensitiveStringsMap computerHeaders() { - FluentCaseInsensitiveStringsMap h = new FluentCaseInsensitiveStringsMap(); - - Header[] uh = method.getResponseHeaders(); - - for (Header e : uh) { - if (e.getName() != null) { - h.add(e.getName(), e.getValue()); - } - } - - uh = method.getResponseFooters(); - for (Header e : uh) { - if (e.getName() != null) { - h.add(e.getName(), e.getValue()); - } - } - - return h; - } - - /** - * Return the HTTP header - * - * @return an {@link com.ning.http.client.FluentCaseInsensitiveStringsMap} - */ - @Override - public FluentCaseInsensitiveStringsMap getHeaders() { - return headers; - } -} \ No newline at end of file diff --git a/src/main/java/com/ning/http/client/providers/apache/ApacheResponseStatus.java b/src/main/java/com/ning/http/client/providers/apache/ApacheResponseStatus.java deleted file mode 100644 index 930750bc33..0000000000 --- a/src/main/java/com/ning/http/client/providers/apache/ApacheResponseStatus.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * 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.providers.apache; - -import org.apache.commons.httpclient.HttpMethodBase; - -import com.ning.http.client.AsyncHttpClientConfig; -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 com.ning.http.client.uri.Uri; - -import java.util.List; - -/** - * A class that represent the HTTP response' status line (code + text) - */ -public class ApacheResponseStatus extends HttpResponseStatus { - - private final HttpMethodBase method; - - public ApacheResponseStatus(Uri uri, AsyncHttpClientConfig config, HttpMethodBase method) { - super(uri, config); - this.method = method; - } - - /** - * Return the response status code - * - * @return the response status code - */ - public int getStatusCode() { - return method.getStatusCode(); - } - - /** - * Return the response status text - * - * @return the response status text - */ - public String getStatusText() { - return method.getStatusText(); - } - - @Override - public String getProtocolName() { - return method.getStatusLine().getHttpVersion(); - } - - @Override - public int getProtocolMajorVersion() { - return 1; //TODO - } - - @Override - public int getProtocolMinorVersion() { - return 1; //TODO - } - - @Override - public String getProtocolText() { - return ""; //TODO - } - - @Override - public Response prepareResponse(HttpResponseHeaders headers, List bodyParts) { - return new ApacheResponse(this, headers, bodyParts); - } -} \ No newline at end of file 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 17cdbe33d1..d32e6fd2de 100644 --- a/src/test/java/com/ning/http/client/async/ProviderUtil.java +++ b/src/test/java/com/ning/http/client/async/ProviderUtil.java @@ -17,7 +17,6 @@ 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; @@ -38,14 +37,6 @@ public static AsyncHttpClient grizzlyProvider(AsyncHttpClientConfig config) { 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())); - } else { - return new AsyncHttpClient(new ApacheAsyncHttpProvider(config)); - } - } - public static AsyncHttpClient jdkProvider(AsyncHttpClientConfig config) { if (config == null) { return new AsyncHttpClient(new JDKAsyncHttpProvider(new AsyncHttpClientConfig.Builder().build())); From ba650c6f215c49c86468d7d44b1d6376001275cd Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 25 Sep 2014 11:53:50 +0200 Subject: [PATCH 633/701] Upgrade TestNG 6.8.8, get rid of transitive JUnit --- pom.xml | 3 +-- .../http/client/async/SimpleAsyncHttpClientTest.java | 11 +++++------ 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/pom.xml b/pom.xml index ad4bf1e4b6..a7f8c53b2f 100644 --- a/pom.xml +++ b/pom.xml @@ -126,9 +126,8 @@ org.testng testng - 5.8 + 6.8.8 test - jdk15 org.eclipse.jetty 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 fe75357297..b1af7ba928 100644 --- a/src/test/java/com/ning/http/client/async/SimpleAsyncHttpClientTest.java +++ b/src/test/java/com/ning/http/client/async/SimpleAsyncHttpClientTest.java @@ -14,9 +14,7 @@ import static java.nio.charset.StandardCharsets.*; -import static junit.framework.Assert.assertTrue; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.fail; +import static org.testng.Assert.*; import static org.testng.AssertJUnit.assertNotNull; import static org.testng.AssertJUnit.assertNotSame; @@ -220,11 +218,12 @@ public void onBytesReceived(Uri uri, long amount, long current, long total) { @Test(groups = { "standalone", "default_provider" }) public void testNullUrl() throws Exception { - SimpleAsyncHttpClient client = new SimpleAsyncHttpClient.Builder().setProviderClass(getProviderClass()).build().derive().build(); + SimpleAsyncHttpClient client = null; try { - assertTrue(true); + client = new SimpleAsyncHttpClient.Builder().setProviderClass(getProviderClass()).build().derive().build(); } finally { - client.close(); + if (client != null) + client.close(); } } From 4df8d035ba42c4cca92955613bea032f2957cbbd Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 25 Sep 2014 12:00:27 +0200 Subject: [PATCH 634/701] Exclude beanshell --- pom.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pom.xml b/pom.xml index a7f8c53b2f..caffa38820 100644 --- a/pom.xml +++ b/pom.xml @@ -128,6 +128,12 @@ testng 6.8.8 test + + + org.beanshell + bsh + + org.eclipse.jetty From 0e1d6da2a405fb881d18db05ff7dacc8aa9696a5 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 25 Sep 2014 14:22:55 +0200 Subject: [PATCH 635/701] Fix DefaultChannelPool.isTTLExpired, close #721 --- .../client/providers/netty/channel/pool/DefaultChannelPool.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/channel/pool/DefaultChannelPool.java b/src/main/java/com/ning/http/client/providers/netty/channel/pool/DefaultChannelPool.java index a0aa742c3a..4333b8bd2a 100644 --- a/src/main/java/com/ning/http/client/providers/netty/channel/pool/DefaultChannelPool.java +++ b/src/main/java/com/ning/http/client/providers/netty/channel/pool/DefaultChannelPool.java @@ -122,7 +122,7 @@ private boolean isTTLExpired(Channel channel, long now) { return false; ChannelCreation creation = channelId2Creation.get(channel.getId()); - return creation == null || now - creation.creationTime >= maxConnectionTTL; + return creation != null && now - creation.creationTime >= maxConnectionTTL; } private final class IdleChannelDetector implements TimerTask { From d7effb8709e28d76d0247481bbac81314c655e7b Mon Sep 17 00:00:00 2001 From: oleksiys Date: Thu, 25 Sep 2014 18:41:16 -0700 Subject: [PATCH 636/701] [1.9.x] update the compression enabling logic --- .../grizzly/GrizzlyAsyncHttpProvider.java | 22 +++++++++---------- 1 file changed, 11 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 a418ed9bd2..027147f403 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 @@ -385,12 +385,12 @@ public void onTimeout(Connection connection) { eventFilter.removeContentEncoding(encoding); } } - if (clientConfig.isCompressionEnforced()) { - eventFilter.addContentEncoding( - new GZipContentEncoding(512, - 512, - new ClientEncodingFilter())); - } + + eventFilter.addContentEncoding( + new GZipContentEncoding(512, + 512, + new ClientEncodingFilter())); + fcb.add(eventFilter); fcb.add(clientFilter); clientTransport.getAsyncQueueIO().getWriter() @@ -1043,7 +1043,10 @@ private void addHeaders(final Request request, requestPacket.addHeader(Header.UserAgent, config.getUserAgent()); } - + if (clientConfig.isCompressionEnforced() && + !headers.contains(Header.AcceptEncoding)) { + requestPacket.addHeader(Header.AcceptEncoding, "gzip"); + } } @@ -1760,10 +1763,7 @@ private static final class ClientEncodingFilter implements EncodingFilter { public boolean applyEncoding(HttpHeader httpPacket) { - - httpPacket.addHeader(Header.AcceptEncoding, "gzip"); - return false; - + return false; } From 57ea85a6424c36fd88d7b34c04dcd366d8ffe15e Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Sun, 28 Sep 2014 21:08:57 +0200 Subject: [PATCH 637/701] Add an option for not dropping Encoding response header, close #723 --- .../netty/NettyAsyncHttpProviderConfig.java | 10 ++++++++ .../netty/channel/ChannelManager.java | 25 ++++++++++++++----- 2 files changed, 29 insertions(+), 6 deletions(-) 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 5ca089d45d..4ae1af6f91 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 @@ -143,6 +143,8 @@ public Set> propertiesSet() { private int webSocketMaxFrameSize = 10 * 1024; + private boolean keepEncodingHeader = false; + public boolean isUseDeadLockChecker() { return useDeadLockChecker; } @@ -295,6 +297,14 @@ public void setWebSocketMaxFrameSize(int webSocketMaxFrameSize) { this.webSocketMaxFrameSize = webSocketMaxFrameSize; } + public boolean isKeepEncodingHeader() { + return keepEncodingHeader; + } + + public void setKeepEncodingHeader(boolean keepEncodingHeader) { + this.keepEncodingHeader = keepEncodingHeader; + } + public static interface NettyWebSocketFactory { NettyWebSocket newNettyWebSocket(Channel channel, NettyAsyncHttpProviderConfig nettyConfig); } diff --git a/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java b/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java index 90d209fda8..5fd4fb7cff 100644 --- a/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java +++ b/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java @@ -204,7 +204,7 @@ public void configureBootstraps(NettyRequestSender requestSender, AtomicBoolean public ChannelPipeline getPipeline() throws Exception { ChannelPipeline pipeline = pipeline(); pipeline.addLast(HTTP_HANDLER, newHttpClientCodec()); - pipeline.addLast(INFLATER_HANDLER, new HttpContentDecompressor()); + pipeline.addLast(INFLATER_HANDLER, newHttpContentDecompressor()); pipeline.addLast(CHUNKED_WRITER_HANDLER, new ChunkedWriteHandler()); pipeline.addLast(HTTP_PROCESSOR, httpProcessor); @@ -235,7 +235,7 @@ public ChannelPipeline getPipeline() throws Exception { ChannelPipeline pipeline = pipeline(); pipeline.addLast(SSL_HANDLER, new SslInitializer(ChannelManager.this)); pipeline.addLast(HTTP_HANDLER, newHttpClientCodec()); - pipeline.addLast(INFLATER_HANDLER, new HttpContentDecompressor()); + pipeline.addLast(INFLATER_HANDLER, newHttpContentDecompressor()); pipeline.addLast(CHUNKED_WRITER_HANDLER, new ChunkedWriteHandler()); pipeline.addLast(HTTP_PROCESSOR, httpProcessor); @@ -262,6 +262,18 @@ public ChannelPipeline getPipeline() throws Exception { }); } + private HttpContentDecompressor newHttpContentDecompressor() { + if (nettyConfig.isKeepEncodingHeader()) + return new HttpContentDecompressor() { + @Override + protected String getTargetContentEncoding(String contentEncoding) throws Exception { + return contentEncoding; + } + }; + else + return new HttpContentDecompressor(); + } + public final void tryToOfferChannelToPool(Channel channel, boolean keepAlive, String partition) { if (channel.isConnected() && keepAlive && channel.isReadable()) { LOGGER.debug("Adding key: {} for channel {}", partition, channel); @@ -388,14 +400,14 @@ public static SslHandler getSslHandler(ChannelPipeline pipeline) { public static boolean isSslHandlerConfigured(ChannelPipeline pipeline) { return pipeline.get(SSL_HANDLER) != null; } - + public void upgradeProtocol(ChannelPipeline pipeline, String scheme, String host, int port) throws IOException, GeneralSecurityException { if (pipeline.get(HTTP_HANDLER) != null) pipeline.remove(HTTP_HANDLER); if (isSecure(scheme)) - if (isSslHandlerConfigured(pipeline)){ + if (isSslHandlerConfigured(pipeline)) { pipeline.addAfter(SSL_HANDLER, HTTP_HANDLER, newHttpClientCodec()); } else { pipeline.addFirst(HTTP_HANDLER, newHttpClientCodec()); @@ -434,7 +446,8 @@ public ClientBootstrap getBootstrap(String scheme, boolean useProxy, boolean use public void upgradePipelineForWebSockets(ChannelPipeline pipeline) { pipeline.addAfter(HTTP_HANDLER, WS_ENCODER_HANDLER, new WebSocket08FrameEncoder(true)); pipeline.remove(HTTP_HANDLER); - pipeline.addBefore(WS_PROCESSOR, WS_DECODER_HANDLER, new WebSocket08FrameDecoder(false, false, nettyConfig.getWebSocketMaxFrameSize())); + pipeline.addBefore(WS_PROCESSOR, WS_DECODER_HANDLER, + new WebSocket08FrameDecoder(false, false, nettyConfig.getWebSocketMaxFrameSize())); pipeline.addAfter(WS_DECODER_HANDLER, WS_FRAME_AGGREGATOR, new WebSocketFrameAggregator(nettyConfig.getWebSocketMaxBufferSize())); } @@ -455,7 +468,7 @@ public void drainChannel(final Channel channel, final NettyResponseFuture fut public void flushPartition(String partitionId) { channelPool.flushPartition(partitionId); - } + } public void flushPartitions(ChannelPoolPartitionSelector selector) { channelPool.flushPartitions(selector); From 77eb6c2b82190b67460a3c992cfdb6b209c35288 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 29 Sep 2014 09:49:44 +0200 Subject: [PATCH 638/701] [maven-release-plugin] prepare release async-http-client-1.9.0-BETA16 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index caffa38820..99d3b182d4 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.9.0-SNAPSHOT + 1.9.0-BETA16 jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From 7cd6d942f332df3afb9487fbfaafd02ec5376055 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 29 Sep 2014 09:49:48 +0200 Subject: [PATCH 639/701] [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 99d3b182d4..caffa38820 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.9.0-BETA16 + 1.9.0-SNAPSHOT jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From bed229bba8f0769c31965ea7a9642b121144e3d9 Mon Sep 17 00:00:00 2001 From: Gerd Riesselmann Date: Mon, 29 Sep 2014 10:51:54 +0200 Subject: [PATCH 640/701] On exception abort Future, do not rethrow --- .../grizzly/GrizzlyAsyncHttpProvider.java | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 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 027147f403..a82eab4e9b 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 @@ -250,18 +250,29 @@ public void updated(final Connection c) { connectionManager.doAsyncTrackedConnection(request, future, connectHandler); } catch (Exception e) { if (e instanceof RuntimeException) { - throw (RuntimeException) e; + abort(future, e); } else if (e instanceof IOException) { - throw (IOException) e; - } - if (LOGGER.isWarnEnabled()) { - LOGGER.warn(e.toString(), e); + abort(future, e); + } else { + if (LOGGER.isWarnEnabled()) { + LOGGER.warn(e.toString(), e); + abort(future, e); + } } } return future; } + private void abort(GrizzlyResponseFuture future, Throwable t) { + if (!future.isDone()) { + LOGGER.debug("Aborting Future {}\n", future); + LOGGER.debug(t.getMessage(), t); + future.abort(t); + } + } + + @Override public void close() { From 8df96151fde641d19880125b73bf96f88a025399 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 30 Sep 2014 12:47:50 +0200 Subject: [PATCH 641/701] NTLM preemptive auth should only happen when sending the first request on a new connection, close #726 --- .../netty/request/NettyRequestFactory.java | 96 ++++++++++++------- .../netty/request/NettyRequestSender.java | 8 ++ 2 files changed, 70 insertions(+), 34 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestFactory.java b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestFactory.java index 1e2545536b..cc8bb08abd 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestFactory.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestFactory.java @@ -92,20 +92,11 @@ private String hostHeader(Request request, Uri uri) { return request.getVirtualHost() != null || uri.getPort() == -1 ? host : host + ":" + uri.getPort(); } - private String authorizationHeader(Request request, Uri uri, ProxyServer proxyServer, Realm realm) throws IOException { - + public String firstRequestOnlyAuthorizationHeader(Request request, Uri uri, ProxyServer proxyServer, Realm realm) throws IOException { String authorizationHeader = null; if (realm != null && realm.getUsePreemptiveAuth()) { - switch (realm.getAuthScheme()) { - case BASIC: - authorizationHeader = computeBasicAuthentication(realm); - break; - case DIGEST: - if (isNonEmpty(realm.getNonce())) - authorizationHeader = computeDigestAuthentication(realm); - break; case NTLM: String domain; if (proxyServer != null && proxyServer.getNtlmDomain() != null) { @@ -122,7 +113,6 @@ private String authorizationHeader(Request request, Uri uri, ProxyServer proxySe break; case KERBEROS: case SPNEGO: - String host; if (proxyServer != null) host = proxyServer.getHost(); @@ -137,6 +127,32 @@ else if (request.getVirtualHost() != null) throw new IOException(e); } break; + default: + break; + } + } + + return authorizationHeader; + } + + private String systematicAuthorizationHeader(Request request, Uri uri, ProxyServer proxyServer, Realm realm) { + + String authorizationHeader = null; + + if (realm != null && realm.getUsePreemptiveAuth()) { + + switch (realm.getAuthScheme()) { + case BASIC: + authorizationHeader = computeBasicAuthentication(realm); + break; + case DIGEST: + if (isNonEmpty(realm.getNonce())) + authorizationHeader = computeDigestAuthentication(realm); + break; + case NTLM: + case KERBEROS: + case SPNEGO: + // NTLM, KERBEROS and SPNEGO are only set on the first request, see firstRequestOnlyAuthorizationHeader case NONE: break; default: @@ -147,8 +163,7 @@ else if (request.getVirtualHost() != null) return authorizationHeader; } - private String proxyAuthorizationHeader(Request request, ProxyServer proxyServer, HttpMethod method) throws IOException { - + public String firstRequestOnlyProxyAuthorizationHeader(Request request, ProxyServer proxyServer, HttpMethod method) throws IOException { String proxyAuthorization = null; if (method == HttpMethod.CONNECT) { @@ -157,26 +172,31 @@ private String proxyAuthorizationHeader(Request request, ProxyServer proxyServer proxyAuthorization = auth.get(0); } - } else if (proxyServer != null && proxyServer.getPrincipal() != null) { - if (isNonEmpty(proxyServer.getNtlmDomain())) { - List auth = request.getHeaders().get(HttpHeaders.Names.PROXY_AUTHORIZATION); - if (!isNTLM(auth)) { - try { - String msg = NTLMEngine.INSTANCE.generateType1Msg(proxyServer.getNtlmDomain(), proxyServer.getHost()); - proxyAuthorization = "NTLM " + msg; - } catch (NTLMEngineException e) { - IOException ie = new IOException(); - ie.initCause(e); - throw ie; - } + } else if (proxyServer != null && proxyServer.getPrincipal() != null && isNonEmpty(proxyServer.getNtlmDomain())) { + List auth = request.getHeaders().get(HttpHeaders.Names.PROXY_AUTHORIZATION); + if (!isNTLM(auth)) { + try { + String msg = NTLMEngine.INSTANCE.generateType1Msg(proxyServer.getNtlmDomain(), proxyServer.getHost()); + proxyAuthorization = "NTLM " + msg; + } catch (NTLMEngineException e) { + throw new IOException(e); } - } else { - proxyAuthorization = computeBasicAuthentication(proxyServer); } } return proxyAuthorization; } + + private String systematicProxyAuthorizationHeader(Request request, ProxyServer proxyServer, HttpMethod method) { + + String proxyAuthorization = null; + + if (method != HttpMethod.CONNECT && proxyServer != null && proxyServer.getPrincipal() != null && !isNonEmpty(proxyServer.getNtlmDomain())) { + proxyAuthorization = computeBasicAuthentication(proxyServer); + } + + return proxyAuthorization; + } private byte[] computeBodyFromParams(List params, Charset bodyCharset) { @@ -235,6 +255,17 @@ else if (request.getBodyGenerator() != null) return nettyBody; } + public void addAuthorizationHeader(HttpHeaders headers, String authorizationHeader) { + if (authorizationHeader != null) + // don't override authorization but append + headers.add(HttpHeaders.Names.AUTHORIZATION, authorizationHeader); + } + + public void setProxyAuthorizationHeader(HttpHeaders headers, String proxyAuthorizationHeader) { + if (proxyAuthorizationHeader != null) + headers.set(HttpHeaders.Names.PROXY_AUTHORIZATION, proxyAuthorizationHeader); + } + public NettyRequest newNettyRequest(Request request, Uri uri, boolean forceConnect, ProxyServer proxyServer) throws IOException { @@ -301,14 +332,11 @@ public NettyRequest newNettyRequest(Request request, Uri uri, boolean forceConne headers.set(HttpHeaders.Names.HOST, hostHeader(request, uri)); Realm realm = request.getRealm() != null ? request.getRealm() : config.getRealm(); - String authorizationHeader = authorizationHeader(request, uri, proxyServer, realm); - if (authorizationHeader != null) - // don't override authorization but append - headers.add(HttpHeaders.Names.AUTHORIZATION, authorizationHeader); - String proxyAuthorizationHeader = proxyAuthorizationHeader(request, proxyServer, method); - if (proxyAuthorizationHeader != null) - headers.set(HttpHeaders.Names.PROXY_AUTHORIZATION, proxyAuthorizationHeader); + // don't override authorization but append + addAuthorizationHeader(headers, systematicAuthorizationHeader(request, uri, proxyServer, realm)); + + setProxyAuthorizationHeader(headers, systematicProxyAuthorizationHeader(request, proxyServer, method)); // Add default accept headers if (!headers.contains(HttpHeaders.Names.ACCEPT)) diff --git a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java index 3a5d1c93e8..0e65947a0b 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java @@ -39,6 +39,7 @@ import com.ning.http.client.FluentCaseInsensitiveStringsMap; import com.ning.http.client.ListenableFuture; import com.ning.http.client.ProxyServer; +import com.ning.http.client.Realm; import com.ning.http.client.Request; import com.ning.http.client.filter.FilterContext; import com.ning.http.client.filter.FilterException; @@ -243,6 +244,13 @@ private ListenableFuture sendRequestWithNewChannel(// boolean useSSl = isSecure(uri) && !useProxy; + // some headers are only set when performing the first request + HttpHeaders headers = future.getNettyRequest().getHttpRequest().headers(); + Realm realm = request.getRealm() != null ? request.getRealm() : config.getRealm(); + HttpMethod method = future.getNettyRequest().getHttpRequest().getMethod(); + requestFactory.addAuthorizationHeader(headers, requestFactory.firstRequestOnlyAuthorizationHeader(request, uri, proxy, realm)); + requestFactory.setProxyAuthorizationHeader(headers, requestFactory.firstRequestOnlyProxyAuthorizationHeader(request, proxy, method)); + // Do not throw an exception when we need an extra connection for a // redirect // FIXME why? This violate the max connection per host handling, right? From b142fa72cfd8eb4623ae14f3c71a36031525eceb Mon Sep 17 00:00:00 2001 From: oleksiys Date: Wed, 1 Oct 2014 13:17:56 -0700 Subject: [PATCH 642/701] [1.9.x] + fix GrizzlyConnectionPoolTest related to https://github.com/AsyncHttpClient/async-http-client/issues/720 --- .../grizzly/GrizzlyAsyncHttpProvider.java | 16 +++++++--------- .../async/grizzly/GrizzlyConnectionPoolTest.java | 11 ++++++----- 2 files changed, 13 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 a82eab4e9b..ebb368ffd6 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 @@ -248,17 +248,15 @@ public void updated(final Connection c) { try { connectionManager.doAsyncTrackedConnection(request, future, connectHandler); + } catch (IOException ioe) { + abort(future, ioe); + } catch (RuntimeException re) { + abort(future, re); } catch (Exception e) { - if (e instanceof RuntimeException) { - abort(future, e); - } else if (e instanceof IOException) { - abort(future, e); - } else { - if (LOGGER.isWarnEnabled()) { - LOGGER.warn(e.toString(), e); - abort(future, e); - } + if (LOGGER.isWarnEnabled()) { + LOGGER.warn(e.toString(), e); } + abort(future, e); } return future; 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 3593da4c0d..0a43e9da85 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012 Sonatype, Inc. All rights reserved. + * Copyright (c) 2012-2014 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. @@ -17,7 +17,6 @@ import static org.testng.Assert.assertNotNull; import static org.testng.Assert.fail; -import java.io.IOException; import java.util.concurrent.TimeUnit; import com.ning.http.client.ListenableFuture; @@ -28,6 +27,7 @@ import com.ning.http.client.Response; import com.ning.http.client.async.ConnectionPoolTest; import com.ning.http.client.async.ProviderUtil; +import java.util.concurrent.ExecutionException; public class GrizzlyConnectionPoolTest extends ConnectionPoolTest { @@ -50,9 +50,10 @@ public void testMaxTotalConnectionsException() { } try { client.prepareConnect(url).execute().get(); - } catch (IOException ioe) { - assertNotNull(ioe); - assertEquals("Max connections exceeded", ioe.getMessage()); + } catch (ExecutionException ee) { + final Throwable cause = ee.getCause(); + assertNotNull(cause); + assertEquals("Max connections exceeded", cause.getMessage()); } catch (Exception e) { fail("Unexpected exception thrown.", e); } From 40234b06fd13ab776319bd49e16da4f836b40de1 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 1 Oct 2014 22:24:35 +0200 Subject: [PATCH 643/701] Fix NTLM, close #730 --- src/main/java/com/ning/http/client/Realm.java | 15 - .../com/ning/http/client/ntlm/NTLMEngine.java | 946 +++++++++++------- .../providers/netty/handler/HttpProtocol.java | 28 +- .../netty/request/NettyRequestFactory.java | 2 +- .../netty/request/NettyRequestSender.java | 2 +- .../com/ning/http/client/async/NTLMTest.java | 104 ++ .../client/async/netty/NettyNTLMTest.java | 30 + 7 files changed, 724 insertions(+), 403 deletions(-) create mode 100644 src/test/java/com/ning/http/client/async/NTLMTest.java create mode 100644 src/test/java/com/ning/http/client/async/netty/NettyNTLMTest.java diff --git a/src/main/java/com/ning/http/client/Realm.java b/src/main/java/com/ning/http/client/Realm.java index a072d78f1b..4eb6227d1d 100644 --- a/src/main/java/com/ning/http/client/Realm.java +++ b/src/main/java/com/ning/http/client/Realm.java @@ -50,7 +50,6 @@ public class Realm { private final boolean usePreemptiveAuth; private final Charset charset; private final String host; - private final boolean messageType2Received; private final boolean useAbsoluteURI; private final boolean omitQuery; private final boolean targetProxy; @@ -82,7 +81,6 @@ private Realm(AuthScheme scheme, String ntlmDomain, Charset charset, String host, - boolean messageType2Received, String opaque, boolean useAbsoluteURI, boolean omitQuery, @@ -105,7 +103,6 @@ private Realm(AuthScheme scheme, this.ntlmDomain = ntlmDomain; this.charset = charset; this.host = host; - this.messageType2Received = messageType2Received; this.useAbsoluteURI = useAbsoluteURI; this.omitQuery = omitQuery; this.targetProxy = targetProxy; @@ -199,10 +196,6 @@ public String getNtlmHost() { return host; } - public boolean isNtlmMessageType2Received() { - return messageType2Received; - } - public boolean isUseAbsoluteURI() { return useAbsoluteURI; } @@ -302,7 +295,6 @@ public static class RealmBuilder { private String ntlmDomain = System.getProperty("http.auth.ntlm.domain", ""); private Charset charset = UTF_8; private String host = "localhost"; - private boolean messageType2Received = false; private boolean useAbsoluteURI = true; private boolean omitQuery = false; private boolean targetProxy = false; @@ -501,11 +493,6 @@ public RealmBuilder parseProxyAuthenticateHeader(String headerLine) { return this; } - public RealmBuilder setNtlmMessageType2Received(boolean messageType2Received) { - this.messageType2Received = messageType2Received; - return this; - } - public RealmBuilder clone(Realm clone) { setRealmName(clone.getRealmName()); setAlgorithm(clone.getAlgorithm()); @@ -522,7 +509,6 @@ public RealmBuilder clone(Realm clone) { setUsePreemptiveAuth(clone.getUsePreemptiveAuth()); setNtlmDomain(clone.getNtlmDomain()); setNtlmHost(clone.getNtlmHost()); - setNtlmMessageType2Received(clone.isNtlmMessageType2Received()); setUseAbsoluteURI(clone.isUseAbsoluteURI()); setOmitQuery(clone.isOmitQuery()); setTargetProxy(clone.isTargetProxy()); @@ -676,7 +662,6 @@ public Realm build() { ntlmDomain, charset, host, - messageType2Received, opaque, useAbsoluteURI, omitQuery, 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 502e874790..912aa7ba1b 100644 --- a/src/main/java/com/ning/http/client/ntlm/NTLMEngine.java +++ b/src/main/java/com/ning/http/client/ntlm/NTLMEngine.java @@ -26,14 +26,14 @@ package com.ning.http.client.ntlm; -import static com.ning.http.util.MiscUtils.isNonEmpty; +import static java.nio.charset.StandardCharsets.US_ASCII; import com.ning.http.util.Base64; import javax.crypto.Cipher; import javax.crypto.spec.SecretKeySpec; -import java.io.UnsupportedEncodingException; +import java.nio.charset.StandardCharsets; import java.security.Key; import java.security.MessageDigest; import java.util.Arrays; @@ -45,117 +45,64 @@ * * @since 4.1 */ -public class NTLMEngine { - - // Flags we use - protected final static int FLAG_UNICODE_ENCODING = 0x00000001; - protected final static int FLAG_TARGET_DESIRED = 0x00000004; - protected final static int FLAG_NEGOTIATE_SIGN = 0x00000010; - protected final static int FLAG_NEGOTIATE_SEAL = 0x00000020; - protected final static int FLAG_NEGOTIATE_NTLM = 0x00000200; - protected final static int FLAG_NEGOTIATE_ALWAYS_SIGN = 0x00008000; - protected final static int FLAG_NEGOTIATE_NTLM2 = 0x00080000; - protected final static int FLAG_NEGOTIATE_128 = 0x20000000; - protected final static int FLAG_NEGOTIATE_KEY_EXCH = 0x40000000; +public final class NTLMEngine { - /** - * Secure random generator - */ + public static final NTLMEngine INSTANCE = new NTLMEngine(); + + // Flags we use; descriptions according to: + // http://davenport.sourceforge.net/ntlm.html + // and + // http://msdn.microsoft.com/en-us/library/cc236650%28v=prot.20%29.aspx + protected final static int FLAG_REQUEST_UNICODE_ENCODING = 0x00000001; // Unicode string encoding requested + protected final static int FLAG_REQUEST_TARGET = 0x00000004; // Requests target field + protected final static int FLAG_REQUEST_SIGN = 0x00000010; // Requests all messages have a signature attached, in NEGOTIATE message. + protected final static int FLAG_REQUEST_SEAL = 0x00000020; // Request key exchange for message confidentiality in NEGOTIATE message. MUST be used in conjunction with 56BIT. + protected final static int FLAG_REQUEST_LAN_MANAGER_KEY = 0x00000080; // Request Lan Manager key instead of user session key + protected final static int FLAG_REQUEST_NTLMv1 = 0x00000200; // Request NTLMv1 security. MUST be set in NEGOTIATE and CHALLENGE both + protected final static int FLAG_DOMAIN_PRESENT = 0x00001000; // Domain is present in message + protected final static int FLAG_WORKSTATION_PRESENT = 0x00002000; // Workstation is present in message + protected final static int FLAG_REQUEST_ALWAYS_SIGN = 0x00008000; // Requests a signature block on all messages. Overridden by REQUEST_SIGN and REQUEST_SEAL. + protected final static int FLAG_REQUEST_NTLM2_SESSION = 0x00080000; // From server in challenge, requesting NTLM2 session security + protected final static int FLAG_REQUEST_VERSION = 0x02000000; // Request protocol version + protected final static int FLAG_TARGETINFO_PRESENT = 0x00800000; // From server in challenge message, indicating targetinfo is present + protected final static int FLAG_REQUEST_128BIT_KEY_EXCH = 0x20000000; // Request explicit 128-bit key exchange + protected final static int FLAG_REQUEST_EXPLICIT_KEY_EXCH = 0x40000000; // Request explicit key exchange + protected final static int FLAG_REQUEST_56BIT_ENCRYPTION = 0x80000000; // Must be used in conjunction with SEAL + + /** Secure random generator */ private static final java.security.SecureRandom RND_GEN; - static { java.security.SecureRandom rnd = null; try { rnd = java.security.SecureRandom.getInstance("SHA1PRNG"); - } catch (Exception ignored) { + } catch (Exception e) { } RND_GEN = rnd; } - /** - * Character encoding - */ - static final String DEFAULT_CHARSET = "ASCII"; - - /** - * The character set to use for encoding the credentials - */ - private String credentialCharset = DEFAULT_CHARSET; - - /** - * The signature string as bytes in the default encoding - */ + /** The signature string as bytes in the default encoding */ private static byte[] SIGNATURE; static { - byte[] bytesWithoutNull = new byte[0]; - try { - bytesWithoutNull = "NTLMSSP".getBytes("ASCII"); - } catch (UnsupportedEncodingException e) { - e.printStackTrace(); - } + byte[] bytesWithoutNull = "NTLMSSP".getBytes(US_ASCII); SIGNATURE = new byte[bytesWithoutNull.length + 1]; System.arraycopy(bytesWithoutNull, 0, SIGNATURE, 0, bytesWithoutNull.length); SIGNATURE[bytesWithoutNull.length] = (byte) 0x00; } - public static final NTLMEngine INSTANCE = new NTLMEngine(); - - private static byte[] getUnicodeLittleUnmarkedBytes(String s) throws NTLMEngineException { - try { - return s.getBytes("UnicodeLittleUnmarked"); - } catch (UnsupportedEncodingException e) { - throw new NTLMEngineException("UnicodeLittleUnmarked not supported! " + e.getMessage(), e); - } - } - - private static String fromUnicodeLittleUnmarkedBytes(byte[] bytes) throws NTLMEngineException { - try { - return new String(bytes, "UnicodeLittleUnmarked"); - } catch (UnsupportedEncodingException e) { - throw new NTLMEngineException(e.getMessage(), e); - } - } - - /** - * Returns the response for the given message. - * - * @param message the message that was received from the server. - * @param username the username to authenticate with. - * @param password the password to authenticate with. - * @param host The host. - * @param domain the NT domain to authenticate in. - * @return The response. - * @throws NTLMEngineException If the messages cannot be retrieved. - */ - final String getResponseFor(String message, String username, String password, String host, String domain) throws NTLMEngineException { - - final String response; - 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; - } - /** * Creates the first message (type 1 message) in the NTLM authentication * sequence. This message includes the user name, domain and host for the * authentication session. * - * @param host the computer name of the host requesting authentication. - * @param domain The domain to authenticate with. + * @param host + * the computer name of the host requesting authentication. + * @param domain + * The domain to authenticate with. * @return String the message to add to the HTTP request header. */ String getType1Message(String host, String domain) throws NTLMEngineException { - try { - return new Type1Message(domain, host).getResponse(); - } catch (UnsupportedEncodingException e) { - throw new NTLMEngineException("Unsupported encoding", e); - } + return new Type1Message(domain, host).getResponse(); } /** @@ -164,57 +111,39 @@ String getType1Message(String host, String domain) throws NTLMEngineException { * username and the result of encrypting the nonce sent by the server using * the user's password as the key. * - * @param user The user name. This should not include the domain name. - * @param password The password. - * @param host The host that is originating the authentication request. - * @param domain The domain to authenticate within. - * @param nonce the 8 byte array the server sent. + * @param user + * The user name. This should not include the domain name. + * @param password + * The password. + * @param host + * The host that is originating the authentication request. + * @param domain + * The domain to authenticate within. + * @param nonce + * the 8 byte array the server sent. * @return The type 3 message. - * @throws NTLMEngineException If {@encrypt(byte[],byte[])} fails. + * @throws NTLMEngineException + * If {@encrypt(byte[],byte[])} fails. */ String getType3Message(String user, String password, String host, String domain, byte[] nonce, int type2Flags, String target, byte[] targetInformation) throws NTLMEngineException { - try { - return new Type3Message(domain, host, user, password, nonce, type2Flags, target, targetInformation).getResponse(); - } catch (UnsupportedEncodingException e) { - throw new NTLMEngineException("Unsupported encoding", e); - } - } - - /** - * @return Returns the credentialCharset. - */ - String getCredentialCharset() { - return credentialCharset; + return new Type3Message(domain, host, user, password, nonce, type2Flags, target, targetInformation).getResponse(); } - /** - * @param credentialCharset The credentialCharset to set. - */ - void setCredentialCharset(String credentialCharset) { - this.credentialCharset = credentialCharset; - } - - /** - * Strip dot suffix from a name - */ + /** Strip dot suffix from a name */ private static String stripDotSuffix(String value) { - int index = value.indexOf("."); + int index = value.indexOf('.'); if (index != -1) return value.substring(0, index); return value; } - /** - * Convert host to standard form - */ + /** Convert host to standard form */ private static String convertHost(String host) { return stripDotSuffix(host); } - /** - * Convert domain to standard form - */ + /** Convert domain to standard form */ private static String convertDomain(String domain) { return stripDotSuffix(domain); } @@ -241,9 +170,7 @@ private static byte[] readSecurityBuffer(byte[] src, int index) throws NTLMEngin return buffer; } - /** - * Calculate a challenge block - */ + /** Calculate a challenge block */ private static byte[] makeRandomChallenge() throws NTLMEngineException { if (RND_GEN == null) { throw new NTLMEngineException("Random generator not available"); @@ -255,100 +182,283 @@ private static byte[] makeRandomChallenge() throws NTLMEngineException { return rval; } - /** - * Calculate an NTLM2 challenge block - */ - private static byte[] makeNTLM2RandomChallenge() throws NTLMEngineException { + /** Calculate a 16-byte secondary key */ + private static byte[] makeSecondaryKey() throws NTLMEngineException { if (RND_GEN == null) { throw new NTLMEngineException("Random generator not available"); } - byte[] rval = new byte[24]; + byte[] rval = new byte[16]; synchronized (RND_GEN) { RND_GEN.nextBytes(rval); } - // 8-byte challenge, padded with zeros to 24 bytes. - Arrays.fill(rval, 8, 24, (byte) 0x00); return rval; } - /** - * Calculates the LM Response for the given challenge, using the specified - * password. - * - * @param password The user's password. - * @param challenge The Type 2 challenge from the server. - * @return The LM Response. - */ - static byte[] getLMResponse(String password, byte[] challenge) throws NTLMEngineException { - byte[] lmHash = lmHash(password); - return lmResponse(lmHash, challenge); - } + protected static class CipherGen { + + protected final String target; + protected final String user; + protected final String password; + protected final byte[] challenge; + protected final byte[] targetInformation; + + // Information we can generate but may be passed in (for testing) + protected byte[] clientChallenge; + protected byte[] secondaryKey; + protected byte[] timestamp; + + // Stuff we always generate + protected byte[] lmHash = null; + protected byte[] lmResponse = null; + protected byte[] ntlmHash = null; + protected byte[] ntlmResponse = null; + protected byte[] ntlmv2Hash = null; + protected byte[] lmv2Response = null; + protected byte[] ntlmv2Blob = null; + protected byte[] ntlmv2Response = null; + protected byte[] ntlm2SessionResponse = null; + protected byte[] lm2SessionResponse = null; + protected byte[] lmUserSessionKey = null; + protected byte[] ntlmUserSessionKey = null; + protected byte[] ntlmv2UserSessionKey = null; + protected byte[] ntlm2SessionResponseUserSessionKey = null; + protected byte[] lanManagerSessionKey = null; + + public CipherGen(String target, String user, String password, byte[] challenge, byte[] targetInformation, byte[] clientChallenge, + byte[] secondaryKey, byte[] timestamp) { + this.target = target; + this.user = user; + this.password = password; + this.challenge = challenge; + this.targetInformation = targetInformation; + this.clientChallenge = clientChallenge; + this.secondaryKey = secondaryKey; + this.timestamp = timestamp; + } - /** - * Calculates the NTLM Response for the given challenge, using the specified - * password. - * - * @param password The user's password. - * @param challenge The Type 2 challenge from the server. - * @return The NTLM Response. - */ - static byte[] getNTLMResponse(String password, byte[] challenge) throws NTLMEngineException { - byte[] ntlmHash = ntlmHash(password); - return lmResponse(ntlmHash, challenge); + public CipherGen(String target, String user, String password, byte[] challenge, byte[] targetInformation) { + this(target, user, password, challenge, targetInformation, null, null, null); + } + + /** Calculate and return client challenge */ + public byte[] getClientChallenge() throws NTLMEngineException { + if (clientChallenge == null) + clientChallenge = makeRandomChallenge(); + return clientChallenge; + } + + /** Calculate and return random secondary key */ + public byte[] getSecondaryKey() throws NTLMEngineException { + if (secondaryKey == null) + secondaryKey = makeSecondaryKey(); + return secondaryKey; + } + + /** Calculate and return the LMHash */ + public byte[] getLMHash() throws NTLMEngineException { + if (lmHash == null) + lmHash = lmHash(password); + return lmHash; + } + + /** Calculate and return the LMResponse */ + public byte[] getLMResponse() throws NTLMEngineException { + if (lmResponse == null) + lmResponse = lmResponse(getLMHash(), challenge); + return lmResponse; + } + + /** Calculate and return the NTLMHash */ + public byte[] getNTLMHash() throws NTLMEngineException { + if (ntlmHash == null) + ntlmHash = ntlmHash(password); + return ntlmHash; + } + + /** Calculate and return the NTLMResponse */ + public byte[] getNTLMResponse() throws NTLMEngineException { + if (ntlmResponse == null) + ntlmResponse = lmResponse(getNTLMHash(), challenge); + return ntlmResponse; + } + + /** Calculate the NTLMv2 hash */ + public byte[] getNTLMv2Hash() throws NTLMEngineException { + if (ntlmv2Hash == null) + ntlmv2Hash = ntlmv2Hash(target, user, password); + return ntlmv2Hash; + } + + /** Calculate a timestamp */ + public byte[] getTimestamp() { + if (timestamp == null) { + long time = System.currentTimeMillis(); + time += 11644473600000l; // milliseconds from January 1, 1601 -> epoch. + time *= 10000; // tenths of a microsecond. + // convert to little-endian byte array. + timestamp = new byte[8]; + for (int i = 0; i < 8; i++) { + timestamp[i] = (byte) time; + time >>>= 8; + } + } + return timestamp; + } + + /** Calculate the NTLMv2Blob */ + public byte[] getNTLMv2Blob() throws NTLMEngineException { + if (ntlmv2Blob == null) + ntlmv2Blob = createBlob(getClientChallenge(), targetInformation, getTimestamp()); + return ntlmv2Blob; + } + + /** Calculate the NTLMv2Response */ + public byte[] getNTLMv2Response() throws NTLMEngineException { + if (ntlmv2Response == null) + ntlmv2Response = lmv2Response(getNTLMv2Hash(), challenge, getNTLMv2Blob()); + return ntlmv2Response; + } + + /** Calculate the LMv2Response */ + public byte[] getLMv2Response() throws NTLMEngineException { + if (lmv2Response == null) + lmv2Response = lmv2Response(getNTLMv2Hash(), challenge, getClientChallenge()); + return lmv2Response; + } + + /** Get NTLM2SessionResponse */ + public byte[] getNTLM2SessionResponse() throws NTLMEngineException { + if (ntlm2SessionResponse == null) + ntlm2SessionResponse = ntlm2SessionResponse(getNTLMHash(), challenge, getClientChallenge()); + return ntlm2SessionResponse; + } + + /** Calculate and return LM2 session response */ + public byte[] getLM2SessionResponse() throws NTLMEngineException { + if (lm2SessionResponse == null) { + byte[] clientChallenge = getClientChallenge(); + lm2SessionResponse = new byte[24]; + System.arraycopy(clientChallenge, 0, lm2SessionResponse, 0, clientChallenge.length); + Arrays.fill(lm2SessionResponse, clientChallenge.length, lm2SessionResponse.length, (byte) 0x00); + } + return lm2SessionResponse; + } + + /** Get LMUserSessionKey */ + public byte[] getLMUserSessionKey() throws NTLMEngineException { + if (lmUserSessionKey == null) { + byte[] lmHash = getLMHash(); + lmUserSessionKey = new byte[16]; + System.arraycopy(lmHash, 0, lmUserSessionKey, 0, 8); + Arrays.fill(lmUserSessionKey, 8, 16, (byte) 0x00); + } + return lmUserSessionKey; + } + + /** Get NTLMUserSessionKey */ + public byte[] getNTLMUserSessionKey() throws NTLMEngineException { + if (ntlmUserSessionKey == null) { + byte[] ntlmHash = getNTLMHash(); + MD4 md4 = new MD4(); + md4.update(ntlmHash); + ntlmUserSessionKey = md4.getOutput(); + } + return ntlmUserSessionKey; + } + + /** GetNTLMv2UserSessionKey */ + public byte[] getNTLMv2UserSessionKey() throws NTLMEngineException { + if (ntlmv2UserSessionKey == null) { + byte[] ntlmv2Hash = getNTLMv2Hash(); + byte[] ntlmv2Blob = getNTLMv2Blob(); + byte[] temp = new byte[ntlmv2Blob.length + challenge.length]; + // "The challenge is concatenated with the blob" - check this (MHL) + System.arraycopy(challenge, 0, temp, 0, challenge.length); + System.arraycopy(ntlmv2Blob, 0, temp, challenge.length, ntlmv2Blob.length); + byte[] partial = hmacMD5(temp, ntlmv2Hash); + ntlmv2UserSessionKey = hmacMD5(partial, ntlmv2Hash); + } + return ntlmv2UserSessionKey; + } + + /** Get NTLM2SessionResponseUserSessionKey */ + public byte[] getNTLM2SessionResponseUserSessionKey() throws NTLMEngineException { + if (ntlm2SessionResponseUserSessionKey == null) { + byte[] ntlmUserSessionKey = getNTLMUserSessionKey(); + byte[] ntlm2SessionResponseNonce = getLM2SessionResponse(); + byte[] sessionNonce = new byte[challenge.length + ntlm2SessionResponseNonce.length]; + System.arraycopy(challenge, 0, sessionNonce, 0, challenge.length); + System.arraycopy(ntlm2SessionResponseNonce, 0, sessionNonce, challenge.length, ntlm2SessionResponseNonce.length); + ntlm2SessionResponseUserSessionKey = hmacMD5(sessionNonce, ntlmUserSessionKey); + } + return ntlm2SessionResponseUserSessionKey; + } + + /** Get LAN Manager session key */ + public byte[] getLanManagerSessionKey() throws NTLMEngineException { + if (lanManagerSessionKey == null) { + byte[] lmHash = getLMHash(); + byte[] lmResponse = getLMResponse(); + try { + byte[] keyBytes = new byte[14]; + System.arraycopy(lmHash, 0, keyBytes, 0, 8); + Arrays.fill(keyBytes, 8, keyBytes.length, (byte) 0xbd); + Key lowKey = createDESKey(keyBytes, 0); + Key highKey = createDESKey(keyBytes, 7); + byte[] truncatedResponse = new byte[8]; + System.arraycopy(lmResponse, 0, truncatedResponse, 0, truncatedResponse.length); + Cipher des = Cipher.getInstance("DES/ECB/NoPadding"); + des.init(Cipher.ENCRYPT_MODE, lowKey); + byte[] lowPart = des.doFinal(truncatedResponse); + des = Cipher.getInstance("DES/ECB/NoPadding"); + des.init(Cipher.ENCRYPT_MODE, highKey); + byte[] highPart = des.doFinal(truncatedResponse); + lanManagerSessionKey = new byte[16]; + System.arraycopy(lowPart, 0, lanManagerSessionKey, 0, lowPart.length); + System.arraycopy(highPart, 0, lanManagerSessionKey, lowPart.length, highPart.length); + } catch (Exception e) { + throw new NTLMEngineException(e.getMessage(), e); + } + } + return lanManagerSessionKey; + } } - /** - * Calculates the NTLMv2 Response for the given challenge, using the - * specified authentication target, username, password, target information - * block, and client challenge. - * - * @param target The authentication target (i.e., domain). - * @param user The username. - * @param password The user's password. - * @param targetInformation The target information block from the Type 2 message. - * @param challenge The Type 2 challenge from the server. - * @param clientChallenge The random 8-byte client challenge. - * @return The NTLMv2 Response. - */ - static byte[] getNTLMv2Response(String target, String user, String password, byte[] challenge, byte[] clientChallenge, - byte[] targetInformation) throws NTLMEngineException { - byte[] ntlmv2Hash = ntlmv2Hash(target, user, password); - byte[] blob = createBlob(clientChallenge, targetInformation); - return lmv2Response(ntlmv2Hash, challenge, blob); + /** Calculates HMAC-MD5 */ + static byte[] hmacMD5(byte[] value, byte[] key) throws NTLMEngineException { + HMACMD5 hmacMD5 = new HMACMD5(key); + hmacMD5.update(value); + return hmacMD5.getOutput(); } - /** - * Calculates the LMv2 Response for the given challenge, using the specified - * authentication target, username, password, and client challenge. - * - * @param target The authentication target (i.e., domain). - * @param user The username. - * @param password The user's password. - * @param challenge The Type 2 challenge from the server. - * @param clientChallenge The random 8-byte client challenge. - * @return The LMv2 Response. - */ - static byte[] getLMv2Response(String target, String user, String password, byte[] challenge, byte[] clientChallenge) - throws NTLMEngineException { - byte[] ntlmv2Hash = ntlmv2Hash(target, user, password); - return lmv2Response(ntlmv2Hash, challenge, clientChallenge); + /** Calculates RC4 */ + static byte[] RC4(byte[] value, byte[] key) throws NTLMEngineException { + try { + Cipher rc4 = Cipher.getInstance("RC4"); + rc4.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "RC4")); + return rc4.doFinal(value); + } catch (Exception e) { + throw new NTLMEngineException(e.getMessage(), e); + } } /** * Calculates the NTLM2 Session Response for the given challenge, using the * specified password and client challenge. * - * @param password The user's password. - * @param challenge The Type 2 challenge from the server. - * @param clientChallenge The random 8-byte client challenge. + * @param password + * The user's password. + * @param challenge + * The Type 2 challenge from the server. + * @param clientChallenge + * The random 8-byte client challenge. + * * @return The NTLM2 Session Response. This is placed in the NTLM response * field of the Type 3 message; the LM response field contains the * client challenge, null-padded to 24 bytes. */ - static byte[] getNTLM2SessionResponse(String password, byte[] challenge, byte[] clientChallenge) throws NTLMEngineException { + static byte[] ntlm2SessionResponse(byte[] ntlmHash, byte[] challenge, byte[] clientChallenge) throws NTLMEngineException { try { - byte[] ntlmHash = ntlmHash(password); - // Look up MD5 algorithm (was necessary on jdk 1.4.2) // This used to be needed, but java 1.5.0_07 includes the MD5 // algorithm (finally) @@ -380,13 +490,15 @@ static byte[] getNTLM2SessionResponse(String password, byte[] challenge, byte[] /** * Creates the LM Hash of the user's password. * - * @param password The password. + * @param password + * The password. + * * @return The LM Hash of the given password, used in the calculation of the * LM Response. */ private static byte[] lmHash(String password) throws NTLMEngineException { try { - byte[] oemPassword = password.toUpperCase(Locale.ENGLISH).getBytes("US-ASCII"); + byte[] oemPassword = password.toUpperCase(Locale.US).getBytes(StandardCharsets.US_ASCII); int length = Math.min(oemPassword.length, 14); byte[] keyBytes = new byte[14]; System.arraycopy(oemPassword, 0, keyBytes, 0, length); @@ -410,40 +522,57 @@ private static byte[] lmHash(String password) throws NTLMEngineException { /** * Creates the NTLM Hash of the user's password. * - * @param password The password. + * @param password + * The password. + * * @return The NTLM Hash of the given password, used in the calculation of * the NTLM Response and the NTLMv2 and LMv2 Hashes. */ private static byte[] ntlmHash(String password) throws NTLMEngineException { - byte[] unicodePassword = getUnicodeLittleUnmarkedBytes(password); - MD4 md4 = new MD4(); - md4.update(unicodePassword); - return md4.getOutput(); + try { + byte[] unicodePassword = password.getBytes("UnicodeLittleUnmarked"); + MD4 md4 = new MD4(); + md4.update(unicodePassword); + return md4.getOutput(); + } catch (java.io.UnsupportedEncodingException e) { + throw new NTLMEngineException("Unicode not supported: " + e.getMessage(), e); + } } /** * Creates the NTLMv2 Hash of the user's password. * - * @param target The authentication target (i.e., domain). - * @param user The username. - * @param password The password. + * @param target + * The authentication target (i.e., domain). + * @param user + * The username. + * @param password + * The password. + * * @return The NTLMv2 Hash, used in the calculation of the NTLMv2 and LMv2 * Responses. */ private static byte[] ntlmv2Hash(String target, String user, String password) throws NTLMEngineException { - byte[] ntlmHash = ntlmHash(password); - HMACMD5 hmacMD5 = new HMACMD5(ntlmHash); - // Upper case username, mixed case target!! - hmacMD5.update(getUnicodeLittleUnmarkedBytes(user.toUpperCase(Locale.ENGLISH))); - hmacMD5.update(getUnicodeLittleUnmarkedBytes(target)); - return hmacMD5.getOutput(); + try { + byte[] ntlmHash = ntlmHash(password); + HMACMD5 hmacMD5 = new HMACMD5(ntlmHash); + // Upper case username, mixed case target!! + hmacMD5.update(user.toUpperCase(Locale.US).getBytes("UnicodeLittleUnmarked")); + hmacMD5.update(target.getBytes("UnicodeLittleUnmarked")); + return hmacMD5.getOutput(); + } catch (java.io.UnsupportedEncodingException e) { + throw new NTLMEngineException("Unicode not supported! " + e.getMessage(), e); + } } /** * Creates the LM Response from the given hash and Type 2 challenge. * - * @param hash The LM or NTLM Hash. - * @param challenge The server challenge from the Type 2 message. + * @param hash + * The LM or NTLM Hash. + * @param challenge + * The server challenge from the Type 2 message. + * * @return The response (either LM or NTLM, depending on the provided hash). */ private static byte[] lmResponse(byte[] hash, byte[] challenge) throws NTLMEngineException { @@ -474,9 +603,13 @@ private static byte[] lmResponse(byte[] hash, byte[] challenge) throws NTLMEngin * Creates the LMv2 Response from the given hash, client data, and Type 2 * challenge. * - * @param hash The NTLMv2 Hash. - * @param clientData The client data (blob or client challenge). - * @param challenge The server challenge from the Type 2 message. + * @param hash + * The NTLMv2 Hash. + * @param clientData + * The client data (blob or client challenge). + * @param challenge + * The server challenge from the Type 2 message. + * * @return The response (either NTLMv2 or LMv2, depending on the client * data). */ @@ -495,24 +628,20 @@ private static byte[] lmv2Response(byte[] hash, byte[] challenge, byte[] clientD * Creates the NTLMv2 blob from the given target information block and * client challenge. * - * @param targetInformation The target information block from the Type 2 message. - * @param clientChallenge The random 8-byte client challenge. + * @param targetInformation + * The target information block from the Type 2 message. + * @param clientChallenge + * The random 8-byte client challenge. + * * @return The blob, used in the calculation of the NTLMv2 Response. */ - private static byte[] createBlob(byte[] clientChallenge, byte[] targetInformation) { + private static byte[] createBlob(byte[] clientChallenge, byte[] targetInformation, byte[] timestamp) { 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(); - time += 11644473600000l; // milliseconds from January 1, 1601 -> epoch. - time *= 10000; // tenths of a microsecond. - // convert to little-endian byte array. - byte[] timestamp = new byte[8]; - for (int i = 0; i < 8; i++) { - timestamp[i] = (byte) time; - time >>>= 8; - } - byte[] blob = new byte[blobSignature.length + reserved.length + timestamp.length + 8 + unknown1.length + targetInformation.length]; + byte[] unknown2 = new byte[] { (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00 }; + byte[] blob = new byte[blobSignature.length + reserved.length + timestamp.length + 8 + unknown1.length + targetInformation.length + + unknown2.length]; int offset = 0; System.arraycopy(blobSignature, 0, blob, offset, blobSignature.length); offset += blobSignature.length; @@ -525,15 +654,21 @@ private static byte[] createBlob(byte[] clientChallenge, byte[] targetInformatio System.arraycopy(unknown1, 0, blob, offset, unknown1.length); offset += unknown1.length; System.arraycopy(targetInformation, 0, blob, offset, targetInformation.length); + offset += targetInformation.length; + System.arraycopy(unknown2, 0, blob, offset, unknown2.length); + offset += unknown2.length; return blob; } /** * Creates a DES encryption key from the given key material. * - * @param bytes A byte array containing the DES key material. - * @param offset The offset in the given byte array at which the 7-byte key - * material starts. + * @param bytes + * A byte array containing the DES key material. + * @param offset + * The offset in the given byte array at which the 7-byte key + * material starts. + * * @return A DES encryption key created from the key material starting at * the specified offset in the given byte array. */ @@ -556,7 +691,8 @@ private static Key createDESKey(byte[] bytes, int offset) { /** * Applies odd parity to the given byte array. * - * @param bytes The data whose parity bits are to be adjusted for odd parity. + * @param bytes + * The data whose parity bits are to be adjusted for odd parity. */ private static void oddParity(byte[] bytes) { for (int i = 0; i < bytes.length; i++) { @@ -570,32 +706,21 @@ private static void oddParity(byte[] bytes) { } } - /** - * NTLM message generation, base class - */ + /** NTLM message generation, base class */ static class NTLMMessage { - /** - * The current response - */ + /** The current response */ private byte[] messageContents = null; - /** - * The current output position - */ + /** The current output position */ private int currentOutputPosition = 0; - /** - * Constructor to use when message contents are not yet known - */ + /** Constructor to use when message contents are not yet known */ NTLMMessage() { } - /** - * Constructor to use when message contents are known - */ + /** Constructor to use when message contents are known */ NTLMMessage(String messageBody, int expectedType) throws NTLMEngineException { messageContents = Base64.decode(messageBody); - // Look for NTLM message if (messageContents.length < SIGNATURE.length) throw new NTLMEngineException("NTLM message decoding error - packet too short"); @@ -623,48 +748,36 @@ protected int getPreambleLength() { return SIGNATURE.length + 4; } - /** - * Get the message length - */ + /** Get the message length */ protected int getMessageLength() { return currentOutputPosition; } - /** - * Read a byte from a position within the message buffer - */ + /** Read a byte from a position within the message buffer */ protected byte readByte(int position) throws NTLMEngineException { if (messageContents.length < position + 1) throw new NTLMEngineException("NTLM: Message too short"); return messageContents[position]; } - /** - * Read a bunch of bytes from a position in the message buffer - */ + /** Read a bunch of bytes from a position in the message buffer */ protected void readBytes(byte[] buffer, int position) throws NTLMEngineException { if (messageContents.length < position + buffer.length) throw new NTLMEngineException("NTLM: Message too short"); System.arraycopy(messageContents, position, buffer, 0, buffer.length); } - /** - * Read a ushort from a position within the message buffer - */ + /** Read a ushort from a position within the message buffer */ protected int readUShort(int position) throws NTLMEngineException { return NTLMEngine.readUShort(messageContents, position); } - /** - * Read a ulong from a position within the message buffer - */ + /** Read a ulong from a position within the message buffer */ protected int readULong(int position) throws NTLMEngineException { return NTLMEngine.readULong(messageContents, position); } - /** - * Read a security buffer from a position within the message buffer - */ + /** Read a security buffer from a position within the message buffer */ protected byte[] readSecurityBuffer(int position) throws NTLMEngineException { return NTLMEngine.readSecurityBuffer(messageContents, position); } @@ -672,9 +785,10 @@ protected byte[] readSecurityBuffer(int position) throws NTLMEngineException { /** * Prepares the object to create a response of the given length. * - * @param maxlength the maximum length of the response to prepare, not - * including the type and the signature (which this method - * adds). + * @param length + * the maximum length of the response to prepare, not + * including the type and the signature (which this method + * adds). */ protected void prepareResponse(int maxlength, int messageType) { messageContents = new byte[maxlength]; @@ -686,7 +800,8 @@ protected void prepareResponse(int maxlength, int messageType) { /** * Adds the given byte to the response. * - * @param b the byte to add. + * @param b + * the byte to add. */ protected void addByte(byte b) { messageContents[currentOutputPosition] = b; @@ -696,26 +811,23 @@ protected void addByte(byte b) { /** * Adds the given bytes to the response. * - * @param bytes the bytes to add. + * @param bytes + * the bytes to add. */ protected void addBytes(byte[] bytes) { - for (int i = 0; i < bytes.length; i++) { - messageContents[currentOutputPosition] = bytes[i]; + for (byte b : bytes) { + messageContents[currentOutputPosition] = b; currentOutputPosition++; } } - /** - * Adds a USHORT to the response - */ + /** Adds a USHORT to the response */ protected void addUShort(int value) { addByte((byte) (value & 0xff)); addByte((byte) (value >> 8 & 0xff)); } - /** - * Adds a ULong to the response - */ + /** Adds a ULong to the response */ protected void addULong(int value) { addByte((byte) (value & 0xff)); addByte((byte) (value >> 8 & 0xff)); @@ -729,7 +841,7 @@ protected void addULong(int value) { * * @return The response as above. */ - String getResponse() throws UnsupportedEncodingException { + String getResponse() { byte[] resp; if (messageContents.length > currentOutputPosition) { byte[] tmp = new byte[currentOutputPosition]; @@ -745,24 +857,26 @@ String getResponse() throws UnsupportedEncodingException { } - /** - * Type 1 message assembly class - */ + /** Type 1 message assembly class */ static class Type1Message extends NTLMMessage { protected byte[] hostBytes; protected byte[] domainBytes; - /** - * Constructor. Include the arguments the message will need - */ + /** Constructor. Include the arguments the message will need */ Type1Message(String domain, String host) throws NTLMEngineException { - // Strip off domain name from the host! - host = convertHost(host); - // Use only the base domain name! - domain = convertDomain(domain); - - hostBytes = getUnicodeLittleUnmarkedBytes(host); - domainBytes = getUnicodeLittleUnmarkedBytes(domain.toUpperCase(Locale.ENGLISH)); + super(); + try { + // Strip off domain name from the host! + host = convertHost(host); + // Use only the base domain name! + domain = convertDomain(domain); + + // FIXME should host be uppercased? + hostBytes = host.getBytes("UnicodeLittleUnmarked"); + domainBytes = domain.toUpperCase(Locale.US).getBytes("UnicodeLittleUnmarked"); + } catch (java.io.UnsupportedEncodingException e) { + throw new NTLMEngineException("Unicode unsupported: " + e.getMessage(), e); + } } /** @@ -770,50 +884,69 @@ static class Type1Message extends NTLMMessage { * it */ @Override - String getResponse() throws UnsupportedEncodingException { + String getResponse() { // Now, build the message. Calculate its length first, including // signature or type. - int finalLength = 32 + hostBytes.length + domainBytes.length; + int finalLength = 32 + 8 /*+ hostBytes.length + domainBytes.length */; // Set up the response. This will initialize the signature, message // type, and flags. prepareResponse(finalLength, 1); // Flags. These are the complete set of flags we support. - addULong(FLAG_NEGOTIATE_NTLM | FLAG_NEGOTIATE_NTLM2 | FLAG_NEGOTIATE_SIGN | FLAG_NEGOTIATE_SEAL | - /* - * FLAG_NEGOTIATE_ALWAYS_SIGN | FLAG_NEGOTIATE_KEY_EXCH | - */ - FLAG_UNICODE_ENCODING | FLAG_TARGET_DESIRED | FLAG_NEGOTIATE_128); + addULong( + //FLAG_WORKSTATION_PRESENT | + //FLAG_DOMAIN_PRESENT | + + // Required flags + FLAG_REQUEST_LAN_MANAGER_KEY | FLAG_REQUEST_NTLMv1 | FLAG_REQUEST_NTLM2_SESSION | + + // Protocol version request + FLAG_REQUEST_VERSION | + + // Recommended privacy settings + FLAG_REQUEST_ALWAYS_SIGN | + //FLAG_REQUEST_SEAL | + FLAG_REQUEST_SIGN | + + // These must be set according to documentation, based on use of SEAL above + FLAG_REQUEST_128BIT_KEY_EXCH | FLAG_REQUEST_56BIT_ENCRYPTION | FLAG_REQUEST_EXPLICIT_KEY_EXCH | + + FLAG_REQUEST_UNICODE_ENCODING); // Domain length (two times). - addUShort(domainBytes.length); - addUShort(domainBytes.length); + addUShort(/*domainBytes.length*/0); + addUShort(/*domainBytes.length*/0); // Domain offset. - addULong(hostBytes.length + 32); + addULong(/*hostBytes.length +*/32 + 8); // Host length (two times). - addUShort(hostBytes.length); - addUShort(hostBytes.length); + addUShort(/*hostBytes.length*/0); + addUShort(/*hostBytes.length*/0); - // Host offset (always 32). - addULong(32); + // Host offset (always 32 + 8). + addULong(32 + 8); - // Host String. - addBytes(hostBytes); + // Version + addUShort(0x0105); + // Build + addULong(2600); + // NTLM revision + addUShort(0x0f00); + + // Host (workstation) String. + //addBytes(hostBytes); // Domain String. - addBytes(domainBytes); + //addBytes(domainBytes); return super.getResponse(); } } - /** - * Type 2 message class - */ + /** Type 2 message class */ static class Type2Message extends NTLMMessage { protected byte[] challenge; protected String target; @@ -823,14 +956,29 @@ static class Type2Message extends NTLMMessage { Type2Message(String message) throws NTLMEngineException { super(message, 2); + // Type 2 message is laid out as follows: + // First 8 bytes: NTLMSSP[0] + // Next 4 bytes: Ulong, value 2 + // Next 8 bytes, starting at offset 12: target field (2 ushort lengths, 1 ulong offset) + // Next 4 bytes, starting at offset 20: Flags, e.g. 0x22890235 + // Next 8 bytes, starting at offset 24: Challenge + // Next 8 bytes, starting at offset 32: ??? (8 bytes of zeros) + // Next 8 bytes, starting at offset 40: targetinfo field (2 ushort lengths, 1 ulong offset) + // Next 2 bytes, major/minor version number (e.g. 0x05 0x02) + // Next 8 bytes, build number + // Next 2 bytes, protocol version number (e.g. 0x00 0x0f) + // Next, various text fields, and a ushort of value 0 at the end + // Parse out the rest of the info we need from the message // The nonce is the 8 bytes starting from the byte in position 24. challenge = new byte[8]; readBytes(challenge, 24); flags = readULong(20); - if ((flags & FLAG_UNICODE_ENCODING) == 0) + + if ((flags & FLAG_REQUEST_UNICODE_ENCODING) == 0) throw new NTLMEngineException("NTLM type 2 message has flags that make no sense: " + Integer.toString(flags)); + // Do the target! target = null; // The TARGET_DESIRED flag is said to not have understood semantics @@ -839,7 +987,11 @@ static class Type2Message extends NTLMMessage { if (getMessageLength() >= 12 + 8) { byte[] bytes = readSecurityBuffer(12); if (bytes.length != 0) { - target = fromUnicodeLittleUnmarkedBytes(bytes); + try { + target = new String(bytes, "UnicodeLittleUnmarked"); + } catch (java.io.UnsupportedEncodingException e) { + throw new NTLMEngineException(e.getMessage(), e); + } } } @@ -854,39 +1006,29 @@ static class Type2Message extends NTLMMessage { } } - /** - * Retrieve the challenge - */ + /** Retrieve the challenge */ byte[] getChallenge() { return challenge; } - /** - * Retrieve the target - */ + /** Retrieve the target */ String getTarget() { return target; } - /** - * Retrieve the target info - */ + /** Retrieve the target info */ byte[] getTargetInfo() { return targetInfo; } - /** - * Retrieve the response flags - */ + /** Retrieve the response flags */ int getFlags() { return flags; } } - /** - * Type 3 message assembly class - */ + /** Type 3 message assembly class */ static class Type3Message extends NTLMMessage { // Response flags from the type2 message protected int type2Flags; @@ -897,10 +1039,9 @@ static class Type3Message extends NTLMMessage { protected byte[] lmResp; protected byte[] ntResp; + protected byte[] sessionKey; - /** - * Constructor. Pass the arguments we will need - */ + /** Constructor. Pass the arguments we will need */ Type3Message(String domain, String host, String user, String password, byte[] nonce, int type2Flags, String target, byte[] targetInformation) throws NTLMEngineException { // Save the flags @@ -911,61 +1052,94 @@ static class Type3Message extends NTLMMessage { // Use only the base domain name! domain = convertDomain(domain); + // Create a cipher generator class + CipherGen gen = new CipherGen(target, user, password, nonce, targetInformation); + // Use the new code to calculate the responses, including v2 if that // seems warranted. + byte[] userSessionKey; try { - if (targetInformation != null && target != null) { - byte[] clientChallenge = makeRandomChallenge(); - ntResp = getNTLMv2Response(target, user, password, nonce, clientChallenge, targetInformation); - lmResp = getLMv2Response(target, user, password, nonce, clientChallenge); + // This conditional may not work on Windows Server 2008 R2 and above, where it has not yet + // been tested + if (((type2Flags & FLAG_TARGETINFO_PRESENT) != 0) && targetInformation != null && target != null) { + // NTLMv2 + ntResp = gen.getNTLMv2Response(); + lmResp = gen.getLMv2Response(); + if ((type2Flags & FLAG_REQUEST_LAN_MANAGER_KEY) != 0) + userSessionKey = gen.getLanManagerSessionKey(); + else + userSessionKey = gen.getNTLMv2UserSessionKey(); } else { - if ((type2Flags & FLAG_NEGOTIATE_NTLM2) != 0) { + // NTLMv1 + if ((type2Flags & FLAG_REQUEST_NTLM2_SESSION) != 0) { // NTLM2 session stuff is requested - byte[] clientChallenge = makeNTLM2RandomChallenge(); - - ntResp = getNTLM2SessionResponse(password, nonce, clientChallenge); - lmResp = clientChallenge; - + ntResp = gen.getNTLM2SessionResponse(); + lmResp = gen.getLM2SessionResponse(); + if ((type2Flags & FLAG_REQUEST_LAN_MANAGER_KEY) != 0) + userSessionKey = gen.getLanManagerSessionKey(); + else + userSessionKey = gen.getNTLM2SessionResponseUserSessionKey(); // All the other flags we send (signing, sealing, key // exchange) are supported, but they don't do anything // at all in an // NTLM2 context! So we're done at this point. } else { - ntResp = getNTLMResponse(password, nonce); - lmResp = getLMResponse(password, nonce); + ntResp = gen.getNTLMResponse(); + lmResp = gen.getLMResponse(); + if ((type2Flags & FLAG_REQUEST_LAN_MANAGER_KEY) != 0) + userSessionKey = gen.getLanManagerSessionKey(); + else + userSessionKey = gen.getNTLMUserSessionKey(); } } } catch (NTLMEngineException e) { // This likely means we couldn't find the MD4 hash algorithm - // fail back to just using LM ntResp = new byte[0]; - lmResp = getLMResponse(password, nonce); + lmResp = gen.getLMResponse(); + if ((type2Flags & FLAG_REQUEST_LAN_MANAGER_KEY) != 0) + userSessionKey = gen.getLanManagerSessionKey(); + else + userSessionKey = gen.getLMUserSessionKey(); } - domainBytes = getUnicodeLittleUnmarkedBytes(domain.toUpperCase(Locale.ENGLISH)); - hostBytes = getUnicodeLittleUnmarkedBytes(host); - userBytes = getUnicodeLittleUnmarkedBytes(user); + if ((type2Flags & FLAG_REQUEST_EXPLICIT_KEY_EXCH) != 0) + sessionKey = RC4(gen.getSecondaryKey(), userSessionKey); + else + sessionKey = null; + + try { + domainBytes = domain.toUpperCase(Locale.US).getBytes("UnicodeLittleUnmarked"); + hostBytes = host.getBytes("UnicodeLittleUnmarked"); + userBytes = user.getBytes("UnicodeLittleUnmarked"); + } catch (java.io.UnsupportedEncodingException e) { + throw new NTLMEngineException("Unicode not supported: " + e.getMessage(), e); + } } - /** - * Assemble the response - */ + /** Assemble the response */ @Override - String getResponse() throws UnsupportedEncodingException { + String getResponse() { int ntRespLen = ntResp.length; int lmRespLen = lmResp.length; int domainLen = domainBytes.length; int hostLen = hostBytes.length; int userLen = userBytes.length; + int sessionKeyLen; + if (sessionKey != null) + sessionKeyLen = sessionKey.length; + else + sessionKeyLen = 0; // Calculate the layout within the packet - int lmRespOffset = 64; + int lmRespOffset = 72; // allocate space for the version int ntRespOffset = lmRespOffset + lmRespLen; int domainOffset = ntRespOffset + ntRespLen; int userOffset = domainOffset + domainLen; int hostOffset = userOffset + userLen; - int finalLength = hostOffset + hostLen; + int sessionKeyOffset = hostOffset + hostLen; + int finalLength = sessionKeyOffset + sessionKeyLen; // Start the response. Length includes signature and type prepareResponse(finalLength, 3); @@ -1005,17 +1179,47 @@ String getResponse() throws UnsupportedEncodingException { // Host offset addULong(hostOffset); - // 4 bytes of zeros - not sure what this is - addULong(0); + // Session key length (twice) + addUShort(sessionKeyLen); + addUShort(sessionKeyLen); - // Message length - addULong(finalLength); + // Session key offset + addULong(sessionKeyOffset); - // Flags. Currently: NEGOTIATE_NTLM + UNICODE_ENCODING + + // Flags. Currently: WORKSTATION_PRESENT + DOMAIN_PRESENT + UNICODE_ENCODING + // TARGET_DESIRED + NEGOTIATE_128 - addULong(FLAG_NEGOTIATE_NTLM | FLAG_UNICODE_ENCODING | FLAG_TARGET_DESIRED | FLAG_NEGOTIATE_128 - | (type2Flags & FLAG_NEGOTIATE_NTLM2) | (type2Flags & FLAG_NEGOTIATE_SIGN) | (type2Flags & FLAG_NEGOTIATE_SEAL) - | (type2Flags & FLAG_NEGOTIATE_KEY_EXCH) | (type2Flags & FLAG_NEGOTIATE_ALWAYS_SIGN)); + addULong(FLAG_WORKSTATION_PRESENT + | FLAG_DOMAIN_PRESENT + | + + // Required flags + (type2Flags & FLAG_REQUEST_LAN_MANAGER_KEY) + | (type2Flags & FLAG_REQUEST_NTLMv1) + | (type2Flags & FLAG_REQUEST_NTLM2_SESSION) + | + + // Protocol version request + FLAG_REQUEST_VERSION + | + + // Recommended privacy settings + (type2Flags & FLAG_REQUEST_ALWAYS_SIGN) | (type2Flags & FLAG_REQUEST_SEAL) + | (type2Flags & FLAG_REQUEST_SIGN) + | + + // These must be set according to documentation, based on use of SEAL above + (type2Flags & FLAG_REQUEST_128BIT_KEY_EXCH) | (type2Flags & FLAG_REQUEST_56BIT_ENCRYPTION) + | (type2Flags & FLAG_REQUEST_EXPLICIT_KEY_EXCH) | + + (type2Flags & FLAG_TARGETINFO_PRESENT) | (type2Flags & FLAG_REQUEST_UNICODE_ENCODING) + | (type2Flags & FLAG_REQUEST_TARGET)); + + // Version + addUShort(0x0105); + // Build + addULong(2600); + // NTLM revision + addUShort(0x0f00); // Add the actual data addBytes(lmResp); @@ -1023,6 +1227,8 @@ String getResponse() throws UnsupportedEncodingException { addBytes(domainBytes); addBytes(userBytes); addBytes(hostBytes); + if (sessionKey != null) + addBytes(sessionKey); return super.getResponse(); } @@ -1093,6 +1299,7 @@ void update(byte[] input) { int transferAmt = input.length - inputIndex; System.arraycopy(input, inputIndex, dataBuffer, curBufferPos, transferAmt); count += transferAmt; + curBufferPos += transferAmt; } } @@ -1263,29 +1470,22 @@ static class HMACMD5 { } - /** - * Grab the current digest. This is the "answer". - */ + /** Grab the current digest. This is the "answer". */ byte[] getOutput() { byte[] digest = md5.digest(); md5.update(opad); return md5.digest(digest); } - /** - * Update by adding a complete array - */ + /** Update by adding a complete array */ void update(byte[] input) { md5.update(input); } - /** - * Update the algorithm - */ + /** Update the algorithm */ void update(byte[] input, int offset, int length) { md5.update(input, offset, length); } - } public String generateType1Msg(final String domain, final String workstation) throws NTLMEngineException { diff --git a/src/main/java/com/ning/http/client/providers/netty/handler/HttpProtocol.java b/src/main/java/com/ning/http/client/providers/netty/handler/HttpProtocol.java index cf443dd686..b7a5d2f11e 100644 --- a/src/main/java/com/ning/http/client/providers/netty/handler/HttpProtocol.java +++ b/src/main/java/com/ning/http/client/providers/netty/handler/HttpProtocol.java @@ -91,7 +91,7 @@ private Realm kerberosChallenge(Channel channel,// } catch (Throwable throwable) { if (isNTLM(proxyAuth)) { - return ntlmChallenge(proxyAuth, request, proxyServer, headers, realm, future, proxyInd); + return ntlmChallenge(proxyAuth.get(0), request, proxyServer, headers, realm, future, proxyInd); } requestSender.abort(channel, future, throwable); return null; @@ -106,7 +106,7 @@ private void addNTLMAuthorizationHeader(FluentCaseInsensitiveStringsMap headers, headers.add(authorizationHeaderName(proxyInd), "NTLM " + challengeHeader); } - private Realm ntlmChallenge(List wwwAuth, Request request, ProxyServer proxyServer, FluentCaseInsensitiveStringsMap headers, + private Realm ntlmChallenge(String wwwAuth, Request request, ProxyServer proxyServer, FluentCaseInsensitiveStringsMap headers, Realm realm, NettyResponseFuture future, boolean proxyInd) throws NTLMEngineException { boolean useRealm = proxyServer == null && realm != null; @@ -117,7 +117,8 @@ private Realm ntlmChallenge(List wwwAuth, Request request, ProxyServer p String password = useRealm ? realm.getPassword() : proxyServer.getPassword(); Uri uri = request.getUri(); - if (realm != null && !realm.isNtlmMessageType2Received()) { + if (wwwAuth.equals("NTLM")) { + // server replied bare NTLM => we didn't preemptively sent Type1Msg String challengeHeader = NTLMEngine.INSTANCE.generateType1Msg(ntlmDomain, ntlmHost); addNTLMAuthorizationHeader(headers, challengeHeader, proxyInd); @@ -126,10 +127,10 @@ private Realm ntlmChallenge(List wwwAuth, Request request, ProxyServer p .setScheme(realm.getAuthScheme())// .setUri(uri)// .setMethodName(request.getMethod())// - .setNtlmMessageType2Received(true)// .build(); } else { + // probably receiving Type2Msg, so we issue Type3Msg addType3NTLMAuthorizationHeader(wwwAuth, headers, principal, password, ntlmDomain, ntlmHost, proxyInd); Realm.AuthScheme authScheme = realm != null ? realm.getAuthScheme() : Realm.AuthScheme.NTLM; return newRealmBuilder(realm)// @@ -140,7 +141,7 @@ private Realm ntlmChallenge(List wwwAuth, Request request, ProxyServer p } } - private Realm ntlmProxyChallenge(List wwwAuth, Request request, ProxyServer proxyServer, + private Realm ntlmProxyChallenge(String wwwAuth, Request request, ProxyServer proxyServer, FluentCaseInsensitiveStringsMap headers, Realm realm, NettyResponseFuture future, boolean proxyInd) throws NTLMEngineException { future.getAndSetAuth(false); @@ -155,12 +156,12 @@ private Realm ntlmProxyChallenge(List wwwAuth, Request request, ProxySer .setMethodName(request.getMethod()).build(); } - private void addType3NTLMAuthorizationHeader(List auth, FluentCaseInsensitiveStringsMap headers, String username, + private void addType3NTLMAuthorizationHeader(String auth, FluentCaseInsensitiveStringsMap headers, String username, String password, String domain, String workstation, boolean proxyInd) throws NTLMEngineException { headers.remove(authorizationHeaderName(proxyInd)); - if (isNonEmpty(auth) && auth.get(0).startsWith("NTLM ")) { - String serverChallenge = auth.get(0).trim().substring("NTLM ".length()); + if (isNonEmpty(auth) && auth.startsWith("NTLM ")) { + String serverChallenge = auth.substring("NTLM ".length()).trim(); String challengeHeader = NTLMEngine.INSTANCE.generateType3Msg(username, password, domain, workstation, serverChallenge); addNTLMAuthorizationHeader(headers, challengeHeader, proxyInd); } @@ -215,15 +216,14 @@ private boolean exitAfterHandling401(// if (!wwwAuthHeaders.isEmpty()) { future.setState(NettyResponseFuture.STATE.NEW); Realm newRealm = null; - FluentCaseInsensitiveStringsMap requestHeaders = request.getHeaders(); boolean negociate = wwwAuthHeaders.contains("Negotiate"); if (!wwwAuthHeaders.contains("Kerberos") && (isNTLM(wwwAuthHeaders) || negociate)) { // NTLM - newRealm = ntlmChallenge(wwwAuthHeaders, request, proxyServer, requestHeaders, realm, future, false); + newRealm = ntlmChallenge(wwwAuthHeaders.get(0), request, proxyServer, request.getHeaders(), realm, future, false); } else if (negociate) { // SPNEGO KERBEROS - newRealm = kerberosChallenge(channel, wwwAuthHeaders, request, proxyServer, requestHeaders, realm, future, false); + newRealm = kerberosChallenge(channel, wwwAuthHeaders, request, proxyServer, request.getHeaders(), realm, future, false); if (newRealm == null) return true; @@ -239,12 +239,14 @@ private boolean exitAfterHandling401(// } Realm nr = newRealm; - final Request nextRequest = new RequestBuilder(future.getRequest()).setHeaders(requestHeaders).setRealm(nr).build(); + final Request nextRequest = new RequestBuilder(future.getRequest()).setHeaders(request.getHeaders()).setRealm(nr).build(); logger.debug("Sending authentication to {}", request.getUri()); Callback callback = new Callback(future) { public void call() throws IOException { channelManager.drainChannel(channel, future); + // don't forget to reuse channel: NTLM authenticates a connection + future.setReuseChannel(true); requestSender.sendNextRequest(nextRequest, future); } }; @@ -298,7 +300,7 @@ private boolean exitAfterHandling407(// boolean negociate = proxyAuthHeaders.contains("Negotiate"); if (!proxyAuthHeaders.contains("Kerberos") && (isNTLM(proxyAuthHeaders) || negociate)) { - newRealm = ntlmProxyChallenge(proxyAuthHeaders, request, proxyServer, requestHeaders, realm, future, true); + newRealm = ntlmProxyChallenge(proxyAuthHeaders.get(0), request, proxyServer, requestHeaders, realm, future, true); // SPNEGO KERBEROS } else if (negociate) { newRealm = kerberosChallenge(channel, proxyAuthHeaders, request, proxyServer, requestHeaders, realm, future, true); diff --git a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestFactory.java b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestFactory.java index cc8bb08abd..8da344ed4a 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestFactory.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestFactory.java @@ -105,7 +105,7 @@ public String firstRequestOnlyAuthorizationHeader(Request request, Uri uri, Prox domain = realm.getNtlmDomain(); } try { - String msg = NTLMEngine.INSTANCE.generateType1Msg("NTLM " + domain, realm.getNtlmHost()); + String msg = NTLMEngine.INSTANCE.generateType1Msg(domain, realm.getNtlmHost()); authorizationHeader = "NTLM " + msg; } catch (NTLMEngineException e) { throw new IOException(e); diff --git a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java index 0e65947a0b..5468b6f899 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java @@ -206,7 +206,7 @@ private ListenableFuture sendRequestWithCachedChannel(Request request, Ur future.setState(NettyResponseFuture.STATE.POOLED); future.attachChannel(channel, false); - LOGGER.debug("\nUsing cached Channel {}\n for request \n{}\n", channel, future.getNettyRequest().getHttpRequest()); + LOGGER.debug("Using cached Channel {}\n for request \n{}\n", channel, future.getNettyRequest().getHttpRequest()); Channels.setAttribute(channel, future); try { diff --git a/src/test/java/com/ning/http/client/async/NTLMTest.java b/src/test/java/com/ning/http/client/async/NTLMTest.java new file mode 100644 index 0000000000..01211aa38f --- /dev/null +++ b/src/test/java/com/ning/http/client/async/NTLMTest.java @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2014 AsyncHttpClient Project. 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; + +import org.eclipse.jetty.server.handler.AbstractHandler; +import org.testng.Assert; +import org.testng.annotations.Test; + +import com.ning.http.client.AsyncHttpClient; +import com.ning.http.client.AsyncHttpClientConfig; +import com.ning.http.client.Realm; +import com.ning.http.client.Realm.AuthScheme; +import com.ning.http.client.Realm.RealmBuilder; +import com.ning.http.client.Request; +import com.ning.http.client.RequestBuilder; +import com.ning.http.client.Response; + +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; + +public abstract class NTLMTest extends AbstractBasicTest { + + public static class NTLMHandler extends AbstractHandler { + + @Override + public void handle(String pathInContext, org.eclipse.jetty.server.Request request, HttpServletRequest httpRequest, + HttpServletResponse httpResponse) throws IOException, ServletException { + + String authorization = httpRequest.getHeader("Authorization"); + if (authorization == null) { + httpResponse.setStatus(401); + httpResponse.setHeader("WWW-Authenticate", "NTLM"); + + } else if (authorization.equals("NTLM TlRMTVNTUAABAAAAkYII4gAAAAAoAAAAAAAAACgAAAAFASgKAAAADw==")) { + httpResponse.setStatus(401); + httpResponse.setHeader("WWW-Authenticate", "NTLM TlRMTVNTUAACAAAAAAAAACgAAAABggAAU3J2Tm9uY2UAAAAAAAAAAA=="); + + } else if (authorization + .equals("NTLM TlRMTVNTUAADAAAAGAAYAEgAAAAYABgAYAAAABQAFAB4AAAADAAMAIwAAAASABIAmAAAAAAAAACqAAAAAbIAAgUBKAoAAAAPrYfKbe/jRoW5xDxHeoxC1gBmfWiS5+iX4OAN4xBKG/IFPwfH3agtPEia6YnhsADTVQBSAFMAQQAtAE0ASQBOAE8AUgBaAGEAcABoAG8AZABMAGkAZwBoAHQAQwBpAHQAeQA=")) { + httpResponse.setStatus(200); + } else { + httpResponse.setStatus(401); + } + + httpResponse.getOutputStream().flush(); + httpResponse.getOutputStream().close(); + } + } + + @Override + public AbstractHandler configureHandler() throws Exception { + return new NTLMHandler(); + } + + private RealmBuilder realmBuilderBase() { + return new Realm.RealmBuilder()// + .setScheme(AuthScheme.NTLM)// + .setNtlmDomain("Ursa-Minor")// + .setNtlmHost("LightCity")// + .setPrincipal("Zaphod")// + .setPassword("Beeblebrox"); + } + + private void ntlmAuthTest(RealmBuilder realmBuilder) throws IOException, InterruptedException, ExecutionException { + + AsyncHttpClientConfig config = new AsyncHttpClientConfig.Builder().setRealm(realmBuilder.build()).build(); + + AsyncHttpClient client = getAsyncHttpClient(config); + try { + Request request = new RequestBuilder("GET").setUrl(getTargetUrl()).build(); + Future responseFuture = client.executeRequest(request); + int status = responseFuture.get().getStatusCode(); + Assert.assertEquals(status, 200); + } finally { + client.close(); + } + } + + @Test + public void lazyNTLMAuthTest() throws IOException, InterruptedException, ExecutionException { + ntlmAuthTest(realmBuilderBase()); + } + + @Test + public void preemptiveNTLMAuthTest() throws IOException, InterruptedException, ExecutionException { + ntlmAuthTest(realmBuilderBase().setUsePreemptiveAuth(true)); + } +} diff --git a/src/test/java/com/ning/http/client/async/netty/NettyNTLMTest.java b/src/test/java/com/ning/http/client/async/netty/NettyNTLMTest.java new file mode 100644 index 0000000000..1bef41a5b4 --- /dev/null +++ b/src/test/java/com/ning/http/client/async/netty/NettyNTLMTest.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2014 AsyncHttpClient Project. 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 org.testng.annotations.Test; + +import com.ning.http.client.AsyncHttpClient; +import com.ning.http.client.AsyncHttpClientConfig; +import com.ning.http.client.async.NTLMTest; +import com.ning.http.client.async.ProviderUtil; + +@Test +public class NettyNTLMTest extends NTLMTest { + + @Override + public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { + return ProviderUtil.nettyProvider(config); + } +} From 83d5db04e345e2f12d9940683c5dbdb9cb70eb58 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 2 Oct 2014 12:00:46 +0200 Subject: [PATCH 644/701] Upgrade NTLMEngine 4.3.5 --- .../com/ning/http/client/ntlm/NTLMEngine.java | 840 ++++++++++-------- .../com/ning/http/client/async/NTLMTest.java | 4 +- 2 files changed, 496 insertions(+), 348 deletions(-) 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 912aa7ba1b..6436e2b47d 100644 --- a/src/main/java/com/ning/http/client/ntlm/NTLMEngine.java +++ b/src/main/java/com/ning/http/client/ntlm/NTLMEngine.java @@ -1,20 +1,21 @@ /* * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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 * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF 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 * - * 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. + * 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. * ==================================================================== * * This software consists of voluntary contributions made by many @@ -23,16 +24,14 @@ * . * */ - package com.ning.http.client.ntlm; -import static java.nio.charset.StandardCharsets.US_ASCII; - import com.ning.http.util.Base64; import javax.crypto.Cipher; import javax.crypto.spec.SecretKeySpec; +import java.io.UnsupportedEncodingException; import java.nio.charset.StandardCharsets; import java.security.Key; import java.security.MessageDigest; @@ -48,26 +47,27 @@ public final class NTLMEngine { public static final NTLMEngine INSTANCE = new NTLMEngine(); - + // Flags we use; descriptions according to: // http://davenport.sourceforge.net/ntlm.html // and // http://msdn.microsoft.com/en-us/library/cc236650%28v=prot.20%29.aspx - protected final static int FLAG_REQUEST_UNICODE_ENCODING = 0x00000001; // Unicode string encoding requested - protected final static int FLAG_REQUEST_TARGET = 0x00000004; // Requests target field - protected final static int FLAG_REQUEST_SIGN = 0x00000010; // Requests all messages have a signature attached, in NEGOTIATE message. - protected final static int FLAG_REQUEST_SEAL = 0x00000020; // Request key exchange for message confidentiality in NEGOTIATE message. MUST be used in conjunction with 56BIT. - protected final static int FLAG_REQUEST_LAN_MANAGER_KEY = 0x00000080; // Request Lan Manager key instead of user session key - protected final static int FLAG_REQUEST_NTLMv1 = 0x00000200; // Request NTLMv1 security. MUST be set in NEGOTIATE and CHALLENGE both - protected final static int FLAG_DOMAIN_PRESENT = 0x00001000; // Domain is present in message - protected final static int FLAG_WORKSTATION_PRESENT = 0x00002000; // Workstation is present in message - protected final static int FLAG_REQUEST_ALWAYS_SIGN = 0x00008000; // Requests a signature block on all messages. Overridden by REQUEST_SIGN and REQUEST_SEAL. - protected final static int FLAG_REQUEST_NTLM2_SESSION = 0x00080000; // From server in challenge, requesting NTLM2 session security - protected final static int FLAG_REQUEST_VERSION = 0x02000000; // Request protocol version - protected final static int FLAG_TARGETINFO_PRESENT = 0x00800000; // From server in challenge message, indicating targetinfo is present - protected final static int FLAG_REQUEST_128BIT_KEY_EXCH = 0x20000000; // Request explicit 128-bit key exchange - protected final static int FLAG_REQUEST_EXPLICIT_KEY_EXCH = 0x40000000; // Request explicit key exchange - protected final static int FLAG_REQUEST_56BIT_ENCRYPTION = 0x80000000; // Must be used in conjunction with SEAL + protected static final int FLAG_REQUEST_UNICODE_ENCODING = 0x00000001; // Unicode string encoding requested + protected static final int FLAG_REQUEST_TARGET = 0x00000004; // Requests target field + protected static final int FLAG_REQUEST_SIGN = 0x00000010; // Requests all messages have a signature attached, in NEGOTIATE message. + protected static final int FLAG_REQUEST_SEAL = 0x00000020; // Request key exchange for message confidentiality in NEGOTIATE message. MUST be used in conjunction with 56BIT. + protected static final int FLAG_REQUEST_LAN_MANAGER_KEY = 0x00000080; // Request Lan Manager key instead of user session key + protected static final int FLAG_REQUEST_NTLMv1 = 0x00000200; // Request NTLMv1 security. MUST be set in NEGOTIATE and CHALLENGE both + protected static final int FLAG_DOMAIN_PRESENT = 0x00001000; // Domain is present in message + protected static final int FLAG_WORKSTATION_PRESENT = 0x00002000; // Workstation is present in message + protected static final int FLAG_REQUEST_ALWAYS_SIGN = 0x00008000; // Requests a signature block on all messages. Overridden by REQUEST_SIGN and REQUEST_SEAL. + protected static final int FLAG_REQUEST_NTLM2_SESSION = 0x00080000; // From server in challenge, requesting NTLM2 session security + protected static final int FLAG_REQUEST_VERSION = 0x02000000; // Request protocol version + protected static final int FLAG_TARGETINFO_PRESENT = 0x00800000; // From server in challenge message, indicating targetinfo is present + protected static final int FLAG_REQUEST_128BIT_KEY_EXCH = 0x20000000; // Request explicit 128-bit key exchange + protected static final int FLAG_REQUEST_EXPLICIT_KEY_EXCH = 0x40000000; // Request explicit key exchange + protected static final int FLAG_REQUEST_56BIT_ENCRYPTION = 0x80000000; // Must be used in conjunction with SEAL + /** Secure random generator */ private static final java.security.SecureRandom RND_GEN; @@ -75,21 +75,52 @@ public final class NTLMEngine { java.security.SecureRandom rnd = null; try { rnd = java.security.SecureRandom.getInstance("SHA1PRNG"); - } catch (Exception e) { + } catch (final Exception ignore) { } RND_GEN = rnd; } /** The signature string as bytes in the default encoding */ - private static byte[] SIGNATURE; + private static final byte[] SIGNATURE; static { - byte[] bytesWithoutNull = "NTLMSSP".getBytes(US_ASCII); + final byte[] bytesWithoutNull = "NTLMSSP".getBytes(StandardCharsets.US_ASCII); SIGNATURE = new byte[bytesWithoutNull.length + 1]; System.arraycopy(bytesWithoutNull, 0, SIGNATURE, 0, bytesWithoutNull.length); SIGNATURE[bytesWithoutNull.length] = (byte) 0x00; } + /** + * Returns the response for the given message. + * + * @param message + * the message that was received from the server. + * @param username + * the username to authenticate with. + * @param password + * the password to authenticate with. + * @param host + * The host. + * @param domain + * the NT domain to authenticate in. + * @return The response. + * @throws org.apache.http.HttpException + * If the messages cannot be retrieved. + */ + final String getResponseFor(final String message, final String username, final String password, + final String host, final String domain) throws NTLMEngineException { + + final String response; + if (message == null || message.trim().equals("")) { + response = getType1Message(host, domain); + } else { + final Type2Message t2m = new Type2Message(message); + response = getType3Message(username, password, host, domain, t2m.getChallenge(), t2m + .getFlags(), t2m.getTarget(), t2m.getTargetInfo()); + } + return response; + } + /** * Creates the first message (type 1 message) in the NTLM authentication * sequence. This message includes the user name, domain and host for the @@ -101,7 +132,7 @@ public final class NTLMEngine { * The domain to authenticate with. * @return String the message to add to the HTTP request header. */ - String getType1Message(String host, String domain) throws NTLMEngineException { + String getType1Message(final String host, final String domain) throws NTLMEngineException { return new Type1Message(domain, host).getResponse(); } @@ -123,49 +154,60 @@ String getType1Message(String host, String domain) throws NTLMEngineException { * the 8 byte array the server sent. * @return The type 3 message. * @throws NTLMEngineException - * If {@encrypt(byte[],byte[])} fails. + * If {@link #RC4(byte[],byte[])} fails. */ - String getType3Message(String user, String password, String host, String domain, byte[] nonce, int type2Flags, String target, - byte[] targetInformation) throws NTLMEngineException { - return new Type3Message(domain, host, user, password, nonce, type2Flags, target, targetInformation).getResponse(); + String getType3Message(final String user, final String password, final String host, final String domain, + final byte[] nonce, final int type2Flags, final String target, final byte[] targetInformation) + throws NTLMEngineException { + return new Type3Message(domain, host, user, password, nonce, type2Flags, target, + targetInformation).getResponse(); } /** Strip dot suffix from a name */ - private static String stripDotSuffix(String value) { - int index = value.indexOf('.'); - if (index != -1) + private static String stripDotSuffix(final String value) { + if (value == null) { + return null; + } + final int index = value.indexOf("."); + if (index != -1) { return value.substring(0, index); + } return value; } /** Convert host to standard form */ - private static String convertHost(String host) { + private static String convertHost(final String host) { return stripDotSuffix(host); } /** Convert domain to standard form */ - private static String convertDomain(String domain) { + private static String convertDomain(final String domain) { return stripDotSuffix(domain); } - private static int readULong(byte[] src, int index) throws NTLMEngineException { - if (src.length < index + 4) + private static int readULong(final byte[] src, final int index) throws NTLMEngineException { + if (src.length < index + 4) { throw new NTLMEngineException("NTLM authentication - buffer too small for DWORD"); - return (src[index] & 0xff) | ((src[index + 1] & 0xff) << 8) | ((src[index + 2] & 0xff) << 16) | ((src[index + 3] & 0xff) << 24); + } + return (src[index] & 0xff) | ((src[index + 1] & 0xff) << 8) + | ((src[index + 2] & 0xff) << 16) | ((src[index + 3] & 0xff) << 24); } - private static int readUShort(byte[] src, int index) throws NTLMEngineException { - if (src.length < index + 2) + private static int readUShort(final byte[] src, final int index) throws NTLMEngineException { + if (src.length < index + 2) { throw new NTLMEngineException("NTLM authentication - buffer too small for WORD"); + } return (src[index] & 0xff) | ((src[index + 1] & 0xff) << 8); } - private static byte[] readSecurityBuffer(byte[] src, int index) throws NTLMEngineException { - int length = readUShort(src, index); - int offset = readULong(src, index + 4); - if (src.length < offset + length) - throw new NTLMEngineException("NTLM authentication - buffer too small for data item"); - byte[] buffer = new byte[length]; + private static byte[] readSecurityBuffer(final byte[] src, final int index) throws NTLMEngineException { + final int length = readUShort(src, index); + final int offset = readULong(src, index + 4); + if (src.length < offset + length) { + throw new NTLMEngineException( + "NTLM authentication - buffer too small for data item"); + } + final byte[] buffer = new byte[length]; System.arraycopy(src, offset, buffer, 0, length); return buffer; } @@ -175,7 +217,7 @@ private static byte[] makeRandomChallenge() throws NTLMEngineException { if (RND_GEN == null) { throw new NTLMEngineException("Random generator not available"); } - byte[] rval = new byte[8]; + final byte[] rval = new byte[8]; synchronized (RND_GEN) { RND_GEN.nextBytes(rval); } @@ -187,7 +229,7 @@ private static byte[] makeSecondaryKey() throws NTLMEngineException { if (RND_GEN == null) { throw new NTLMEngineException("Random generator not available"); } - byte[] rval = new byte[16]; + final byte[] rval = new byte[16]; synchronized (RND_GEN) { RND_GEN.nextBytes(rval); } @@ -196,14 +238,16 @@ private static byte[] makeSecondaryKey() throws NTLMEngineException { protected static class CipherGen { - protected final String target; + protected final String domain; protected final String user; protected final String password; protected final byte[] challenge; + protected final String target; protected final byte[] targetInformation; // Information we can generate but may be passed in (for testing) protected byte[] clientChallenge; + protected byte[] clientChallenge2; protected byte[] secondaryKey; protected byte[] timestamp; @@ -213,6 +257,7 @@ protected static class CipherGen { protected byte[] ntlmHash = null; protected byte[] ntlmResponse = null; protected byte[] ntlmv2Hash = null; + protected byte[] lmv2Hash = null; protected byte[] lmv2Response = null; protected byte[] ntlmv2Blob = null; protected byte[] ntlmv2Response = null; @@ -224,68 +269,105 @@ protected static class CipherGen { protected byte[] ntlm2SessionResponseUserSessionKey = null; protected byte[] lanManagerSessionKey = null; - public CipherGen(String target, String user, String password, byte[] challenge, byte[] targetInformation, byte[] clientChallenge, - byte[] secondaryKey, byte[] timestamp) { + public CipherGen(final String domain, final String user, final String password, + final byte[] challenge, final String target, final byte[] targetInformation, + final byte[] clientChallenge, final byte[] clientChallenge2, + final byte[] secondaryKey, final byte[] timestamp) { + this.domain = domain; this.target = target; this.user = user; this.password = password; this.challenge = challenge; this.targetInformation = targetInformation; this.clientChallenge = clientChallenge; + this.clientChallenge2 = clientChallenge2; this.secondaryKey = secondaryKey; this.timestamp = timestamp; } - public CipherGen(String target, String user, String password, byte[] challenge, byte[] targetInformation) { - this(target, user, password, challenge, targetInformation, null, null, null); + public CipherGen(final String domain, final String user, final String password, + final byte[] challenge, final String target, final byte[] targetInformation) { + this(domain, user, password, challenge, target, targetInformation, null, null, null, null); } /** Calculate and return client challenge */ - public byte[] getClientChallenge() throws NTLMEngineException { - if (clientChallenge == null) + public byte[] getClientChallenge() + throws NTLMEngineException { + if (clientChallenge == null) { clientChallenge = makeRandomChallenge(); + } return clientChallenge; } + /** Calculate and return second client challenge */ + public byte[] getClientChallenge2() + throws NTLMEngineException { + if (clientChallenge2 == null) { + clientChallenge2 = makeRandomChallenge(); + } + return clientChallenge2; + } + /** Calculate and return random secondary key */ - public byte[] getSecondaryKey() throws NTLMEngineException { - if (secondaryKey == null) + public byte[] getSecondaryKey() + throws NTLMEngineException { + if (secondaryKey == null) { secondaryKey = makeSecondaryKey(); + } return secondaryKey; } /** Calculate and return the LMHash */ - public byte[] getLMHash() throws NTLMEngineException { - if (lmHash == null) + public byte[] getLMHash() + throws NTLMEngineException { + if (lmHash == null) { lmHash = lmHash(password); + } return lmHash; } /** Calculate and return the LMResponse */ - public byte[] getLMResponse() throws NTLMEngineException { - if (lmResponse == null) - lmResponse = lmResponse(getLMHash(), challenge); + public byte[] getLMResponse() + throws NTLMEngineException { + if (lmResponse == null) { + lmResponse = lmResponse(getLMHash(),challenge); + } return lmResponse; } /** Calculate and return the NTLMHash */ - public byte[] getNTLMHash() throws NTLMEngineException { - if (ntlmHash == null) + public byte[] getNTLMHash() + throws NTLMEngineException { + if (ntlmHash == null) { ntlmHash = ntlmHash(password); + } return ntlmHash; } /** Calculate and return the NTLMResponse */ - public byte[] getNTLMResponse() throws NTLMEngineException { - if (ntlmResponse == null) - ntlmResponse = lmResponse(getNTLMHash(), challenge); + public byte[] getNTLMResponse() + throws NTLMEngineException { + if (ntlmResponse == null) { + ntlmResponse = lmResponse(getNTLMHash(),challenge); + } return ntlmResponse; } + /** Calculate the LMv2 hash */ + public byte[] getLMv2Hash() + throws NTLMEngineException { + if (lmv2Hash == null) { + lmv2Hash = lmv2Hash(domain, user, getNTLMHash()); + } + return lmv2Hash; + } + /** Calculate the NTLMv2 hash */ - public byte[] getNTLMv2Hash() throws NTLMEngineException { - if (ntlmv2Hash == null) - ntlmv2Hash = ntlmv2Hash(target, user, password); + public byte[] getNTLMv2Hash() + throws NTLMEngineException { + if (ntlmv2Hash == null) { + ntlmv2Hash = ntlmv2Hash(domain, user, getNTLMHash()); + } return ntlmv2Hash; } @@ -306,117 +388,122 @@ public byte[] getTimestamp() { } /** Calculate the NTLMv2Blob */ - public byte[] getNTLMv2Blob() throws NTLMEngineException { - if (ntlmv2Blob == null) - ntlmv2Blob = createBlob(getClientChallenge(), targetInformation, getTimestamp()); + public byte[] getNTLMv2Blob() + throws NTLMEngineException { + if (ntlmv2Blob == null) { + ntlmv2Blob = createBlob(getClientChallenge2(), targetInformation, getTimestamp()); + } return ntlmv2Blob; } /** Calculate the NTLMv2Response */ - public byte[] getNTLMv2Response() throws NTLMEngineException { - if (ntlmv2Response == null) - ntlmv2Response = lmv2Response(getNTLMv2Hash(), challenge, getNTLMv2Blob()); + public byte[] getNTLMv2Response() + throws NTLMEngineException { + if (ntlmv2Response == null) { + ntlmv2Response = lmv2Response(getNTLMv2Hash(),challenge,getNTLMv2Blob()); + } return ntlmv2Response; } /** Calculate the LMv2Response */ - public byte[] getLMv2Response() throws NTLMEngineException { - if (lmv2Response == null) - lmv2Response = lmv2Response(getNTLMv2Hash(), challenge, getClientChallenge()); + public byte[] getLMv2Response() + throws NTLMEngineException { + if (lmv2Response == null) { + lmv2Response = lmv2Response(getLMv2Hash(),challenge,getClientChallenge()); + } return lmv2Response; } /** Get NTLM2SessionResponse */ - public byte[] getNTLM2SessionResponse() throws NTLMEngineException { - if (ntlm2SessionResponse == null) - ntlm2SessionResponse = ntlm2SessionResponse(getNTLMHash(), challenge, getClientChallenge()); + public byte[] getNTLM2SessionResponse() + throws NTLMEngineException { + if (ntlm2SessionResponse == null) { + ntlm2SessionResponse = ntlm2SessionResponse(getNTLMHash(),challenge,getClientChallenge()); + } return ntlm2SessionResponse; } /** Calculate and return LM2 session response */ - public byte[] getLM2SessionResponse() throws NTLMEngineException { + public byte[] getLM2SessionResponse() + throws NTLMEngineException { if (lm2SessionResponse == null) { - byte[] clientChallenge = getClientChallenge(); + final byte[] clChallenge = getClientChallenge(); lm2SessionResponse = new byte[24]; - System.arraycopy(clientChallenge, 0, lm2SessionResponse, 0, clientChallenge.length); - Arrays.fill(lm2SessionResponse, clientChallenge.length, lm2SessionResponse.length, (byte) 0x00); + System.arraycopy(clChallenge, 0, lm2SessionResponse, 0, clChallenge.length); + Arrays.fill(lm2SessionResponse, clChallenge.length, lm2SessionResponse.length, (byte) 0x00); } return lm2SessionResponse; } /** Get LMUserSessionKey */ - public byte[] getLMUserSessionKey() throws NTLMEngineException { + public byte[] getLMUserSessionKey() + throws NTLMEngineException { if (lmUserSessionKey == null) { - byte[] lmHash = getLMHash(); lmUserSessionKey = new byte[16]; - System.arraycopy(lmHash, 0, lmUserSessionKey, 0, 8); + System.arraycopy(getLMHash(), 0, lmUserSessionKey, 0, 8); Arrays.fill(lmUserSessionKey, 8, 16, (byte) 0x00); } return lmUserSessionKey; } /** Get NTLMUserSessionKey */ - public byte[] getNTLMUserSessionKey() throws NTLMEngineException { + public byte[] getNTLMUserSessionKey() + throws NTLMEngineException { if (ntlmUserSessionKey == null) { - byte[] ntlmHash = getNTLMHash(); - MD4 md4 = new MD4(); - md4.update(ntlmHash); + final MD4 md4 = new MD4(); + md4.update(getNTLMHash()); ntlmUserSessionKey = md4.getOutput(); } return ntlmUserSessionKey; } /** GetNTLMv2UserSessionKey */ - public byte[] getNTLMv2UserSessionKey() throws NTLMEngineException { + public byte[] getNTLMv2UserSessionKey() + throws NTLMEngineException { if (ntlmv2UserSessionKey == null) { - byte[] ntlmv2Hash = getNTLMv2Hash(); - byte[] ntlmv2Blob = getNTLMv2Blob(); - byte[] temp = new byte[ntlmv2Blob.length + challenge.length]; - // "The challenge is concatenated with the blob" - check this (MHL) - System.arraycopy(challenge, 0, temp, 0, challenge.length); - System.arraycopy(ntlmv2Blob, 0, temp, challenge.length, ntlmv2Blob.length); - byte[] partial = hmacMD5(temp, ntlmv2Hash); - ntlmv2UserSessionKey = hmacMD5(partial, ntlmv2Hash); + final byte[] ntlmv2hash = getNTLMv2Hash(); + final byte[] truncatedResponse = new byte[16]; + System.arraycopy(getNTLMv2Response(), 0, truncatedResponse, 0, 16); + ntlmv2UserSessionKey = hmacMD5(truncatedResponse, ntlmv2hash); } return ntlmv2UserSessionKey; } /** Get NTLM2SessionResponseUserSessionKey */ - public byte[] getNTLM2SessionResponseUserSessionKey() throws NTLMEngineException { + public byte[] getNTLM2SessionResponseUserSessionKey() + throws NTLMEngineException { if (ntlm2SessionResponseUserSessionKey == null) { - byte[] ntlmUserSessionKey = getNTLMUserSessionKey(); - byte[] ntlm2SessionResponseNonce = getLM2SessionResponse(); - byte[] sessionNonce = new byte[challenge.length + ntlm2SessionResponseNonce.length]; + final byte[] ntlm2SessionResponseNonce = getLM2SessionResponse(); + final byte[] sessionNonce = new byte[challenge.length + ntlm2SessionResponseNonce.length]; System.arraycopy(challenge, 0, sessionNonce, 0, challenge.length); System.arraycopy(ntlm2SessionResponseNonce, 0, sessionNonce, challenge.length, ntlm2SessionResponseNonce.length); - ntlm2SessionResponseUserSessionKey = hmacMD5(sessionNonce, ntlmUserSessionKey); + ntlm2SessionResponseUserSessionKey = hmacMD5(sessionNonce,getNTLMUserSessionKey()); } return ntlm2SessionResponseUserSessionKey; } /** Get LAN Manager session key */ - public byte[] getLanManagerSessionKey() throws NTLMEngineException { + public byte[] getLanManagerSessionKey() + throws NTLMEngineException { if (lanManagerSessionKey == null) { - byte[] lmHash = getLMHash(); - byte[] lmResponse = getLMResponse(); try { - byte[] keyBytes = new byte[14]; - System.arraycopy(lmHash, 0, keyBytes, 0, 8); - Arrays.fill(keyBytes, 8, keyBytes.length, (byte) 0xbd); - Key lowKey = createDESKey(keyBytes, 0); - Key highKey = createDESKey(keyBytes, 7); - byte[] truncatedResponse = new byte[8]; - System.arraycopy(lmResponse, 0, truncatedResponse, 0, truncatedResponse.length); + final byte[] keyBytes = new byte[14]; + System.arraycopy(getLMHash(), 0, keyBytes, 0, 8); + Arrays.fill(keyBytes, 8, keyBytes.length, (byte)0xbd); + final Key lowKey = createDESKey(keyBytes, 0); + final Key highKey = createDESKey(keyBytes, 7); + final byte[] truncatedResponse = new byte[8]; + System.arraycopy(getLMResponse(), 0, truncatedResponse, 0, truncatedResponse.length); Cipher des = Cipher.getInstance("DES/ECB/NoPadding"); des.init(Cipher.ENCRYPT_MODE, lowKey); - byte[] lowPart = des.doFinal(truncatedResponse); + final byte[] lowPart = des.doFinal(truncatedResponse); des = Cipher.getInstance("DES/ECB/NoPadding"); des.init(Cipher.ENCRYPT_MODE, highKey); - byte[] highPart = des.doFinal(truncatedResponse); + final byte[] highPart = des.doFinal(truncatedResponse); lanManagerSessionKey = new byte[16]; System.arraycopy(lowPart, 0, lanManagerSessionKey, 0, lowPart.length); System.arraycopy(highPart, 0, lanManagerSessionKey, lowPart.length, highPart.length); - } catch (Exception e) { + } catch (final Exception e) { throw new NTLMEngineException(e.getMessage(), e); } } @@ -425,19 +512,21 @@ public byte[] getLanManagerSessionKey() throws NTLMEngineException { } /** Calculates HMAC-MD5 */ - static byte[] hmacMD5(byte[] value, byte[] key) throws NTLMEngineException { - HMACMD5 hmacMD5 = new HMACMD5(key); + static byte[] hmacMD5(final byte[] value, final byte[] key) + throws NTLMEngineException { + final HMACMD5 hmacMD5 = new HMACMD5(key); hmacMD5.update(value); return hmacMD5.getOutput(); } /** Calculates RC4 */ - static byte[] RC4(byte[] value, byte[] key) throws NTLMEngineException { + static byte[] RC4(final byte[] value, final byte[] key) + throws NTLMEngineException { try { - Cipher rc4 = Cipher.getInstance("RC4"); + final Cipher rc4 = Cipher.getInstance("RC4"); rc4.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "RC4")); return rc4.doFinal(value); - } catch (Exception e) { + } catch (final Exception e) { throw new NTLMEngineException(e.getMessage(), e); } } @@ -446,18 +535,12 @@ static byte[] RC4(byte[] value, byte[] key) throws NTLMEngineException { * Calculates the NTLM2 Session Response for the given challenge, using the * specified password and client challenge. * - * @param password - * The user's password. - * @param challenge - * The Type 2 challenge from the server. - * @param clientChallenge - * The random 8-byte client challenge. - * * @return The NTLM2 Session Response. This is placed in the NTLM response * field of the Type 3 message; the LM response field contains the * client challenge, null-padded to 24 bytes. */ - static byte[] ntlm2SessionResponse(byte[] ntlmHash, byte[] challenge, byte[] clientChallenge) throws NTLMEngineException { + static byte[] ntlm2SessionResponse(final byte[] ntlmHash, final byte[] challenge, + final byte[] clientChallenge) throws NTLMEngineException { try { // Look up MD5 algorithm (was necessary on jdk 1.4.2) // This used to be needed, but java 1.5.0_07 includes the MD5 @@ -472,17 +555,18 @@ static byte[] ntlm2SessionResponse(byte[] ntlmHash, byte[] challenge, byte[] cli // byte[] digest = (byte[])digestMethod.invoke(mdInstance,new // Object[0]); - MessageDigest md5 = MessageDigest.getInstance("MD5"); + final MessageDigest md5 = MessageDigest.getInstance("MD5"); md5.update(challenge); md5.update(clientChallenge); - byte[] digest = md5.digest(); + final byte[] digest = md5.digest(); - byte[] sessionHash = new byte[8]; + final byte[] sessionHash = new byte[8]; System.arraycopy(digest, 0, sessionHash, 0, 8); return lmResponse(ntlmHash, sessionHash); - } catch (Exception e) { - if (e instanceof NTLMEngineException) + } catch (final Exception e) { + if (e instanceof NTLMEngineException) { throw (NTLMEngineException) e; + } throw new NTLMEngineException(e.getMessage(), e); } } @@ -496,25 +580,25 @@ static byte[] ntlm2SessionResponse(byte[] ntlmHash, byte[] challenge, byte[] cli * @return The LM Hash of the given password, used in the calculation of the * LM Response. */ - private static byte[] lmHash(String password) throws NTLMEngineException { + private static byte[] lmHash(final String password) throws NTLMEngineException { try { - byte[] oemPassword = password.toUpperCase(Locale.US).getBytes(StandardCharsets.US_ASCII); - int length = Math.min(oemPassword.length, 14); - byte[] keyBytes = new byte[14]; + final byte[] oemPassword = password.toUpperCase(Locale.ENGLISH).getBytes("US-ASCII"); + final int length = Math.min(oemPassword.length, 14); + final byte[] keyBytes = new byte[14]; System.arraycopy(oemPassword, 0, keyBytes, 0, length); - Key lowKey = createDESKey(keyBytes, 0); - Key highKey = createDESKey(keyBytes, 7); - byte[] magicConstant = "KGS!@#$%".getBytes("US-ASCII"); - Cipher des = Cipher.getInstance("DES/ECB/NoPadding"); + final Key lowKey = createDESKey(keyBytes, 0); + final Key highKey = createDESKey(keyBytes, 7); + final byte[] magicConstant = "KGS!@#$%".getBytes("US-ASCII"); + final Cipher des = Cipher.getInstance("DES/ECB/NoPadding"); des.init(Cipher.ENCRYPT_MODE, lowKey); - byte[] lowHash = des.doFinal(magicConstant); + final byte[] lowHash = des.doFinal(magicConstant); des.init(Cipher.ENCRYPT_MODE, highKey); - byte[] highHash = des.doFinal(magicConstant); - byte[] lmHash = new byte[16]; + final byte[] highHash = des.doFinal(magicConstant); + final byte[] lmHash = new byte[16]; System.arraycopy(lowHash, 0, lmHash, 0, 8); System.arraycopy(highHash, 0, lmHash, 8, 8); return lmHash; - } catch (Exception e) { + } catch (final Exception e) { throw new NTLMEngineException(e.getMessage(), e); } } @@ -528,39 +612,55 @@ private static byte[] lmHash(String password) throws NTLMEngineException { * @return The NTLM Hash of the given password, used in the calculation of * the NTLM Response and the NTLMv2 and LMv2 Hashes. */ - private static byte[] ntlmHash(String password) throws NTLMEngineException { + private static byte[] ntlmHash(final String password) throws NTLMEngineException { try { - byte[] unicodePassword = password.getBytes("UnicodeLittleUnmarked"); - MD4 md4 = new MD4(); + final byte[] unicodePassword = password.getBytes("UnicodeLittleUnmarked"); + final MD4 md4 = new MD4(); md4.update(unicodePassword); return md4.getOutput(); - } catch (java.io.UnsupportedEncodingException e) { + } catch (final UnsupportedEncodingException e) { throw new NTLMEngineException("Unicode not supported: " + e.getMessage(), e); } } /** - * Creates the NTLMv2 Hash of the user's password. + * Creates the LMv2 Hash of the user's password. * - * @param target - * The authentication target (i.e., domain). - * @param user - * The username. - * @param password - * The password. + * @return The LMv2 Hash, used in the calculation of the NTLMv2 and LMv2 + * Responses. + */ + private static byte[] lmv2Hash(final String domain, final String user, final byte[] ntlmHash) + throws NTLMEngineException { + try { + final HMACMD5 hmacMD5 = new HMACMD5(ntlmHash); + // Upper case username, upper case domain! + hmacMD5.update(user.toUpperCase(Locale.ENGLISH).getBytes("UnicodeLittleUnmarked")); + if (domain != null) { + hmacMD5.update(domain.toUpperCase(Locale.ENGLISH).getBytes("UnicodeLittleUnmarked")); + } + return hmacMD5.getOutput(); + } catch (final UnsupportedEncodingException e) { + throw new NTLMEngineException("Unicode not supported! " + e.getMessage(), e); + } + } + + /** + * Creates the NTLMv2 Hash of the user's password. * * @return The NTLMv2 Hash, used in the calculation of the NTLMv2 and LMv2 * Responses. */ - private static byte[] ntlmv2Hash(String target, String user, String password) throws NTLMEngineException { + private static byte[] ntlmv2Hash(final String domain, final String user, final byte[] ntlmHash) + throws NTLMEngineException { try { - byte[] ntlmHash = ntlmHash(password); - HMACMD5 hmacMD5 = new HMACMD5(ntlmHash); + final HMACMD5 hmacMD5 = new HMACMD5(ntlmHash); // Upper case username, mixed case target!! - hmacMD5.update(user.toUpperCase(Locale.US).getBytes("UnicodeLittleUnmarked")); - hmacMD5.update(target.getBytes("UnicodeLittleUnmarked")); + hmacMD5.update(user.toUpperCase(Locale.ENGLISH).getBytes("UnicodeLittleUnmarked")); + if (domain != null) { + hmacMD5.update(domain.getBytes("UnicodeLittleUnmarked")); + } return hmacMD5.getOutput(); - } catch (java.io.UnsupportedEncodingException e) { + } catch (final UnsupportedEncodingException e) { throw new NTLMEngineException("Unicode not supported! " + e.getMessage(), e); } } @@ -575,26 +675,26 @@ private static byte[] ntlmv2Hash(String target, String user, String password) th * * @return The response (either LM or NTLM, depending on the provided hash). */ - private static byte[] lmResponse(byte[] hash, byte[] challenge) throws NTLMEngineException { + private static byte[] lmResponse(final byte[] hash, final byte[] challenge) throws NTLMEngineException { try { - byte[] keyBytes = new byte[21]; + final byte[] keyBytes = new byte[21]; System.arraycopy(hash, 0, keyBytes, 0, 16); - Key lowKey = createDESKey(keyBytes, 0); - Key middleKey = createDESKey(keyBytes, 7); - Key highKey = createDESKey(keyBytes, 14); - Cipher des = Cipher.getInstance("DES/ECB/NoPadding"); + final Key lowKey = createDESKey(keyBytes, 0); + final Key middleKey = createDESKey(keyBytes, 7); + final Key highKey = createDESKey(keyBytes, 14); + final Cipher des = Cipher.getInstance("DES/ECB/NoPadding"); des.init(Cipher.ENCRYPT_MODE, lowKey); - byte[] lowResponse = des.doFinal(challenge); + final byte[] lowResponse = des.doFinal(challenge); des.init(Cipher.ENCRYPT_MODE, middleKey); - byte[] middleResponse = des.doFinal(challenge); + final byte[] middleResponse = des.doFinal(challenge); des.init(Cipher.ENCRYPT_MODE, highKey); - byte[] highResponse = des.doFinal(challenge); - byte[] lmResponse = new byte[24]; + final byte[] highResponse = des.doFinal(challenge); + final byte[] lmResponse = new byte[24]; System.arraycopy(lowResponse, 0, lmResponse, 0, 8); System.arraycopy(middleResponse, 0, lmResponse, 8, 8); System.arraycopy(highResponse, 0, lmResponse, 16, 8); return lmResponse; - } catch (Exception e) { + } catch (final Exception e) { throw new NTLMEngineException(e.getMessage(), e); } } @@ -613,12 +713,13 @@ private static byte[] lmResponse(byte[] hash, byte[] challenge) throws NTLMEngin * @return The response (either NTLMv2 or LMv2, depending on the client * data). */ - private static byte[] lmv2Response(byte[] hash, byte[] challenge, byte[] clientData) throws NTLMEngineException { - HMACMD5 hmacMD5 = new HMACMD5(hash); + private static byte[] lmv2Response(final byte[] hash, final byte[] challenge, final byte[] clientData) + throws NTLMEngineException { + final HMACMD5 hmacMD5 = new HMACMD5(hash); hmacMD5.update(challenge); hmacMD5.update(clientData); - byte[] mac = hmacMD5.getOutput(); - byte[] lmv2Response = new byte[mac.length + clientData.length]; + final byte[] mac = hmacMD5.getOutput(); + final byte[] lmv2Response = new byte[mac.length + clientData.length]; System.arraycopy(mac, 0, lmv2Response, 0, mac.length); System.arraycopy(clientData, 0, lmv2Response, mac.length, clientData.length); return lmv2Response; @@ -635,13 +736,13 @@ private static byte[] lmv2Response(byte[] hash, byte[] challenge, byte[] clientD * * @return The blob, used in the calculation of the NTLMv2 Response. */ - private static byte[] createBlob(byte[] clientChallenge, byte[] targetInformation, byte[] timestamp) { - 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 }; - byte[] unknown2 = new byte[] { (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00 }; - byte[] blob = new byte[blobSignature.length + reserved.length + timestamp.length + 8 + unknown1.length + targetInformation.length - + unknown2.length]; + private static byte[] createBlob(final byte[] clientChallenge, final byte[] targetInformation, final byte[] timestamp) { + final byte[] blobSignature = new byte[] { (byte) 0x01, (byte) 0x01, (byte) 0x00, (byte) 0x00 }; + final byte[] reserved = new byte[] { (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00 }; + final byte[] unknown1 = new byte[] { (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00 }; + final byte[] unknown2 = new byte[] { (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00 }; + final byte[] blob = new byte[blobSignature.length + reserved.length + timestamp.length + 8 + + unknown1.length + targetInformation.length + unknown2.length]; int offset = 0; System.arraycopy(blobSignature, 0, blob, offset, blobSignature.length); offset += blobSignature.length; @@ -672,10 +773,10 @@ private static byte[] createBlob(byte[] clientChallenge, byte[] targetInformatio * @return A DES encryption key created from the key material starting at * the specified offset in the given byte array. */ - private static Key createDESKey(byte[] bytes, int offset) { - byte[] keyBytes = new byte[7]; + private static Key createDESKey(final byte[] bytes, final int offset) { + final byte[] keyBytes = new byte[7]; System.arraycopy(bytes, offset, keyBytes, 0, 7); - byte[] material = new byte[8]; + final byte[] material = new byte[8]; material[0] = keyBytes[0]; material[1] = (byte) (keyBytes[0] << 7 | (keyBytes[1] & 0xff) >>> 1); material[2] = (byte) (keyBytes[1] << 6 | (keyBytes[2] & 0xff) >>> 2); @@ -694,10 +795,11 @@ private static Key createDESKey(byte[] bytes, int offset) { * @param bytes * The data whose parity bits are to be adjusted for odd parity. */ - private static void oddParity(byte[] bytes) { + private static void oddParity(final byte[] bytes) { for (int i = 0; i < bytes.length; i++) { - byte b = bytes[i]; - boolean needsParity = (((b >>> 7) ^ (b >>> 6) ^ (b >>> 5) ^ (b >>> 4) ^ (b >>> 3) ^ (b >>> 2) ^ (b >>> 1)) & 0x01) == 0; + final byte b = bytes[i]; + final boolean needsParity = (((b >>> 7) ^ (b >>> 6) ^ (b >>> 5) ^ (b >>> 4) ^ (b >>> 3) + ^ (b >>> 2) ^ (b >>> 1)) & 0x01) == 0; if (needsParity) { bytes[i] |= (byte) 0x01; } else { @@ -719,23 +821,27 @@ static class NTLMMessage { } /** Constructor to use when message contents are known */ - NTLMMessage(String messageBody, int expectedType) throws NTLMEngineException { + NTLMMessage(final String messageBody, final int expectedType) throws NTLMEngineException { messageContents = Base64.decode(messageBody); // Look for NTLM message - if (messageContents.length < SIGNATURE.length) + if (messageContents.length < SIGNATURE.length) { throw new NTLMEngineException("NTLM message decoding error - packet too short"); + } int i = 0; while (i < SIGNATURE.length) { - if (messageContents[i] != SIGNATURE[i]) - throw new NTLMEngineException("NTLM message expected - instead got unrecognized bytes"); + if (messageContents[i] != SIGNATURE[i]) { + throw new NTLMEngineException( + "NTLM message expected - instead got unrecognized bytes"); + } i++; } // Check to be sure there's a type 2 message indicator next - int type = readULong(SIGNATURE.length); - if (type != expectedType) - throw new NTLMEngineException("NTLM type " + Integer.toString(expectedType) + " message expected - instead got type " - + Integer.toString(type)); + final int type = readULong(SIGNATURE.length); + if (type != expectedType) { + throw new NTLMEngineException("NTLM type " + Integer.toString(expectedType) + + " message expected - instead got type " + Integer.toString(type)); + } currentOutputPosition = messageContents.length; } @@ -754,43 +860,45 @@ protected int getMessageLength() { } /** Read a byte from a position within the message buffer */ - protected byte readByte(int position) throws NTLMEngineException { - if (messageContents.length < position + 1) + protected byte readByte(final int position) throws NTLMEngineException { + if (messageContents.length < position + 1) { throw new NTLMEngineException("NTLM: Message too short"); + } return messageContents[position]; } /** Read a bunch of bytes from a position in the message buffer */ - protected void readBytes(byte[] buffer, int position) throws NTLMEngineException { - if (messageContents.length < position + buffer.length) + protected void readBytes(final byte[] buffer, final int position) throws NTLMEngineException { + if (messageContents.length < position + buffer.length) { throw new NTLMEngineException("NTLM: Message too short"); + } System.arraycopy(messageContents, position, buffer, 0, buffer.length); } /** Read a ushort from a position within the message buffer */ - protected int readUShort(int position) throws NTLMEngineException { + protected int readUShort(final int position) throws NTLMEngineException { return NTLMEngine.readUShort(messageContents, position); } /** Read a ulong from a position within the message buffer */ - protected int readULong(int position) throws NTLMEngineException { + protected int readULong(final int position) throws NTLMEngineException { return NTLMEngine.readULong(messageContents, position); } /** Read a security buffer from a position within the message buffer */ - protected byte[] readSecurityBuffer(int position) throws NTLMEngineException { + protected byte[] readSecurityBuffer(final int position) throws NTLMEngineException { return NTLMEngine.readSecurityBuffer(messageContents, position); } /** * Prepares the object to create a response of the given length. * - * @param length + * @param maxlength * the maximum length of the response to prepare, not * including the type and the signature (which this method * adds). */ - protected void prepareResponse(int maxlength, int messageType) { + protected void prepareResponse(final int maxlength, final int messageType) { messageContents = new byte[maxlength]; currentOutputPosition = 0; addBytes(SIGNATURE); @@ -803,7 +911,7 @@ protected void prepareResponse(int maxlength, int messageType) { * @param b * the byte to add. */ - protected void addByte(byte b) { + protected void addByte(final byte b) { messageContents[currentOutputPosition] = b; currentOutputPosition++; } @@ -814,21 +922,24 @@ protected void addByte(byte b) { * @param bytes * the bytes to add. */ - protected void addBytes(byte[] bytes) { - for (byte b : bytes) { + protected void addBytes(final byte[] bytes) { + if (bytes == null) { + return; + } + for (final byte b : bytes) { messageContents[currentOutputPosition] = b; currentOutputPosition++; } } /** Adds a USHORT to the response */ - protected void addUShort(int value) { + protected void addUShort(final int value) { addByte((byte) (value & 0xff)); addByte((byte) (value >> 8 & 0xff)); } /** Adds a ULong to the response */ - protected void addULong(int value) { + protected void addULong(final int value) { addByte((byte) (value & 0xff)); addByte((byte) (value >> 8 & 0xff)); addByte((byte) (value >> 16 & 0xff)); @@ -842,12 +953,10 @@ protected void addULong(int value) { * @return The response as above. */ String getResponse() { - byte[] resp; + final byte[] resp; if (messageContents.length > currentOutputPosition) { - byte[] tmp = new byte[currentOutputPosition]; - for (int i = 0; i < currentOutputPosition; i++) { - tmp[i] = messageContents[i]; - } + final byte[] tmp = new byte[currentOutputPosition]; + System.arraycopy(messageContents, 0, tmp, 0, currentOutputPosition); resp = tmp; } else { resp = messageContents; @@ -863,18 +972,18 @@ static class Type1Message extends NTLMMessage { protected byte[] domainBytes; /** Constructor. Include the arguments the message will need */ - Type1Message(String domain, String host) throws NTLMEngineException { + Type1Message(final String domain, final String host) throws NTLMEngineException { super(); try { // Strip off domain name from the host! - host = convertHost(host); + final String unqualifiedHost = convertHost(host); // Use only the base domain name! - domain = convertDomain(domain); + final String unqualifiedDomain = convertDomain(domain); - // FIXME should host be uppercased? - hostBytes = host.getBytes("UnicodeLittleUnmarked"); - domainBytes = domain.toUpperCase(Locale.US).getBytes("UnicodeLittleUnmarked"); - } catch (java.io.UnsupportedEncodingException e) { + hostBytes = unqualifiedHost != null? unqualifiedHost.getBytes("ASCII") : null; + domainBytes = unqualifiedDomain != null ? unqualifiedDomain + .toUpperCase(Locale.ENGLISH).getBytes("ASCII") : null; + } catch (final UnsupportedEncodingException e) { throw new NTLMEngineException("Unicode unsupported: " + e.getMessage(), e); } } @@ -887,7 +996,7 @@ static class Type1Message extends NTLMMessage { String getResponse() { // Now, build the message. Calculate its length first, including // signature or type. - int finalLength = 32 + 8 /*+ hostBytes.length + domainBytes.length */; + final int finalLength = 32 + 8 /*+ hostBytes.length + domainBytes.length */; // Set up the response. This will initialize the signature, message // type, and flags. @@ -895,22 +1004,26 @@ String getResponse() { // Flags. These are the complete set of flags we support. addULong( - //FLAG_WORKSTATION_PRESENT | - //FLAG_DOMAIN_PRESENT | + //FLAG_WORKSTATION_PRESENT | + //FLAG_DOMAIN_PRESENT | - // Required flags - FLAG_REQUEST_LAN_MANAGER_KEY | FLAG_REQUEST_NTLMv1 | FLAG_REQUEST_NTLM2_SESSION | + // Required flags + //FLAG_REQUEST_LAN_MANAGER_KEY | + FLAG_REQUEST_NTLMv1 | + FLAG_REQUEST_NTLM2_SESSION | - // Protocol version request + // Protocol version request FLAG_REQUEST_VERSION | // Recommended privacy settings FLAG_REQUEST_ALWAYS_SIGN | //FLAG_REQUEST_SEAL | - FLAG_REQUEST_SIGN | + //FLAG_REQUEST_SIGN | // These must be set according to documentation, based on use of SEAL above - FLAG_REQUEST_128BIT_KEY_EXCH | FLAG_REQUEST_56BIT_ENCRYPTION | FLAG_REQUEST_EXPLICIT_KEY_EXCH | + FLAG_REQUEST_128BIT_KEY_EXCH | + FLAG_REQUEST_56BIT_ENCRYPTION | + //FLAG_REQUEST_EXPLICIT_KEY_EXCH | FLAG_REQUEST_UNICODE_ENCODING); @@ -919,7 +1032,7 @@ String getResponse() { addUShort(/*domainBytes.length*/0); // Domain offset. - addULong(/*hostBytes.length +*/32 + 8); + addULong(/*hostBytes.length +*/ 32 + 8); // Host length (two times). addUShort(/*hostBytes.length*/0); @@ -935,12 +1048,14 @@ String getResponse() { // NTLM revision addUShort(0x0f00); + // Host (workstation) String. //addBytes(hostBytes); // Domain String. //addBytes(domainBytes); + return super.getResponse(); } @@ -953,7 +1068,7 @@ static class Type2Message extends NTLMMessage { protected byte[] targetInfo; protected int flags; - Type2Message(String message) throws NTLMEngineException { + Type2Message(final String message) throws NTLMEngineException { super(message, 2); // Type 2 message is laid out as follows: @@ -976,8 +1091,11 @@ static class Type2Message extends NTLMMessage { flags = readULong(20); - if ((flags & FLAG_REQUEST_UNICODE_ENCODING) == 0) - throw new NTLMEngineException("NTLM type 2 message has flags that make no sense: " + Integer.toString(flags)); + if ((flags & FLAG_REQUEST_UNICODE_ENCODING) == 0) { + throw new NTLMEngineException( + "NTLM type 2 message has flags that make no sense: " + + Integer.toString(flags)); + } // Do the target! target = null; @@ -985,11 +1103,11 @@ static class Type2Message extends NTLMMessage { // in Type2 messages, so use the length of the packet to decide // how to proceed instead if (getMessageLength() >= 12 + 8) { - byte[] bytes = readSecurityBuffer(12); + final byte[] bytes = readSecurityBuffer(12); if (bytes.length != 0) { try { target = new String(bytes, "UnicodeLittleUnmarked"); - } catch (java.io.UnsupportedEncodingException e) { + } catch (final UnsupportedEncodingException e) { throw new NTLMEngineException(e.getMessage(), e); } } @@ -999,7 +1117,7 @@ static class Type2Message extends NTLMMessage { targetInfo = null; // TARGET_DESIRED flag cannot be relied on, so use packet length if (getMessageLength() >= 40 + 8) { - byte[] bytes = readSecurityBuffer(40); + final byte[] bytes = readSecurityBuffer(40); if (bytes.length != 0) { targetInfo = bytes; } @@ -1041,19 +1159,21 @@ static class Type3Message extends NTLMMessage { protected byte[] ntResp; protected byte[] sessionKey; + /** Constructor. Pass the arguments we will need */ - Type3Message(String domain, String host, String user, String password, byte[] nonce, int type2Flags, String target, - byte[] targetInformation) throws NTLMEngineException { + Type3Message(final String domain, final String host, final String user, final String password, final byte[] nonce, + final int type2Flags, final String target, final byte[] targetInformation) + throws NTLMEngineException { // Save the flags this.type2Flags = type2Flags; // Strip off domain name from the host! - host = convertHost(host); + final String unqualifiedHost = convertHost(host); // Use only the base domain name! - domain = convertDomain(domain); + final String unqualifiedDomain = convertDomain(domain); - // Create a cipher generator class - CipherGen gen = new CipherGen(target, user, password, nonce, targetInformation); + // Create a cipher generator class. Use domain BEFORE it gets modified! + final CipherGen gen = new CipherGen(unqualifiedDomain, user, password, nonce, target, targetInformation); // Use the new code to calculate the responses, including v2 if that // seems warranted. @@ -1061,58 +1181,66 @@ static class Type3Message extends NTLMMessage { try { // This conditional may not work on Windows Server 2008 R2 and above, where it has not yet // been tested - if (((type2Flags & FLAG_TARGETINFO_PRESENT) != 0) && targetInformation != null && target != null) { + if (((type2Flags & FLAG_TARGETINFO_PRESENT) != 0) && + targetInformation != null && target != null) { // NTLMv2 ntResp = gen.getNTLMv2Response(); lmResp = gen.getLMv2Response(); - if ((type2Flags & FLAG_REQUEST_LAN_MANAGER_KEY) != 0) + if ((type2Flags & FLAG_REQUEST_LAN_MANAGER_KEY) != 0) { userSessionKey = gen.getLanManagerSessionKey(); - else + } else { userSessionKey = gen.getNTLMv2UserSessionKey(); + } } else { // NTLMv1 if ((type2Flags & FLAG_REQUEST_NTLM2_SESSION) != 0) { // NTLM2 session stuff is requested ntResp = gen.getNTLM2SessionResponse(); lmResp = gen.getLM2SessionResponse(); - if ((type2Flags & FLAG_REQUEST_LAN_MANAGER_KEY) != 0) + if ((type2Flags & FLAG_REQUEST_LAN_MANAGER_KEY) != 0) { userSessionKey = gen.getLanManagerSessionKey(); - else + } else { userSessionKey = gen.getNTLM2SessionResponseUserSessionKey(); - // All the other flags we send (signing, sealing, key - // exchange) are supported, but they don't do anything - // at all in an - // NTLM2 context! So we're done at this point. + } } else { ntResp = gen.getNTLMResponse(); lmResp = gen.getLMResponse(); - if ((type2Flags & FLAG_REQUEST_LAN_MANAGER_KEY) != 0) + if ((type2Flags & FLAG_REQUEST_LAN_MANAGER_KEY) != 0) { userSessionKey = gen.getLanManagerSessionKey(); - else + } else { userSessionKey = gen.getNTLMUserSessionKey(); + } } } - } catch (NTLMEngineException e) { + } catch (final NTLMEngineException e) { // This likely means we couldn't find the MD4 hash algorithm - // fail back to just using LM ntResp = new byte[0]; lmResp = gen.getLMResponse(); - if ((type2Flags & FLAG_REQUEST_LAN_MANAGER_KEY) != 0) + if ((type2Flags & FLAG_REQUEST_LAN_MANAGER_KEY) != 0) { userSessionKey = gen.getLanManagerSessionKey(); - else + } else { userSessionKey = gen.getLMUserSessionKey(); + } } - if ((type2Flags & FLAG_REQUEST_EXPLICIT_KEY_EXCH) != 0) - sessionKey = RC4(gen.getSecondaryKey(), userSessionKey); - else + if ((type2Flags & FLAG_REQUEST_SIGN) != 0) { + if ((type2Flags & FLAG_REQUEST_EXPLICIT_KEY_EXCH) != 0) { + sessionKey = RC4(gen.getSecondaryKey(), userSessionKey); + } else { + sessionKey = userSessionKey; + } + } else { sessionKey = null; + } try { - domainBytes = domain.toUpperCase(Locale.US).getBytes("UnicodeLittleUnmarked"); - hostBytes = host.getBytes("UnicodeLittleUnmarked"); + hostBytes = unqualifiedHost != null ? unqualifiedHost + .getBytes("UnicodeLittleUnmarked") : null; + domainBytes = unqualifiedDomain != null ? unqualifiedDomain + .toUpperCase(Locale.ENGLISH).getBytes("UnicodeLittleUnmarked") : null; userBytes = user.getBytes("UnicodeLittleUnmarked"); - } catch (java.io.UnsupportedEncodingException e) { + } catch (final UnsupportedEncodingException e) { throw new NTLMEngineException("Unicode not supported: " + e.getMessage(), e); } } @@ -1120,26 +1248,27 @@ static class Type3Message extends NTLMMessage { /** Assemble the response */ @Override String getResponse() { - int ntRespLen = ntResp.length; - int lmRespLen = lmResp.length; - - int domainLen = domainBytes.length; - int hostLen = hostBytes.length; - int userLen = userBytes.length; - int sessionKeyLen; - if (sessionKey != null) + final int ntRespLen = ntResp.length; + final int lmRespLen = lmResp.length; + + final int domainLen = domainBytes != null ? domainBytes.length : 0; + final int hostLen = hostBytes != null ? hostBytes.length: 0; + final int userLen = userBytes.length; + final int sessionKeyLen; + if (sessionKey != null) { sessionKeyLen = sessionKey.length; - else + } else { sessionKeyLen = 0; + } // Calculate the layout within the packet - int lmRespOffset = 72; // allocate space for the version - int ntRespOffset = lmRespOffset + lmRespLen; - int domainOffset = ntRespOffset + ntRespLen; - int userOffset = domainOffset + domainLen; - int hostOffset = userOffset + userLen; - int sessionKeyOffset = hostOffset + hostLen; - int finalLength = sessionKeyOffset + sessionKeyLen; + final int lmRespOffset = 72; // allocate space for the version + final int ntRespOffset = lmRespOffset + lmRespLen; + final int domainOffset = ntRespOffset + ntRespLen; + final int userOffset = domainOffset + domainLen; + final int hostOffset = userOffset + userLen; + final int sessionKeyOffset = hostOffset + hostLen; + final int finalLength = sessionKeyOffset + sessionKeyLen; // Start the response. Length includes signature and type prepareResponse(finalLength, 3); @@ -1186,33 +1315,33 @@ String getResponse() { // Session key offset addULong(sessionKeyOffset); - // Flags. Currently: WORKSTATION_PRESENT + DOMAIN_PRESENT + UNICODE_ENCODING + - // TARGET_DESIRED + NEGOTIATE_128 - addULong(FLAG_WORKSTATION_PRESENT - | FLAG_DOMAIN_PRESENT - | + // Flags. + addULong( + //FLAG_WORKSTATION_PRESENT | + //FLAG_DOMAIN_PRESENT | // Required flags - (type2Flags & FLAG_REQUEST_LAN_MANAGER_KEY) - | (type2Flags & FLAG_REQUEST_NTLMv1) - | (type2Flags & FLAG_REQUEST_NTLM2_SESSION) - | + (type2Flags & FLAG_REQUEST_LAN_MANAGER_KEY) | + (type2Flags & FLAG_REQUEST_NTLMv1) | + (type2Flags & FLAG_REQUEST_NTLM2_SESSION) | // Protocol version request - FLAG_REQUEST_VERSION - | + FLAG_REQUEST_VERSION | // Recommended privacy settings - (type2Flags & FLAG_REQUEST_ALWAYS_SIGN) | (type2Flags & FLAG_REQUEST_SEAL) - | (type2Flags & FLAG_REQUEST_SIGN) - | + (type2Flags & FLAG_REQUEST_ALWAYS_SIGN) | + (type2Flags & FLAG_REQUEST_SEAL) | + (type2Flags & FLAG_REQUEST_SIGN) | // These must be set according to documentation, based on use of SEAL above - (type2Flags & FLAG_REQUEST_128BIT_KEY_EXCH) | (type2Flags & FLAG_REQUEST_56BIT_ENCRYPTION) - | (type2Flags & FLAG_REQUEST_EXPLICIT_KEY_EXCH) | + (type2Flags & FLAG_REQUEST_128BIT_KEY_EXCH) | + (type2Flags & FLAG_REQUEST_56BIT_ENCRYPTION) | + (type2Flags & FLAG_REQUEST_EXPLICIT_KEY_EXCH) | - (type2Flags & FLAG_TARGETINFO_PRESENT) | (type2Flags & FLAG_REQUEST_UNICODE_ENCODING) - | (type2Flags & FLAG_REQUEST_TARGET)); + (type2Flags & FLAG_TARGETINFO_PRESENT) | + (type2Flags & FLAG_REQUEST_UNICODE_ENCODING) | + (type2Flags & FLAG_REQUEST_TARGET) + ); // Version addUShort(0x0105); @@ -1227,33 +1356,34 @@ String getResponse() { addBytes(domainBytes); addBytes(userBytes); addBytes(hostBytes); - if (sessionKey != null) + if (sessionKey != null) { addBytes(sessionKey); + } return super.getResponse(); } } - static void writeULong(byte[] buffer, int value, int offset) { + static void writeULong(final byte[] buffer, final int value, final int offset) { buffer[offset] = (byte) (value & 0xff); buffer[offset + 1] = (byte) (value >> 8 & 0xff); buffer[offset + 2] = (byte) (value >> 16 & 0xff); buffer[offset + 3] = (byte) (value >> 24 & 0xff); } - static int F(int x, int y, int z) { + static int F(final int x, final int y, final int z) { return ((x & y) | (~x & z)); } - static int G(int x, int y, int z) { + static int G(final int x, final int y, final int z) { return ((x & y) | (x & z) | (y & z)); } - static int H(int x, int y, int z) { + static int H(final int x, final int y, final int z) { return (x ^ y ^ z); } - static int rotintlft(int val, int numbits) { + static int rotintlft(final int val, final int numbits) { return ((val << numbits) | (val >>> (32 - numbits))); } @@ -1275,7 +1405,7 @@ static class MD4 { MD4() { } - void update(byte[] input) { + void update(final byte[] input) { // We always deal with 512 bits at a time. Correspondingly, there is // a buffer 64 bytes long that we write data into until it gets // full. @@ -1285,7 +1415,7 @@ void update(byte[] input) { // We have enough data to do the next step. Do a partial copy // and a transform, updating inputIndex and curBufferPos // accordingly - int transferAmt = dataBuffer.length - curBufferPos; + final int transferAmt = dataBuffer.length - curBufferPos; System.arraycopy(input, inputIndex, dataBuffer, curBufferPos, transferAmt); count += transferAmt; curBufferPos = 0; @@ -1296,7 +1426,7 @@ void update(byte[] input) { // If there's anything left, copy it into the buffer and leave it. // We know there's not enough left to process. if (inputIndex < input.length) { - int transferAmt = input.length - inputIndex; + final int transferAmt = input.length - inputIndex; System.arraycopy(input, inputIndex, dataBuffer, curBufferPos, transferAmt); count += transferAmt; curBufferPos += transferAmt; @@ -1306,9 +1436,9 @@ void update(byte[] input) { byte[] getOutput() { // Feed pad/length data into engine. This must round out the input // to a multiple of 512 bits. - int bufferIndex = (int) (count & 63L); - int padLen = (bufferIndex < 56) ? (56 - bufferIndex) : (120 - bufferIndex); - byte[] postBytes = new byte[padLen + 8]; + final int bufferIndex = (int) (count & 63L); + final int padLen = (bufferIndex < 56) ? (56 - bufferIndex) : (120 - bufferIndex); + final byte[] postBytes = new byte[padLen + 8]; // Leading 0x80, specified amount of zero padding, then length in // bits. postBytes[0] = (byte) 0x80; @@ -1321,7 +1451,7 @@ byte[] getOutput() { update(postBytes); // Calculate final result - byte[] result = new byte[16]; + final byte[] result = new byte[16]; writeULong(result, A, 0); writeULong(result, B, 4); writeULong(result, C, 8); @@ -1331,18 +1461,19 @@ byte[] getOutput() { protected void processBuffer() { // Convert current buffer to 16 ulongs - int[] d = new int[16]; + final int[] d = new int[16]; for (int i = 0; i < 16; i++) { - d[i] = (dataBuffer[i * 4] & 0xff) + ((dataBuffer[i * 4 + 1] & 0xff) << 8) + ((dataBuffer[i * 4 + 2] & 0xff) << 16) + d[i] = (dataBuffer[i * 4] & 0xff) + ((dataBuffer[i * 4 + 1] & 0xff) << 8) + + ((dataBuffer[i * 4 + 2] & 0xff) << 16) + ((dataBuffer[i * 4 + 3] & 0xff) << 24); } // Do a round of processing - int AA = A; - int BB = B; - int CC = C; - int DD = D; + final int AA = A; + final int BB = B; + final int CC = C; + final int DD = D; round1(d); round2(d); round3(d); @@ -1353,7 +1484,7 @@ protected void processBuffer() { } - protected void round1(int[] d) { + protected void round1(final int[] d) { A = rotintlft((A + F(B, C, D) + d[0]), 3); D = rotintlft((D + F(A, B, C) + d[1]), 7); C = rotintlft((C + F(D, A, B) + d[2]), 11); @@ -1375,7 +1506,7 @@ protected void round1(int[] d) { B = rotintlft((B + F(C, D, A) + d[15]), 19); } - protected void round2(int[] d) { + protected void round2(final int[] d) { A = rotintlft((A + G(B, C, D) + d[0] + 0x5a827999), 3); D = rotintlft((D + G(A, B, C) + d[4] + 0x5a827999), 5); C = rotintlft((C + G(D, A, B) + d[8] + 0x5a827999), 9); @@ -1398,7 +1529,7 @@ protected void round2(int[] d) { } - protected void round3(int[] d) { + protected void round3(final int[] d) { A = rotintlft((A + H(B, C, D) + d[0] + 0x6ed9eba1), 3); D = rotintlft((D + H(A, B, C) + d[8] + 0x6ed9eba1), 9); C = rotintlft((C + H(D, A, B) + d[4] + 0x6ed9eba1), 11); @@ -1432,13 +1563,15 @@ static class HMACMD5 { protected byte[] opad; protected MessageDigest md5; - HMACMD5(byte[] key) throws NTLMEngineException { + HMACMD5(final byte[] input) throws NTLMEngineException { + byte[] key = input; try { md5 = MessageDigest.getInstance("MD5"); - } catch (Exception ex) { + } catch (final Exception ex) { // Umm, the algorithm doesn't exist - throw an // NTLMEngineException! - throw new NTLMEngineException("Error getting md5 message digest implementation: " + ex.getMessage(), ex); + throw new NTLMEngineException( + "Error getting md5 message digest implementation: " + ex.getMessage(), ex); } // Initialize the pad buffers with the key @@ -1472,30 +1605,45 @@ static class HMACMD5 { /** Grab the current digest. This is the "answer". */ byte[] getOutput() { - byte[] digest = md5.digest(); + final byte[] digest = md5.digest(); md5.update(opad); return md5.digest(digest); } /** Update by adding a complete array */ - void update(byte[] input) { + void update(final byte[] input) { md5.update(input); } /** Update the algorithm */ - void update(byte[] input, int offset, int length) { + void update(final byte[] input, final int offset, final int length) { md5.update(input, offset, length); } + } - public String generateType1Msg(final String domain, final String workstation) throws NTLMEngineException { + public String generateType1Msg( + final String domain, + final String workstation) throws NTLMEngineException { return getType1Message(workstation, domain); } - public String generateType3Msg(final String username, final String password, final String domain, final String workstation, + public String generateType3Msg( + final String username, + final String password, + final String domain, + final String workstation, final String challenge) throws NTLMEngineException { - Type2Message t2m = new Type2Message(challenge); - return getType3Message(username, password, workstation, domain, t2m.getChallenge(), t2m.getFlags(), t2m.getTarget(), + final Type2Message t2m = new Type2Message(challenge); + return getType3Message( + username, + password, + workstation, + domain, + t2m.getChallenge(), + t2m.getFlags(), + t2m.getTarget(), t2m.getTargetInfo()); } + } diff --git a/src/test/java/com/ning/http/client/async/NTLMTest.java b/src/test/java/com/ning/http/client/async/NTLMTest.java index 01211aa38f..4989b30ecc 100644 --- a/src/test/java/com/ning/http/client/async/NTLMTest.java +++ b/src/test/java/com/ning/http/client/async/NTLMTest.java @@ -47,12 +47,12 @@ public void handle(String pathInContext, org.eclipse.jetty.server.Request reques httpResponse.setStatus(401); httpResponse.setHeader("WWW-Authenticate", "NTLM"); - } else if (authorization.equals("NTLM TlRMTVNTUAABAAAAkYII4gAAAAAoAAAAAAAAACgAAAAFASgKAAAADw==")) { + } else if (authorization.equals("NTLM TlRMTVNTUAABAAAAAYIIogAAAAAoAAAAAAAAACgAAAAFASgKAAAADw==")) { httpResponse.setStatus(401); httpResponse.setHeader("WWW-Authenticate", "NTLM TlRMTVNTUAACAAAAAAAAACgAAAABggAAU3J2Tm9uY2UAAAAAAAAAAA=="); } else if (authorization - .equals("NTLM TlRMTVNTUAADAAAAGAAYAEgAAAAYABgAYAAAABQAFAB4AAAADAAMAIwAAAASABIAmAAAAAAAAACqAAAAAbIAAgUBKAoAAAAPrYfKbe/jRoW5xDxHeoxC1gBmfWiS5+iX4OAN4xBKG/IFPwfH3agtPEia6YnhsADTVQBSAFMAQQAtAE0ASQBOAE8AUgBaAGEAcABoAG8AZABMAGkAZwBoAHQAQwBpAHQAeQA=")) { + .equals("NTLM TlRMTVNTUAADAAAAGAAYAEgAAAAYABgAYAAAABQAFAB4AAAADAAMAIwAAAASABIAmAAAAAAAAACqAAAAAYIAAgUBKAoAAAAPrYfKbe/jRoW5xDxHeoxC1gBmfWiS5+iX4OAN4xBKG/IFPwfH3agtPEia6YnhsADTVQBSAFMAQQAtAE0ASQBOAE8AUgBaAGEAcABoAG8AZABMAGkAZwBoAHQAQwBpAHQAeQA=")) { httpResponse.setStatus(200); } else { httpResponse.setStatus(401); From acdb7e4ded0a0e957a3f6d01689a21f7e4246bf2 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 2 Oct 2014 12:15:48 +0200 Subject: [PATCH 645/701] See https://issues.apache.org/jira/browse/HTTPCLIENT-1557 --- .../com/ning/http/client/ntlm/NTLMEngine.java | 31 ++++++++++--------- 1 file changed, 16 insertions(+), 15 deletions(-) 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 6436e2b47d..48226ea5fc 100644 --- a/src/main/java/com/ning/http/client/ntlm/NTLMEngine.java +++ b/src/main/java/com/ning/http/client/ntlm/NTLMEngine.java @@ -968,24 +968,25 @@ String getResponse() { /** Type 1 message assembly class */ static class Type1Message extends NTLMMessage { - protected byte[] hostBytes; - protected byte[] domainBytes; + // FIXME https://issues.apache.org/jira/browse/HTTPCLIENT-1557 +// protected byte[] hostBytes; +// protected byte[] domainBytes; /** Constructor. Include the arguments the message will need */ Type1Message(final String domain, final String host) throws NTLMEngineException { - super(); - try { - // Strip off domain name from the host! - final String unqualifiedHost = convertHost(host); - // Use only the base domain name! - final String unqualifiedDomain = convertDomain(domain); - - hostBytes = unqualifiedHost != null? unqualifiedHost.getBytes("ASCII") : null; - domainBytes = unqualifiedDomain != null ? unqualifiedDomain - .toUpperCase(Locale.ENGLISH).getBytes("ASCII") : null; - } catch (final UnsupportedEncodingException e) { - throw new NTLMEngineException("Unicode unsupported: " + e.getMessage(), e); - } +// super(); +// try { +// // Strip off domain name from the host! +// final String unqualifiedHost = convertHost(host); +// // Use only the base domain name! +// final String unqualifiedDomain = convertDomain(domain); +// +// hostBytes = unqualifiedHost != null? unqualifiedHost.getBytes("ASCII") : null; +// domainBytes = unqualifiedDomain != null ? unqualifiedDomain +// .toUpperCase(Locale.ENGLISH).getBytes("ASCII") : null; +// } catch (final UnsupportedEncodingException e) { +// throw new NTLMEngineException("Unicode unsupported: " + e.getMessage(), e); +// } } /** From 3425a303c9ef26012ad72b89d7d3624ae20cb8f8 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 2 Oct 2014 12:30:11 +0200 Subject: [PATCH 646/701] Fix test, set Content-Length --- src/test/java/com/ning/http/client/async/NTLMTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/ning/http/client/async/NTLMTest.java b/src/test/java/com/ning/http/client/async/NTLMTest.java index 4989b30ecc..01d1bc448d 100644 --- a/src/test/java/com/ning/http/client/async/NTLMTest.java +++ b/src/test/java/com/ning/http/client/async/NTLMTest.java @@ -57,7 +57,7 @@ public void handle(String pathInContext, org.eclipse.jetty.server.Request reques } else { httpResponse.setStatus(401); } - + httpResponse.setContentLength(0); httpResponse.getOutputStream().flush(); httpResponse.getOutputStream().close(); } From fe8215b904728eea9693c28dcfc992af7e201b26 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 2 Oct 2014 13:34:42 +0200 Subject: [PATCH 647/701] Don't enforce connection reuse on schemes other than NTLM --- .../client/providers/netty/handler/HttpProtocol.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/handler/HttpProtocol.java b/src/main/java/com/ning/http/client/providers/netty/handler/HttpProtocol.java index b7a5d2f11e..f03c647fe7 100644 --- a/src/main/java/com/ning/http/client/providers/netty/handler/HttpProtocol.java +++ b/src/main/java/com/ning/http/client/providers/netty/handler/HttpProtocol.java @@ -221,11 +221,18 @@ private boolean exitAfterHandling401(// if (!wwwAuthHeaders.contains("Kerberos") && (isNTLM(wwwAuthHeaders) || negociate)) { // NTLM newRealm = ntlmChallenge(wwwAuthHeaders.get(0), request, proxyServer, request.getHeaders(), realm, future, false); + + // don't forget to reuse channel: NTLM authenticates a connection + future.setReuseChannel(true); + } else if (negociate) { // SPNEGO KERBEROS newRealm = kerberosChallenge(channel, wwwAuthHeaders, request, proxyServer, request.getHeaders(), realm, future, false); if (newRealm == null) return true; + else + // don't forget to reuse channel: KERBEROS authenticates a connection + future.setReuseChannel(true); } else { newRealm = new Realm.RealmBuilder()// @@ -245,8 +252,6 @@ private boolean exitAfterHandling401(// Callback callback = new Callback(future) { public void call() throws IOException { channelManager.drainChannel(channel, future); - // don't forget to reuse channel: NTLM authenticates a connection - future.setReuseChannel(true); requestSender.sendNextRequest(nextRequest, future); } }; From 3c172e63144d1116c0f24a994a314509a70ca34d Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 2 Oct 2014 13:36:27 +0200 Subject: [PATCH 648/701] [maven-release-plugin] prepare release async-http-client-1.9.0-BETA17 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index caffa38820..9a63525d28 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.9.0-SNAPSHOT + 1.9.0-BETA17 jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From 9714f7a377ff7b1e86952bd7d65bc91c3c6c71c4 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 2 Oct 2014 13:36:31 +0200 Subject: [PATCH 649/701] [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 9a63525d28..caffa38820 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.9.0-BETA17 + 1.9.0-SNAPSHOT jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From d8a19aee3eb13d769e505faa8f6ebcc6c1352fa8 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 2 Oct 2014 16:39:52 +0200 Subject: [PATCH 650/701] Dead code --- src/main/java/com/ning/http/client/ProxyServer.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/main/java/com/ning/http/client/ProxyServer.java b/src/main/java/com/ning/http/client/ProxyServer.java index 30a5594dac..de65d399de 100644 --- a/src/main/java/com/ning/http/client/ProxyServer.java +++ b/src/main/java/com/ning/http/client/ProxyServer.java @@ -82,10 +82,6 @@ public Protocol getProtocol() { return protocol; } - public String getProtocolAsString() { - return protocol.toString(); - } - public String getHost() { return host; } From 43bfdb2b733d64c5c36f739a9e5d1659d7e4091d Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 3 Oct 2014 13:28:00 +0200 Subject: [PATCH 651/701] Ignore Domain and Host in NTLM Type1Message --- .../com/ning/http/client/ntlm/NTLMEngine.java | 468 +++++++----------- .../grizzly/GrizzlyAsyncHttpProvider.java | 2 +- .../providers/netty/handler/HttpProtocol.java | 2 +- .../netty/request/NettyRequestFactory.java | 23 +- 4 files changed, 181 insertions(+), 314 deletions(-) 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 48226ea5fc..2cd0479338 100644 --- a/src/main/java/com/ning/http/client/ntlm/NTLMEngine.java +++ b/src/main/java/com/ning/http/client/ntlm/NTLMEngine.java @@ -24,15 +24,19 @@ * . * */ +// fork from Apache HttpComponents package com.ning.http.client.ntlm; +import static java.nio.charset.StandardCharsets.US_ASCII; + import com.ning.http.util.Base64; import javax.crypto.Cipher; import javax.crypto.spec.SecretKeySpec; import java.io.UnsupportedEncodingException; -import java.nio.charset.StandardCharsets; +import java.nio.charset.Charset; +import java.nio.charset.UnsupportedCharsetException; import java.security.Key; import java.security.MessageDigest; import java.util.Arrays; @@ -48,26 +52,40 @@ public final class NTLMEngine { public static final NTLMEngine INSTANCE = new NTLMEngine(); + /** Unicode encoding */ + private static final Charset UNICODE_LITTLE_UNMARKED; + + static { + Charset c; + try { + c = Charset.forName("UnicodeLittleUnmarked"); + } catch (UnsupportedCharsetException e) { + c = null; + } + UNICODE_LITTLE_UNMARKED = c; + } + + private static final byte[] MAGIC_CONSTANT = "KGS!@#$%".getBytes(US_ASCII); + // Flags we use; descriptions according to: // http://davenport.sourceforge.net/ntlm.html // and // http://msdn.microsoft.com/en-us/library/cc236650%28v=prot.20%29.aspx - protected static final int FLAG_REQUEST_UNICODE_ENCODING = 0x00000001; // Unicode string encoding requested - protected static final int FLAG_REQUEST_TARGET = 0x00000004; // Requests target field - protected static final int FLAG_REQUEST_SIGN = 0x00000010; // Requests all messages have a signature attached, in NEGOTIATE message. - protected static final int FLAG_REQUEST_SEAL = 0x00000020; // Request key exchange for message confidentiality in NEGOTIATE message. MUST be used in conjunction with 56BIT. - protected static final int FLAG_REQUEST_LAN_MANAGER_KEY = 0x00000080; // Request Lan Manager key instead of user session key - protected static final int FLAG_REQUEST_NTLMv1 = 0x00000200; // Request NTLMv1 security. MUST be set in NEGOTIATE and CHALLENGE both - protected static final int FLAG_DOMAIN_PRESENT = 0x00001000; // Domain is present in message - protected static final int FLAG_WORKSTATION_PRESENT = 0x00002000; // Workstation is present in message - protected static final int FLAG_REQUEST_ALWAYS_SIGN = 0x00008000; // Requests a signature block on all messages. Overridden by REQUEST_SIGN and REQUEST_SEAL. - protected static final int FLAG_REQUEST_NTLM2_SESSION = 0x00080000; // From server in challenge, requesting NTLM2 session security - protected static final int FLAG_REQUEST_VERSION = 0x02000000; // Request protocol version - protected static final int FLAG_TARGETINFO_PRESENT = 0x00800000; // From server in challenge message, indicating targetinfo is present - protected static final int FLAG_REQUEST_128BIT_KEY_EXCH = 0x20000000; // Request explicit 128-bit key exchange - protected static final int FLAG_REQUEST_EXPLICIT_KEY_EXCH = 0x40000000; // Request explicit key exchange - protected static final int FLAG_REQUEST_56BIT_ENCRYPTION = 0x80000000; // Must be used in conjunction with SEAL - + private static final int FLAG_REQUEST_UNICODE_ENCODING = 0x00000001; // Unicode string encoding requested + private static final int FLAG_REQUEST_TARGET = 0x00000004; // Requests target field + private static final int FLAG_REQUEST_SIGN = 0x00000010; // Requests all messages have a signature attached, in NEGOTIATE message. + private static final int FLAG_REQUEST_SEAL = 0x00000020; // Request key exchange for message confidentiality in NEGOTIATE message. MUST be used in conjunction with 56BIT. + private static final int FLAG_REQUEST_LAN_MANAGER_KEY = 0x00000080; // Request Lan Manager key instead of user session key + private static final int FLAG_REQUEST_NTLMv1 = 0x00000200; // Request NTLMv1 security. MUST be set in NEGOTIATE and CHALLENGE both + private static final int FLAG_DOMAIN_PRESENT = 0x00001000; // Domain is present in message + private static final int FLAG_WORKSTATION_PRESENT = 0x00002000; // Workstation is present in message + private static final int FLAG_REQUEST_ALWAYS_SIGN = 0x00008000; // Requests a signature block on all messages. Overridden by REQUEST_SIGN and REQUEST_SEAL. + private static final int FLAG_REQUEST_NTLM2_SESSION = 0x00080000; // From server in challenge, requesting NTLM2 session security + private static final int FLAG_REQUEST_VERSION = 0x02000000; // Request protocol version + private static final int FLAG_TARGETINFO_PRESENT = 0x00800000; // From server in challenge message, indicating targetinfo is present + private static final int FLAG_REQUEST_128BIT_KEY_EXCH = 0x20000000; // Request explicit 128-bit key exchange + private static final int FLAG_REQUEST_EXPLICIT_KEY_EXCH = 0x40000000; // Request explicit key exchange + private static final int FLAG_REQUEST_56BIT_ENCRYPTION = 0x80000000; // Must be used in conjunction with SEAL /** Secure random generator */ private static final java.security.SecureRandom RND_GEN; @@ -84,57 +102,13 @@ public final class NTLMEngine { private static final byte[] SIGNATURE; static { - final byte[] bytesWithoutNull = "NTLMSSP".getBytes(StandardCharsets.US_ASCII); + final byte[] bytesWithoutNull = "NTLMSSP".getBytes(US_ASCII); SIGNATURE = new byte[bytesWithoutNull.length + 1]; System.arraycopy(bytesWithoutNull, 0, SIGNATURE, 0, bytesWithoutNull.length); SIGNATURE[bytesWithoutNull.length] = (byte) 0x00; } - /** - * Returns the response for the given message. - * - * @param message - * the message that was received from the server. - * @param username - * the username to authenticate with. - * @param password - * the password to authenticate with. - * @param host - * The host. - * @param domain - * the NT domain to authenticate in. - * @return The response. - * @throws org.apache.http.HttpException - * If the messages cannot be retrieved. - */ - final String getResponseFor(final String message, final String username, final String password, - final String host, final String domain) throws NTLMEngineException { - - final String response; - if (message == null || message.trim().equals("")) { - response = getType1Message(host, domain); - } else { - final Type2Message t2m = new Type2Message(message); - response = getType3Message(username, password, host, domain, t2m.getChallenge(), t2m - .getFlags(), t2m.getTarget(), t2m.getTargetInfo()); - } - return response; - } - - /** - * Creates the first message (type 1 message) in the NTLM authentication - * sequence. This message includes the user name, domain and host for the - * authentication session. - * - * @param host - * the computer name of the host requesting authentication. - * @param domain - * The domain to authenticate with. - * @return String the message to add to the HTTP request header. - */ - String getType1Message(final String host, final String domain) throws NTLMEngineException { - return new Type1Message(domain, host).getResponse(); - } + private static final String TYPE_1_MESSAGE = new Type1Message().getResponse(); /** * Creates the type 3 message using the given server nonce. The type 3 @@ -154,13 +128,11 @@ String getType1Message(final String host, final String domain) throws NTLMEngine * the 8 byte array the server sent. * @return The type 3 message. * @throws NTLMEngineException - * If {@link #RC4(byte[],byte[])} fails. + * If {@encrypt(byte[],byte[])} fails. */ - String getType3Message(final String user, final String password, final String host, final String domain, - final byte[] nonce, final int type2Flags, final String target, final byte[] targetInformation) - throws NTLMEngineException { - return new Type3Message(domain, host, user, password, nonce, type2Flags, target, - targetInformation).getResponse(); + private String getType3Message(final String user, final String password, final String host, final String domain, final byte[] nonce, + final int type2Flags, final String target, final byte[] targetInformation) throws NTLMEngineException { + return new Type3Message(domain, host, user, password, nonce, type2Flags, target, targetInformation).getResponse(); } /** Strip dot suffix from a name */ @@ -189,8 +161,7 @@ private static int readULong(final byte[] src, final int index) throws NTLMEngin if (src.length < index + 4) { throw new NTLMEngineException("NTLM authentication - buffer too small for DWORD"); } - return (src[index] & 0xff) | ((src[index + 1] & 0xff) << 8) - | ((src[index + 2] & 0xff) << 16) | ((src[index + 3] & 0xff) << 24); + return (src[index] & 0xff) | ((src[index + 1] & 0xff) << 8) | ((src[index + 2] & 0xff) << 16) | ((src[index + 3] & 0xff) << 24); } private static int readUShort(final byte[] src, final int index) throws NTLMEngineException { @@ -204,8 +175,7 @@ private static byte[] readSecurityBuffer(final byte[] src, final int index) thro final int length = readUShort(src, index); final int offset = readULong(src, index + 4); if (src.length < offset + length) { - throw new NTLMEngineException( - "NTLM authentication - buffer too small for data item"); + throw new NTLMEngineException("NTLM authentication - buffer too small for data item"); } final byte[] buffer = new byte[length]; System.arraycopy(src, offset, buffer, 0, length); @@ -236,7 +206,7 @@ private static byte[] makeSecondaryKey() throws NTLMEngineException { return rval; } - protected static class CipherGen { + private static class CipherGen { protected final String domain; protected final String user; @@ -269,10 +239,9 @@ protected static class CipherGen { protected byte[] ntlm2SessionResponseUserSessionKey = null; protected byte[] lanManagerSessionKey = null; - public CipherGen(final String domain, final String user, final String password, - final byte[] challenge, final String target, final byte[] targetInformation, - final byte[] clientChallenge, final byte[] clientChallenge2, - final byte[] secondaryKey, final byte[] timestamp) { + public CipherGen(final String domain, final String user, final String password, final byte[] challenge, final String target, + final byte[] targetInformation, final byte[] clientChallenge, final byte[] clientChallenge2, final byte[] secondaryKey, + final byte[] timestamp) { this.domain = domain; this.target = target; this.user = user; @@ -285,14 +254,13 @@ public CipherGen(final String domain, final String user, final String password, this.timestamp = timestamp; } - public CipherGen(final String domain, final String user, final String password, - final byte[] challenge, final String target, final byte[] targetInformation) { + public CipherGen(final String domain, final String user, final String password, final byte[] challenge, final String target, + final byte[] targetInformation) { this(domain, user, password, challenge, target, targetInformation, null, null, null, null); } /** Calculate and return client challenge */ - public byte[] getClientChallenge() - throws NTLMEngineException { + public byte[] getClientChallenge() throws NTLMEngineException { if (clientChallenge == null) { clientChallenge = makeRandomChallenge(); } @@ -300,8 +268,7 @@ public byte[] getClientChallenge() } /** Calculate and return second client challenge */ - public byte[] getClientChallenge2() - throws NTLMEngineException { + public byte[] getClientChallenge2() throws NTLMEngineException { if (clientChallenge2 == null) { clientChallenge2 = makeRandomChallenge(); } @@ -309,8 +276,7 @@ public byte[] getClientChallenge2() } /** Calculate and return random secondary key */ - public byte[] getSecondaryKey() - throws NTLMEngineException { + public byte[] getSecondaryKey() throws NTLMEngineException { if (secondaryKey == null) { secondaryKey = makeSecondaryKey(); } @@ -318,8 +284,7 @@ public byte[] getSecondaryKey() } /** Calculate and return the LMHash */ - public byte[] getLMHash() - throws NTLMEngineException { + public byte[] getLMHash() throws NTLMEngineException { if (lmHash == null) { lmHash = lmHash(password); } @@ -327,17 +292,15 @@ public byte[] getLMHash() } /** Calculate and return the LMResponse */ - public byte[] getLMResponse() - throws NTLMEngineException { + public byte[] getLMResponse() throws NTLMEngineException { if (lmResponse == null) { - lmResponse = lmResponse(getLMHash(),challenge); + lmResponse = lmResponse(getLMHash(), challenge); } return lmResponse; } /** Calculate and return the NTLMHash */ - public byte[] getNTLMHash() - throws NTLMEngineException { + public byte[] getNTLMHash() throws NTLMEngineException { if (ntlmHash == null) { ntlmHash = ntlmHash(password); } @@ -345,17 +308,15 @@ public byte[] getNTLMHash() } /** Calculate and return the NTLMResponse */ - public byte[] getNTLMResponse() - throws NTLMEngineException { + public byte[] getNTLMResponse() throws NTLMEngineException { if (ntlmResponse == null) { - ntlmResponse = lmResponse(getNTLMHash(),challenge); + ntlmResponse = lmResponse(getNTLMHash(), challenge); } return ntlmResponse; } /** Calculate the LMv2 hash */ - public byte[] getLMv2Hash() - throws NTLMEngineException { + public byte[] getLMv2Hash() throws NTLMEngineException { if (lmv2Hash == null) { lmv2Hash = lmv2Hash(domain, user, getNTLMHash()); } @@ -363,8 +324,7 @@ public byte[] getLMv2Hash() } /** Calculate the NTLMv2 hash */ - public byte[] getNTLMv2Hash() - throws NTLMEngineException { + public byte[] getNTLMv2Hash() throws NTLMEngineException { if (ntlmv2Hash == null) { ntlmv2Hash = ntlmv2Hash(domain, user, getNTLMHash()); } @@ -388,8 +348,7 @@ public byte[] getTimestamp() { } /** Calculate the NTLMv2Blob */ - public byte[] getNTLMv2Blob() - throws NTLMEngineException { + public byte[] getNTLMv2Blob() throws NTLMEngineException { if (ntlmv2Blob == null) { ntlmv2Blob = createBlob(getClientChallenge2(), targetInformation, getTimestamp()); } @@ -397,47 +356,42 @@ public byte[] getNTLMv2Blob() } /** Calculate the NTLMv2Response */ - public byte[] getNTLMv2Response() - throws NTLMEngineException { + public byte[] getNTLMv2Response() throws NTLMEngineException { if (ntlmv2Response == null) { - ntlmv2Response = lmv2Response(getNTLMv2Hash(),challenge,getNTLMv2Blob()); + ntlmv2Response = lmv2Response(getNTLMv2Hash(), challenge, getNTLMv2Blob()); } return ntlmv2Response; } /** Calculate the LMv2Response */ - public byte[] getLMv2Response() - throws NTLMEngineException { + public byte[] getLMv2Response() throws NTLMEngineException { if (lmv2Response == null) { - lmv2Response = lmv2Response(getLMv2Hash(),challenge,getClientChallenge()); + lmv2Response = lmv2Response(getLMv2Hash(), challenge, getClientChallenge()); } return lmv2Response; } /** Get NTLM2SessionResponse */ - public byte[] getNTLM2SessionResponse() - throws NTLMEngineException { + public byte[] getNTLM2SessionResponse() throws NTLMEngineException { if (ntlm2SessionResponse == null) { - ntlm2SessionResponse = ntlm2SessionResponse(getNTLMHash(),challenge,getClientChallenge()); + ntlm2SessionResponse = ntlm2SessionResponse(getNTLMHash(), challenge, getClientChallenge()); } return ntlm2SessionResponse; } /** Calculate and return LM2 session response */ - public byte[] getLM2SessionResponse() - throws NTLMEngineException { + public byte[] getLM2SessionResponse() throws NTLMEngineException { if (lm2SessionResponse == null) { - final byte[] clChallenge = getClientChallenge(); + final byte[] clntChallenge = getClientChallenge(); lm2SessionResponse = new byte[24]; - System.arraycopy(clChallenge, 0, lm2SessionResponse, 0, clChallenge.length); - Arrays.fill(lm2SessionResponse, clChallenge.length, lm2SessionResponse.length, (byte) 0x00); + System.arraycopy(clntChallenge, 0, lm2SessionResponse, 0, clntChallenge.length); + Arrays.fill(lm2SessionResponse, clntChallenge.length, lm2SessionResponse.length, (byte) 0x00); } return lm2SessionResponse; } /** Get LMUserSessionKey */ - public byte[] getLMUserSessionKey() - throws NTLMEngineException { + public byte[] getLMUserSessionKey() throws NTLMEngineException { if (lmUserSessionKey == null) { lmUserSessionKey = new byte[16]; System.arraycopy(getLMHash(), 0, lmUserSessionKey, 0, 8); @@ -447,8 +401,7 @@ public byte[] getLMUserSessionKey() } /** Get NTLMUserSessionKey */ - public byte[] getNTLMUserSessionKey() - throws NTLMEngineException { + public byte[] getNTLMUserSessionKey() throws NTLMEngineException { if (ntlmUserSessionKey == null) { final MD4 md4 = new MD4(); md4.update(getNTLMHash()); @@ -458,8 +411,7 @@ public byte[] getNTLMUserSessionKey() } /** GetNTLMv2UserSessionKey */ - public byte[] getNTLMv2UserSessionKey() - throws NTLMEngineException { + public byte[] getNTLMv2UserSessionKey() throws NTLMEngineException { if (ntlmv2UserSessionKey == null) { final byte[] ntlmv2hash = getNTLMv2Hash(); final byte[] truncatedResponse = new byte[16]; @@ -470,26 +422,24 @@ public byte[] getNTLMv2UserSessionKey() } /** Get NTLM2SessionResponseUserSessionKey */ - public byte[] getNTLM2SessionResponseUserSessionKey() - throws NTLMEngineException { + public byte[] getNTLM2SessionResponseUserSessionKey() throws NTLMEngineException { if (ntlm2SessionResponseUserSessionKey == null) { final byte[] ntlm2SessionResponseNonce = getLM2SessionResponse(); final byte[] sessionNonce = new byte[challenge.length + ntlm2SessionResponseNonce.length]; System.arraycopy(challenge, 0, sessionNonce, 0, challenge.length); System.arraycopy(ntlm2SessionResponseNonce, 0, sessionNonce, challenge.length, ntlm2SessionResponseNonce.length); - ntlm2SessionResponseUserSessionKey = hmacMD5(sessionNonce,getNTLMUserSessionKey()); + ntlm2SessionResponseUserSessionKey = hmacMD5(sessionNonce, getNTLMUserSessionKey()); } return ntlm2SessionResponseUserSessionKey; } /** Get LAN Manager session key */ - public byte[] getLanManagerSessionKey() - throws NTLMEngineException { + public byte[] getLanManagerSessionKey() throws NTLMEngineException { if (lanManagerSessionKey == null) { try { final byte[] keyBytes = new byte[14]; System.arraycopy(getLMHash(), 0, keyBytes, 0, 8); - Arrays.fill(keyBytes, 8, keyBytes.length, (byte)0xbd); + Arrays.fill(keyBytes, 8, keyBytes.length, (byte) 0xbd); final Key lowKey = createDESKey(keyBytes, 0); final Key highKey = createDESKey(keyBytes, 7); final byte[] truncatedResponse = new byte[8]; @@ -512,16 +462,14 @@ public byte[] getLanManagerSessionKey() } /** Calculates HMAC-MD5 */ - static byte[] hmacMD5(final byte[] value, final byte[] key) - throws NTLMEngineException { + private static byte[] hmacMD5(final byte[] value, final byte[] key) throws NTLMEngineException { final HMACMD5 hmacMD5 = new HMACMD5(key); hmacMD5.update(value); return hmacMD5.getOutput(); } /** Calculates RC4 */ - static byte[] RC4(final byte[] value, final byte[] key) - throws NTLMEngineException { + private static byte[] RC4(final byte[] value, final byte[] key) throws NTLMEngineException { try { final Cipher rc4 = Cipher.getInstance("RC4"); rc4.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "RC4")); @@ -539,8 +487,8 @@ static byte[] RC4(final byte[] value, final byte[] key) * field of the Type 3 message; the LM response field contains the * client challenge, null-padded to 24 bytes. */ - static byte[] ntlm2SessionResponse(final byte[] ntlmHash, final byte[] challenge, - final byte[] clientChallenge) throws NTLMEngineException { + private static byte[] ntlm2SessionResponse(final byte[] ntlmHash, final byte[] challenge, final byte[] clientChallenge) + throws NTLMEngineException { try { // Look up MD5 algorithm (was necessary on jdk 1.4.2) // This used to be needed, but java 1.5.0_07 includes the MD5 @@ -582,18 +530,17 @@ static byte[] ntlm2SessionResponse(final byte[] ntlmHash, final byte[] challenge */ private static byte[] lmHash(final String password) throws NTLMEngineException { try { - final byte[] oemPassword = password.toUpperCase(Locale.ENGLISH).getBytes("US-ASCII"); + final byte[] oemPassword = password.toUpperCase(Locale.ROOT).getBytes(US_ASCII); final int length = Math.min(oemPassword.length, 14); final byte[] keyBytes = new byte[14]; System.arraycopy(oemPassword, 0, keyBytes, 0, length); final Key lowKey = createDESKey(keyBytes, 0); final Key highKey = createDESKey(keyBytes, 7); - final byte[] magicConstant = "KGS!@#$%".getBytes("US-ASCII"); final Cipher des = Cipher.getInstance("DES/ECB/NoPadding"); des.init(Cipher.ENCRYPT_MODE, lowKey); - final byte[] lowHash = des.doFinal(magicConstant); + final byte[] lowHash = des.doFinal(MAGIC_CONSTANT); des.init(Cipher.ENCRYPT_MODE, highKey); - final byte[] highHash = des.doFinal(magicConstant); + final byte[] highHash = des.doFinal(MAGIC_CONSTANT); final byte[] lmHash = new byte[16]; System.arraycopy(lowHash, 0, lmHash, 0, 8); System.arraycopy(highHash, 0, lmHash, 8, 8); @@ -613,14 +560,13 @@ private static byte[] lmHash(final String password) throws NTLMEngineException { * the NTLM Response and the NTLMv2 and LMv2 Hashes. */ private static byte[] ntlmHash(final String password) throws NTLMEngineException { - try { - final byte[] unicodePassword = password.getBytes("UnicodeLittleUnmarked"); - final MD4 md4 = new MD4(); - md4.update(unicodePassword); - return md4.getOutput(); - } catch (final UnsupportedEncodingException e) { - throw new NTLMEngineException("Unicode not supported: " + e.getMessage(), e); + if (UNICODE_LITTLE_UNMARKED == null) { + throw new NTLMEngineException("Unicode not supported"); } + final byte[] unicodePassword = password.getBytes(UNICODE_LITTLE_UNMARKED); + final MD4 md4 = new MD4(); + md4.update(unicodePassword); + return md4.getOutput(); } /** @@ -629,19 +575,17 @@ private static byte[] ntlmHash(final String password) throws NTLMEngineException * @return The LMv2 Hash, used in the calculation of the NTLMv2 and LMv2 * Responses. */ - private static byte[] lmv2Hash(final String domain, final String user, final byte[] ntlmHash) - throws NTLMEngineException { - try { - final HMACMD5 hmacMD5 = new HMACMD5(ntlmHash); - // Upper case username, upper case domain! - hmacMD5.update(user.toUpperCase(Locale.ENGLISH).getBytes("UnicodeLittleUnmarked")); - if (domain != null) { - hmacMD5.update(domain.toUpperCase(Locale.ENGLISH).getBytes("UnicodeLittleUnmarked")); - } - return hmacMD5.getOutput(); - } catch (final UnsupportedEncodingException e) { - throw new NTLMEngineException("Unicode not supported! " + e.getMessage(), e); + private static byte[] lmv2Hash(final String domain, final String user, final byte[] ntlmHash) throws NTLMEngineException { + if (UNICODE_LITTLE_UNMARKED == null) { + throw new NTLMEngineException("Unicode not supported"); } + final HMACMD5 hmacMD5 = new HMACMD5(ntlmHash); + // Upper case username, upper case domain! + hmacMD5.update(user.toUpperCase(Locale.ROOT).getBytes(UNICODE_LITTLE_UNMARKED)); + if (domain != null) { + hmacMD5.update(domain.toUpperCase(Locale.ROOT).getBytes(UNICODE_LITTLE_UNMARKED)); + } + return hmacMD5.getOutput(); } /** @@ -650,19 +594,17 @@ private static byte[] lmv2Hash(final String domain, final String user, final byt * @return The NTLMv2 Hash, used in the calculation of the NTLMv2 and LMv2 * Responses. */ - private static byte[] ntlmv2Hash(final String domain, final String user, final byte[] ntlmHash) - throws NTLMEngineException { - try { - final HMACMD5 hmacMD5 = new HMACMD5(ntlmHash); - // Upper case username, mixed case target!! - hmacMD5.update(user.toUpperCase(Locale.ENGLISH).getBytes("UnicodeLittleUnmarked")); - if (domain != null) { - hmacMD5.update(domain.getBytes("UnicodeLittleUnmarked")); - } - return hmacMD5.getOutput(); - } catch (final UnsupportedEncodingException e) { - throw new NTLMEngineException("Unicode not supported! " + e.getMessage(), e); + private static byte[] ntlmv2Hash(final String domain, final String user, final byte[] ntlmHash) throws NTLMEngineException { + if (UNICODE_LITTLE_UNMARKED == null) { + throw new NTLMEngineException("Unicode not supported"); } + final HMACMD5 hmacMD5 = new HMACMD5(ntlmHash); + // Upper case username, mixed case target!! + hmacMD5.update(user.toUpperCase(Locale.ROOT).getBytes(UNICODE_LITTLE_UNMARKED)); + if (domain != null) { + hmacMD5.update(domain.getBytes(UNICODE_LITTLE_UNMARKED)); + } + return hmacMD5.getOutput(); } /** @@ -713,8 +655,7 @@ private static byte[] lmResponse(final byte[] hash, final byte[] challenge) thro * @return The response (either NTLMv2 or LMv2, depending on the client * data). */ - private static byte[] lmv2Response(final byte[] hash, final byte[] challenge, final byte[] clientData) - throws NTLMEngineException { + private static byte[] lmv2Response(final byte[] hash, final byte[] challenge, final byte[] clientData) throws NTLMEngineException { final HMACMD5 hmacMD5 = new HMACMD5(hash); hmacMD5.update(challenge); hmacMD5.update(clientData); @@ -741,8 +682,8 @@ private static byte[] createBlob(final byte[] clientChallenge, final byte[] targ final byte[] reserved = new byte[] { (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00 }; final byte[] unknown1 = new byte[] { (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00 }; final byte[] unknown2 = new byte[] { (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00 }; - final byte[] blob = new byte[blobSignature.length + reserved.length + timestamp.length + 8 - + unknown1.length + targetInformation.length + unknown2.length]; + final byte[] blob = new byte[blobSignature.length + reserved.length + timestamp.length + 8 + unknown1.length + + targetInformation.length + unknown2.length]; int offset = 0; System.arraycopy(blobSignature, 0, blob, offset, blobSignature.length); offset += blobSignature.length; @@ -798,8 +739,7 @@ private static Key createDESKey(final byte[] bytes, final int offset) { private static void oddParity(final byte[] bytes) { for (int i = 0; i < bytes.length; i++) { final byte b = bytes[i]; - final boolean needsParity = (((b >>> 7) ^ (b >>> 6) ^ (b >>> 5) ^ (b >>> 4) ^ (b >>> 3) - ^ (b >>> 2) ^ (b >>> 1)) & 0x01) == 0; + final boolean needsParity = (((b >>> 7) ^ (b >>> 6) ^ (b >>> 5) ^ (b >>> 4) ^ (b >>> 3) ^ (b >>> 2) ^ (b >>> 1)) & 0x01) == 0; if (needsParity) { bytes[i] |= (byte) 0x01; } else { @@ -809,7 +749,7 @@ private static void oddParity(final byte[] bytes) { } /** NTLM message generation, base class */ - static class NTLMMessage { + private static class NTLMMessage { /** The current response */ private byte[] messageContents = null; @@ -830,8 +770,7 @@ static class NTLMMessage { int i = 0; while (i < SIGNATURE.length) { if (messageContents[i] != SIGNATURE[i]) { - throw new NTLMEngineException( - "NTLM message expected - instead got unrecognized bytes"); + throw new NTLMEngineException("NTLM message expected - instead got unrecognized bytes"); } i++; } @@ -839,8 +778,8 @@ static class NTLMMessage { // Check to be sure there's a type 2 message indicator next final int type = readULong(SIGNATURE.length); if (type != expectedType) { - throw new NTLMEngineException("NTLM type " + Integer.toString(expectedType) - + " message expected - instead got type " + Integer.toString(type)); + throw new NTLMEngineException("NTLM type " + Integer.toString(expectedType) + " message expected - instead got type " + + Integer.toString(type)); } currentOutputPosition = messageContents.length; @@ -967,27 +906,7 @@ String getResponse() { } /** Type 1 message assembly class */ - static class Type1Message extends NTLMMessage { - // FIXME https://issues.apache.org/jira/browse/HTTPCLIENT-1557 -// protected byte[] hostBytes; -// protected byte[] domainBytes; - - /** Constructor. Include the arguments the message will need */ - Type1Message(final String domain, final String host) throws NTLMEngineException { -// super(); -// try { -// // Strip off domain name from the host! -// final String unqualifiedHost = convertHost(host); -// // Use only the base domain name! -// final String unqualifiedDomain = convertDomain(domain); -// -// hostBytes = unqualifiedHost != null? unqualifiedHost.getBytes("ASCII") : null; -// domainBytes = unqualifiedDomain != null ? unqualifiedDomain -// .toUpperCase(Locale.ENGLISH).getBytes("ASCII") : null; -// } catch (final UnsupportedEncodingException e) { -// throw new NTLMEngineException("Unicode unsupported: " + e.getMessage(), e); -// } - } + private static class Type1Message extends NTLMMessage { /** * Getting the response involves building the message before returning @@ -997,7 +916,7 @@ static class Type1Message extends NTLMMessage { String getResponse() { // Now, build the message. Calculate its length first, including // signature or type. - final int finalLength = 32 + 8 /*+ hostBytes.length + domainBytes.length */; + final int finalLength = 32 + 8; // Set up the response. This will initialize the signature, message // type, and flags. @@ -1005,15 +924,14 @@ String getResponse() { // Flags. These are the complete set of flags we support. addULong( - //FLAG_WORKSTATION_PRESENT | - //FLAG_DOMAIN_PRESENT | + //FLAG_WORKSTATION_PRESENT | + //FLAG_DOMAIN_PRESENT | - // Required flags - //FLAG_REQUEST_LAN_MANAGER_KEY | - FLAG_REQUEST_NTLMv1 | - FLAG_REQUEST_NTLM2_SESSION | + // Required flags + //FLAG_REQUEST_LAN_MANAGER_KEY | + FLAG_REQUEST_NTLMv1 | FLAG_REQUEST_NTLM2_SESSION | - // Protocol version request + // Protocol version request FLAG_REQUEST_VERSION | // Recommended privacy settings @@ -1022,25 +940,24 @@ String getResponse() { //FLAG_REQUEST_SIGN | // These must be set according to documentation, based on use of SEAL above - FLAG_REQUEST_128BIT_KEY_EXCH | - FLAG_REQUEST_56BIT_ENCRYPTION | + FLAG_REQUEST_128BIT_KEY_EXCH | FLAG_REQUEST_56BIT_ENCRYPTION | //FLAG_REQUEST_EXPLICIT_KEY_EXCH | FLAG_REQUEST_UNICODE_ENCODING); // Domain length (two times). - addUShort(/*domainBytes.length*/0); - addUShort(/*domainBytes.length*/0); + addUShort(0); + addUShort(0); // Domain offset. - addULong(/*hostBytes.length +*/ 32 + 8); + addULong(finalLength); // Host length (two times). - addUShort(/*hostBytes.length*/0); - addUShort(/*hostBytes.length*/0); + addUShort(0); + addUShort(0); // Host offset (always 32 + 8). - addULong(32 + 8); + addULong(finalLength); // Version addUShort(0x0105); @@ -1049,17 +966,8 @@ String getResponse() { // NTLM revision addUShort(0x0f00); - - // Host (workstation) String. - //addBytes(hostBytes); - - // Domain String. - //addBytes(domainBytes); - - return super.getResponse(); } - } /** Type 2 message class */ @@ -1093,9 +1001,7 @@ static class Type2Message extends NTLMMessage { flags = readULong(20); if ((flags & FLAG_REQUEST_UNICODE_ENCODING) == 0) { - throw new NTLMEngineException( - "NTLM type 2 message has flags that make no sense: " - + Integer.toString(flags)); + throw new NTLMEngineException("NTLM type 2 message indicates no support for Unicode. Flags are: " + Integer.toString(flags)); } // Do the target! @@ -1160,11 +1066,9 @@ static class Type3Message extends NTLMMessage { protected byte[] ntResp; protected byte[] sessionKey; - /** Constructor. Pass the arguments we will need */ Type3Message(final String domain, final String host, final String user, final String password, final byte[] nonce, - final int type2Flags, final String target, final byte[] targetInformation) - throws NTLMEngineException { + final int type2Flags, final String target, final byte[] targetInformation) throws NTLMEngineException { // Save the flags this.type2Flags = type2Flags; @@ -1182,8 +1086,7 @@ static class Type3Message extends NTLMMessage { try { // This conditional may not work on Windows Server 2008 R2 and above, where it has not yet // been tested - if (((type2Flags & FLAG_TARGETINFO_PRESENT) != 0) && - targetInformation != null && target != null) { + if (((type2Flags & FLAG_TARGETINFO_PRESENT) != 0) && targetInformation != null && target != null) { // NTLMv2 ntResp = gen.getNTLMv2Response(); lmResp = gen.getLMv2Response(); @@ -1234,16 +1137,12 @@ static class Type3Message extends NTLMMessage { } else { sessionKey = null; } - - try { - hostBytes = unqualifiedHost != null ? unqualifiedHost - .getBytes("UnicodeLittleUnmarked") : null; - domainBytes = unqualifiedDomain != null ? unqualifiedDomain - .toUpperCase(Locale.ENGLISH).getBytes("UnicodeLittleUnmarked") : null; - userBytes = user.getBytes("UnicodeLittleUnmarked"); - } catch (final UnsupportedEncodingException e) { - throw new NTLMEngineException("Unicode not supported: " + e.getMessage(), e); + if (UNICODE_LITTLE_UNMARKED == null) { + throw new NTLMEngineException("Unicode not supported"); } + hostBytes = unqualifiedHost != null ? unqualifiedHost.getBytes(UNICODE_LITTLE_UNMARKED) : null; + domainBytes = unqualifiedDomain != null ? unqualifiedDomain.toUpperCase(Locale.ROOT).getBytes(UNICODE_LITTLE_UNMARKED) : null; + userBytes = user.getBytes(UNICODE_LITTLE_UNMARKED); } /** Assemble the response */ @@ -1253,7 +1152,7 @@ String getResponse() { final int lmRespLen = lmResp.length; final int domainLen = domainBytes != null ? domainBytes.length : 0; - final int hostLen = hostBytes != null ? hostBytes.length: 0; + final int hostLen = hostBytes != null ? hostBytes.length : 0; final int userLen = userBytes.length; final int sessionKeyLen; if (sessionKey != null) { @@ -1263,7 +1162,7 @@ String getResponse() { } // Calculate the layout within the packet - final int lmRespOffset = 72; // allocate space for the version + final int lmRespOffset = 72; // allocate space for the version final int ntRespOffset = lmRespOffset + lmRespLen; final int domainOffset = ntRespOffset + ntRespLen; final int userOffset = domainOffset + domainLen; @@ -1318,31 +1217,30 @@ String getResponse() { // Flags. addULong( - //FLAG_WORKSTATION_PRESENT | - //FLAG_DOMAIN_PRESENT | + //FLAG_WORKSTATION_PRESENT | + //FLAG_DOMAIN_PRESENT | - // Required flags - (type2Flags & FLAG_REQUEST_LAN_MANAGER_KEY) | - (type2Flags & FLAG_REQUEST_NTLMv1) | - (type2Flags & FLAG_REQUEST_NTLM2_SESSION) | + // Required flags + (type2Flags & FLAG_REQUEST_LAN_MANAGER_KEY) + | (type2Flags & FLAG_REQUEST_NTLMv1) + | (type2Flags & FLAG_REQUEST_NTLM2_SESSION) + | // Protocol version request - FLAG_REQUEST_VERSION | + FLAG_REQUEST_VERSION + | // Recommended privacy settings - (type2Flags & FLAG_REQUEST_ALWAYS_SIGN) | - (type2Flags & FLAG_REQUEST_SEAL) | - (type2Flags & FLAG_REQUEST_SIGN) | + (type2Flags & FLAG_REQUEST_ALWAYS_SIGN) | (type2Flags & FLAG_REQUEST_SEAL) + | (type2Flags & FLAG_REQUEST_SIGN) + | // These must be set according to documentation, based on use of SEAL above - (type2Flags & FLAG_REQUEST_128BIT_KEY_EXCH) | - (type2Flags & FLAG_REQUEST_56BIT_ENCRYPTION) | - (type2Flags & FLAG_REQUEST_EXPLICIT_KEY_EXCH) | + (type2Flags & FLAG_REQUEST_128BIT_KEY_EXCH) | (type2Flags & FLAG_REQUEST_56BIT_ENCRYPTION) + | (type2Flags & FLAG_REQUEST_EXPLICIT_KEY_EXCH) | - (type2Flags & FLAG_TARGETINFO_PRESENT) | - (type2Flags & FLAG_REQUEST_UNICODE_ENCODING) | - (type2Flags & FLAG_REQUEST_TARGET) - ); + (type2Flags & FLAG_TARGETINFO_PRESENT) | (type2Flags & FLAG_REQUEST_UNICODE_ENCODING) + | (type2Flags & FLAG_REQUEST_TARGET)); // Version addUShort(0x0105); @@ -1465,8 +1363,7 @@ protected void processBuffer() { final int[] d = new int[16]; for (int i = 0; i < 16; i++) { - d[i] = (dataBuffer[i * 4] & 0xff) + ((dataBuffer[i * 4 + 1] & 0xff) << 8) - + ((dataBuffer[i * 4 + 2] & 0xff) << 16) + d[i] = (dataBuffer[i * 4] & 0xff) + ((dataBuffer[i * 4 + 1] & 0xff) << 8) + ((dataBuffer[i * 4 + 2] & 0xff) << 16) + ((dataBuffer[i * 4 + 3] & 0xff) << 24); } @@ -1550,16 +1447,14 @@ protected void round3(final int[] d) { D = rotintlft((D + H(A, B, C) + d[11] + 0x6ed9eba1), 9); C = rotintlft((C + H(D, A, B) + d[7] + 0x6ed9eba1), 11); B = rotintlft((B + H(C, D, A) + d[15] + 0x6ed9eba1), 15); - } - } /** * Cryptography support - HMACMD5 - algorithmically based on various web * resources by Karl Wright */ - static class HMACMD5 { + private static class HMACMD5 { protected byte[] ipad; protected byte[] opad; protected MessageDigest md5; @@ -1571,8 +1466,7 @@ static class HMACMD5 { } catch (final Exception ex) { // Umm, the algorithm doesn't exist - throw an // NTLMEngineException! - throw new NTLMEngineException( - "Error getting md5 message digest implementation: " + ex.getMessage(), ex); + throw new NTLMEngineException("Error getting md5 message digest implementation: " + ex.getMessage(), ex); } // Initialize the pad buffers with the key @@ -1615,36 +1509,24 @@ byte[] getOutput() { void update(final byte[] input) { md5.update(input); } - - /** Update the algorithm */ - void update(final byte[] input, final int offset, final int length) { - md5.update(input, offset, length); - } - } - public String generateType1Msg( - final String domain, - final String workstation) throws NTLMEngineException { - return getType1Message(workstation, domain); + /** + * Creates the first message (type 1 message) in the NTLM authentication + * sequence. This message includes the user name, domain and host for the + * authentication session. + * + * @return String the message to add to the HTTP request header. + */ + public String generateType1Msg() { + return TYPE_1_MESSAGE; } - public String generateType3Msg( - final String username, - final String password, - final String domain, - final String workstation, + public String generateType3Msg(final String username, final String password, final String domain, final String workstation, final String challenge) throws NTLMEngineException { final Type2Message t2m = new Type2Message(challenge); - return getType3Message( - username, - password, - workstation, - domain, - t2m.getChallenge(), - t2m.getFlags(), - t2m.getTarget(), + return getType3Message(username, password, workstation, domain, t2m.getChallenge(), t2m.getFlags(), t2m.getTarget(), t2m.getTargetInfo()); } -} +} \ No newline at end of file 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 ebb368ffd6..6604d139be 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 @@ -993,7 +993,7 @@ private String generateAuthHeader(final Realm realm) { case DIGEST: return AuthenticatorUtils.computeDigestAuthentication(realm); case NTLM: - return ntlmEngine.generateType1Msg("NTLM " + realm.getNtlmDomain(), realm.getNtlmHost()); + return ntlmEngine.generateType1Msg(); default: return null; } diff --git a/src/main/java/com/ning/http/client/providers/netty/handler/HttpProtocol.java b/src/main/java/com/ning/http/client/providers/netty/handler/HttpProtocol.java index f03c647fe7..d90bb769fe 100644 --- a/src/main/java/com/ning/http/client/providers/netty/handler/HttpProtocol.java +++ b/src/main/java/com/ning/http/client/providers/netty/handler/HttpProtocol.java @@ -119,7 +119,7 @@ private Realm ntlmChallenge(String wwwAuth, Request request, ProxyServer proxySe if (wwwAuth.equals("NTLM")) { // server replied bare NTLM => we didn't preemptively sent Type1Msg - String challengeHeader = NTLMEngine.INSTANCE.generateType1Msg(ntlmDomain, ntlmHost); + String challengeHeader = NTLMEngine.INSTANCE.generateType1Msg(); addNTLMAuthorizationHeader(headers, challengeHeader, proxyInd); future.getAndSetAuth(false); diff --git a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestFactory.java b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestFactory.java index 8da344ed4a..5a89f0c2e9 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestFactory.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestFactory.java @@ -42,7 +42,6 @@ import com.ning.http.client.generators.FileBodyGenerator; import com.ning.http.client.generators.InputStreamBodyGenerator; import com.ning.http.client.ntlm.NTLMEngine; -import com.ning.http.client.ntlm.NTLMEngineException; import com.ning.http.client.providers.netty.NettyAsyncHttpProviderConfig; import com.ning.http.client.providers.netty.request.body.NettyBody; import com.ning.http.client.providers.netty.request.body.NettyBodyBody; @@ -98,18 +97,8 @@ public String firstRequestOnlyAuthorizationHeader(Request request, Uri uri, Prox if (realm != null && realm.getUsePreemptiveAuth()) { switch (realm.getAuthScheme()) { case NTLM: - String domain; - if (proxyServer != null && proxyServer.getNtlmDomain() != null) { - domain = proxyServer.getNtlmDomain(); - } else { - domain = realm.getNtlmDomain(); - } - try { - String msg = NTLMEngine.INSTANCE.generateType1Msg(domain, realm.getNtlmHost()); - authorizationHeader = "NTLM " + msg; - } catch (NTLMEngineException e) { - throw new IOException(e); - } + String msg = NTLMEngine.INSTANCE.generateType1Msg(); + authorizationHeader = "NTLM " + msg; break; case KERBEROS: case SPNEGO: @@ -175,12 +164,8 @@ public String firstRequestOnlyProxyAuthorizationHeader(Request request, ProxySer } else if (proxyServer != null && proxyServer.getPrincipal() != null && isNonEmpty(proxyServer.getNtlmDomain())) { List auth = request.getHeaders().get(HttpHeaders.Names.PROXY_AUTHORIZATION); if (!isNTLM(auth)) { - try { - String msg = NTLMEngine.INSTANCE.generateType1Msg(proxyServer.getNtlmDomain(), proxyServer.getHost()); - proxyAuthorization = "NTLM " + msg; - } catch (NTLMEngineException e) { - throw new IOException(e); - } + String msg = NTLMEngine.INSTANCE.generateType1Msg(); + proxyAuthorization = "NTLM " + msg; } } From 2e783a590e4856a6f51957a959c12281620a4fea Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 9 Oct 2014 16:12:02 +0200 Subject: [PATCH 652/701] Execute shouldn't throw Exceptions, close #710 --- .../com/ning/http/client/AsyncHttpClient.java | 38 +++--- .../ning/http/client/AsyncHttpProvider.java | 5 +- .../ning/http/client/ListenableFuture.java | 59 +++++++++ .../http/client/filter/FilterContext.java | 32 ++--- .../http/client/filter/RequestFilter.java | 3 +- .../http/client/filter/ResponseFilter.java | 3 +- .../grizzly/GrizzlyAsyncHttpProvider.java | 24 ++-- .../providers/jdk/JDKAsyncHttpProvider.java | 9 +- .../netty/NettyAsyncHttpProvider.java | 10 +- .../ning/http/client/async/ChunkingTest.java | 10 +- .../ning/http/client/async/FilterTest.java | 34 ++---- .../client/async/HostnameVerifierTest.java | 24 ++-- .../client/async/MaxConnectionsInThreads.java | 112 +++++++++--------- .../client/async/MaxTotalConnectionTest.java | 95 ++++++--------- .../async/SimpleAsyncHttpClientTest.java | 9 +- .../client/async/TransferListenerTest.java | 7 -- .../GrizzlyFeedableBodyGeneratorTest.java | 94 +++++++-------- 17 files changed, 279 insertions(+), 289 deletions(-) diff --git a/src/main/java/com/ning/http/client/AsyncHttpClient.java b/src/main/java/com/ning/http/client/AsyncHttpClient.java index 10957d03fe..87826e6dd4 100755 --- a/src/main/java/com/ning/http/client/AsyncHttpClient.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClient.java @@ -17,7 +17,6 @@ package com.ning.http.client; import java.io.Closeable; -import java.io.IOException; import java.io.InputStream; import java.lang.reflect.InvocationTargetException; import java.util.Collection; @@ -222,11 +221,11 @@ private BoundRequestBuilder(Request prototype) { super(BoundRequestBuilder.class, prototype); } - public ListenableFuture execute(AsyncHandler handler) throws IOException { + public ListenableFuture execute(AsyncHandler handler) { return AsyncHttpClient.this.executeRequest(build(), handler); } - public ListenableFuture execute() throws IOException { + public ListenableFuture execute() { return AsyncHttpClient.this.executeRequest(build(), new AsyncCompletionHandlerBase()); } @@ -480,17 +479,20 @@ public BoundRequestBuilder prepareRequest(Request request) { * @param handler an instance of {@link AsyncHandler} * @param Type of the value that will be returned by the associated {@link java.util.concurrent.Future} * @return a {@link Future} of type T - * @throws IOException */ - @SuppressWarnings({ "rawtypes", "unchecked" }) - public ListenableFuture executeRequest(Request request, AsyncHandler handler) throws IOException { + public ListenableFuture executeRequest(Request request, AsyncHandler handler) { if (config.getRequestFilters().isEmpty()) { return httpProvider.execute(request, handler); } else { - FilterContext fc = new FilterContext.FilterContextBuilder().asyncHandler(handler).request(request).build(); - fc = preProcessRequest(fc); + FilterContext fc = new FilterContext.FilterContextBuilder().asyncHandler(handler).request(request).build(); + try { + fc = preProcessRequest(fc); + } catch (Exception e) { + handler.onThrowable(e); + return new ListenableFuture.CompletedFailure("preProcessRequest failed", e); + } return httpProvider.execute(fc.getRequest(), fc.getAsyncHandler()); } @@ -501,9 +503,8 @@ public ListenableFuture executeRequest(Request request, AsyncHandler h * * @param request {@link Request} * @return a {@link Future} of type Response - * @throws IOException */ - public ListenableFuture executeRequest(Request request) throws IOException { + public ListenableFuture executeRequest(Request request) { return executeRequest(request, new AsyncCompletionHandlerBase()); } @@ -513,18 +514,11 @@ public ListenableFuture executeRequest(Request request) throws IOExcep * @param fc {@link FilterContext} * @return {@link FilterContext} */ - @SuppressWarnings("rawtypes") - private FilterContext preProcessRequest(FilterContext fc) throws IOException { + private FilterContext preProcessRequest(FilterContext fc) throws FilterException { for (RequestFilter asyncFilter : config.getRequestFilters()) { - try { - fc = asyncFilter.filter(fc); - if (fc == null) { - throw new NullPointerException("FilterContext is null"); - } - } catch (FilterException e) { - IOException ex = new IOException(); - ex.initCause(e); - throw ex; + fc = asyncFilter.filter(fc); + if (fc == null) { + throw new NullPointerException("FilterContext is null"); } } @@ -538,7 +532,7 @@ private FilterContext preProcessRequest(FilterContext fc) throws IOException { builder.setHeader("Range", "bytes=" + request.getRangeOffset() + "-"); request = builder.build(); } - fc = new FilterContext.FilterContextBuilder(fc).request(request).build(); + fc = new FilterContext.FilterContextBuilder(fc).request(request).build(); return fc; } diff --git a/src/main/java/com/ning/http/client/AsyncHttpProvider.java b/src/main/java/com/ning/http/client/AsyncHttpProvider.java index cfde4082d8..1c17df1ea8 100644 --- a/src/main/java/com/ning/http/client/AsyncHttpProvider.java +++ b/src/main/java/com/ning/http/client/AsyncHttpProvider.java @@ -15,8 +15,6 @@ */ package com.ning.http.client; -import java.io.IOException; - /** * Interface to be used when implementing custom asynchronous I/O HTTP client. * By default, the {@link com.ning.http.client.providers.netty.NettyAsyncHttpProvider} is used. @@ -28,9 +26,8 @@ public interface AsyncHttpProvider { * * @param handler an instance of {@link AsyncHandler} * @return a {@link ListenableFuture} of Type T. - * @throws IOException */ - ListenableFuture execute(Request request, AsyncHandler handler) throws IOException; + ListenableFuture execute(Request request, AsyncHandler handler); /** * Close the current underlying TCP/HTTP connection. diff --git a/src/main/java/com/ning/http/client/ListenableFuture.java b/src/main/java/com/ning/http/client/ListenableFuture.java index e2f75fb45d..cc23b272c1 100755 --- a/src/main/java/com/ning/http/client/ListenableFuture.java +++ b/src/main/java/com/ning/http/client/ListenableFuture.java @@ -30,8 +30,11 @@ */ package com.ning.http.client; +import java.util.concurrent.ExecutionException; import java.util.concurrent.Executor; import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; /** * Extended {@link Future} @@ -79,4 +82,60 @@ public interface ListenableFuture extends Future { * immediately but the executor rejected it. */ ListenableFuture addListener(Runnable listener, Executor exec); + + public class CompletedFailure implements ListenableFuture{ + + private final ExecutionException e; + + public CompletedFailure(Throwable t) { + e = new ExecutionException(t); + } + + public CompletedFailure(String message, Throwable t) { + e = new ExecutionException(message, t); + } + + @Override + public boolean cancel(boolean mayInterruptIfRunning) { + return true; + } + + @Override + public boolean isCancelled() { + return false; + } + + @Override + public boolean isDone() { + return true; + } + + @Override + public T get() throws InterruptedException, ExecutionException { + throw e; + } + + @Override + public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { + throw e; + } + + @Override + public void done() { + } + + @Override + public void abort(Throwable t) { + } + + @Override + public void touch() { + } + + @Override + public ListenableFuture addListener(Runnable listener, Executor exec) { + exec.execute(listener); + return this; + } + } } diff --git a/src/main/java/com/ning/http/client/filter/FilterContext.java b/src/main/java/com/ning/http/client/filter/FilterContext.java index 1f564bc11d..6ae5cf4f95 100644 --- a/src/main/java/com/ning/http/client/filter/FilterContext.java +++ b/src/main/java/com/ning/http/client/filter/FilterContext.java @@ -33,15 +33,14 @@ */ public class FilterContext { - @SuppressWarnings("rawtypes") - private final FilterContextBuilder b; + private final FilterContextBuilder b; /** * Create a new {@link FilterContext} * * @param b a {@link FilterContextBuilder} */ - private FilterContext(@SuppressWarnings("rawtypes") FilterContextBuilder b) { + private FilterContext(FilterContextBuilder b) { this.b = b; } @@ -50,7 +49,6 @@ private FilterContext(@SuppressWarnings("rawtypes") FilterContextBuilder b) { * * @return the original or decorated {@link AsyncHandler} */ - @SuppressWarnings("unchecked") public AsyncHandler getAsyncHandler() { return b.asyncHandler; } @@ -109,8 +107,7 @@ public static class FilterContextBuilder { public FilterContextBuilder() { } - @SuppressWarnings({ "rawtypes", "unchecked" }) - public FilterContextBuilder(FilterContext clone) { + public FilterContextBuilder(FilterContext clone) { asyncHandler = clone.getAsyncHandler(); request = clone.getRequest(); responseStatus = clone.getResponseStatus(); @@ -122,8 +119,7 @@ public AsyncHandler getAsyncHandler() { return asyncHandler; } - @SuppressWarnings("rawtypes") - public FilterContextBuilder asyncHandler(AsyncHandler asyncHandler) { + public FilterContextBuilder asyncHandler(AsyncHandler asyncHandler) { this.asyncHandler = asyncHandler; return this; } @@ -132,39 +128,33 @@ public Request getRequest() { return request; } - @SuppressWarnings("rawtypes") - public FilterContextBuilder request(Request request) { + public FilterContextBuilder request(Request request) { this.request = request; return this; } - @SuppressWarnings("rawtypes") - public FilterContextBuilder responseStatus(HttpResponseStatus responseStatus) { + public FilterContextBuilder responseStatus(HttpResponseStatus responseStatus) { this.responseStatus = responseStatus; return this; } - @SuppressWarnings("rawtypes") - public FilterContextBuilder responseHeaders(HttpResponseHeaders headers) { + public FilterContextBuilder responseHeaders(HttpResponseHeaders headers) { this.headers = headers; return this; } - @SuppressWarnings("rawtypes") - public FilterContextBuilder replayRequest(boolean replayRequest) { + public FilterContextBuilder replayRequest(boolean replayRequest) { this.replayRequest = replayRequest; return this; } - @SuppressWarnings("rawtypes") - public FilterContextBuilder ioException(IOException ioException) { + public FilterContextBuilder ioException(IOException ioException) { this.ioException = ioException; return this; } - @SuppressWarnings("rawtypes") - public FilterContext build() { - return new FilterContext(this); + public FilterContext build() { + return new FilterContext(this); } } } diff --git a/src/main/java/com/ning/http/client/filter/RequestFilter.java b/src/main/java/com/ning/http/client/filter/RequestFilter.java index bd10e5b7f6..89a4251386 100644 --- a/src/main/java/com/ning/http/client/filter/RequestFilter.java +++ b/src/main/java/com/ning/http/client/filter/RequestFilter.java @@ -26,6 +26,5 @@ public interface RequestFilter { * @return {@link FilterContext}. The {@link FilterContext} instance may not the same as the original one. * @throws FilterException to interrupt the filter processing. */ - @SuppressWarnings("rawtypes") - FilterContext filter(FilterContext ctx) throws FilterException; + FilterContext filter(FilterContext ctx) throws FilterException; } diff --git a/src/main/java/com/ning/http/client/filter/ResponseFilter.java b/src/main/java/com/ning/http/client/filter/ResponseFilter.java index 4a955aa40f..7177b6fe8a 100644 --- a/src/main/java/com/ning/http/client/filter/ResponseFilter.java +++ b/src/main/java/com/ning/http/client/filter/ResponseFilter.java @@ -29,6 +29,5 @@ public interface ResponseFilter { * @return {@link FilterContext}. The {@link FilterContext} instance may not the same as the original one. * @throws FilterException to interrupt the filter processing. */ - @SuppressWarnings("rawtypes") - FilterContext filter(FilterContext ctx) throws FilterException; + FilterContext filter(FilterContext ctx) throws FilterException; } 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 6604d139be..28666fad1d 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 @@ -202,13 +202,13 @@ public GrizzlyAsyncHttpProvider(final AsyncHttpClientConfig clientConfig) { // ------------------------------------------ Methods from AsyncHttpProvider - @SuppressWarnings({"unchecked"}) @Override - public ListenableFuture execute(final Request request, - final AsyncHandler handler) throws IOException { + public ListenableFuture execute(final Request request, final AsyncHandler handler) { if (clientTransport.isStopped()) { - throw new IOException("AsyncHttpClient has been closed."); + IOException e = new IOException("AsyncHttpClient has been closed."); + handler.onThrowable(e); + return new ListenableFuture.CompletedFailure<>(e); } final ProxyServer proxy = ProxyUtils.getProxyServer(clientConfig, request); final GrizzlyResponseFuture future = new GrizzlyResponseFuture(this, request, handler, proxy); @@ -2908,19 +2908,15 @@ public static void main(String[] args) { .setConnectTimeout(5000) .setSSLContext(sslContext).build(); AsyncHttpClient client = new AsyncHttpClient(new GrizzlyAsyncHttpProvider(config), config); + long start = System.currentTimeMillis(); 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) { + client.executeRequest(client.prepareGet("http://www.google.com").build()).get(); + } catch (InterruptedException e) { + e.printStackTrace(); + } catch (ExecutionException e) { e.printStackTrace(); } + LOGGER.debug("COMPLETE: " + (System.currentTimeMillis() - start) + "ms"); } } 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 283a97df6e..464301ac00 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 @@ -114,8 +114,13 @@ private void configure(JDKAsyncHttpProviderConfig config) { } } - public ListenableFuture execute(Request request, AsyncHandler handler) throws IOException { - return execute(request, handler, null); + public ListenableFuture execute(Request request, AsyncHandler handler) { + try { + return execute(request, handler, null); + } catch (IOException e) { + handler.onThrowable(e); + return new ListenableFuture.CompletedFailure<>(e); + } } private ListenableFuture execute(Request request, AsyncHandler handler, JDKFuture future) throws IOException { 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 1f95be7f7c..d16c061893 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 @@ -28,7 +28,6 @@ import com.ning.http.client.providers.netty.channel.pool.ChannelPoolPartitionSelector; import com.ning.http.client.providers.netty.request.NettyRequestSender; -import java.io.IOException; import java.util.concurrent.atomic.AtomicBoolean; public class NettyAsyncHttpProvider extends SimpleChannelUpstreamHandler implements AsyncHttpProvider { @@ -83,8 +82,13 @@ public void close() { } @Override - public ListenableFuture execute(Request request, final AsyncHandler asyncHandler) throws IOException { - return requestSender.sendRequest(request, asyncHandler, null, false); + public ListenableFuture execute(Request request, final AsyncHandler asyncHandler) { + try { + return requestSender.sendRequest(request, asyncHandler, null, false); + } catch (Exception e) { + asyncHandler.onThrowable(e); + return new ListenableFuture.CompletedFailure<>(e); + } } public void flushChannelPoolPartition(String partitionId) { 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 0f3ac0fd80..956a6f4f6b 100644 --- a/src/test/java/com/ning/http/client/async/ChunkingTest.java +++ b/src/test/java/com/ning/http/client/async/ChunkingTest.java @@ -28,9 +28,7 @@ import java.net.URL; import java.util.Random; -import static org.testng.Assert.assertNotNull; -import static org.testng.AssertJUnit.assertEquals; -import static org.testng.AssertJUnit.assertTrue; +import static org.testng.Assert.*; import static org.testng.FileAssert.fail; /** @@ -106,11 +104,11 @@ private void doTest(boolean customChunkedInputStream) throws Exception { System.out.println("Headers:" + res.getHeaders()); System.out.println("=============="); System.out.flush(); - assertEquals("Should have 500 status code", 500, res.getStatusCode()); - assertTrue("Should have failed due to chunking", res.getHeader("X-Exception").contains("invalid.chunk.length")); + assertEquals(res.getStatusCode(), 500, "Should have 500 status code"); + assertTrue(res.getHeader("X-Exception").contains("invalid.chunk.length"), "Should have failed due to chunking"); fail("HARD Failing the test due to provided InputStreamBodyGenerator, chunking incorrectly:" + res.getHeader("X-Exception")); } else { - assertEquals(LARGE_IMAGE_BYTES, readInputStreamToBytes(res.getResponseBodyAsStream())); + assertEquals(readInputStreamToBytes(res.getResponseBodyAsStream()), LARGE_IMAGE_BYTES); } } catch (Exception e) { 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 43367d962c..c9bf28c810 100644 --- a/src/test/java/com/ning/http/client/async/FilterTest.java +++ b/src/test/java/com/ning/http/client/async/FilterTest.java @@ -21,22 +21,23 @@ import com.ning.http.client.filter.FilterContext; import com.ning.http.client.filter.FilterException; import com.ning.http.client.filter.ResponseFilter; + 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.Enumeration; import java.util.List; +import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.atomic.AtomicBoolean; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertNotNull; -import static org.testng.Assert.fail; +import static org.testng.Assert.*; public abstract class FilterTest extends AbstractBasicTest { @@ -108,9 +109,8 @@ public void maxConnectionsText() throws Throwable { try { client.preparePost(getTargetUrl()).execute().get(); fail("Should have timed out"); - } catch (IOException ex) { - assertNotNull(ex); - assertEquals(ex.getCause().getClass(), FilterException.class); + } catch (ExecutionException ex) { + assertTrue(ex.getCause() instanceof FilterException); } finally { client.close(); } @@ -125,7 +125,7 @@ public void basicResponseFilterTest() throws Throwable { AsyncHttpClientConfig.Builder b = new AsyncHttpClientConfig.Builder(); b.addResponseFilter(new ResponseFilter() { - public FilterContext filter(FilterContext ctx) throws FilterException { + public FilterContext filter(FilterContext ctx) throws FilterException { return ctx; } @@ -137,8 +137,6 @@ public FilterContext filter(FilterContext ctx) throws FilterException { assertNotNull(response); assertEquals(response.getStatusCode(), 200); - } catch (IOException ex) { - fail("Should have timed out"); } finally { client.close(); } @@ -151,11 +149,11 @@ public void replayResponseFilterTest() throws Throwable { b.addResponseFilter(new ResponseFilter() { - public FilterContext filter(FilterContext ctx) throws FilterException { + public FilterContext filter(FilterContext ctx) throws FilterException { if (replay.getAndSet(false)) { Request request = new RequestBuilder(ctx.getRequest()).addHeader("X-Replay", "true").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; } @@ -169,8 +167,6 @@ public FilterContext filter(FilterContext ctx) throws FilterException { assertNotNull(response); assertEquals(response.getStatusCode(), 200); assertEquals(response.getHeader("X-Replay"), "true"); - } catch (IOException ex) { - fail("Should have timed out"); } finally { c.close(); } @@ -183,11 +179,11 @@ public void replayStatusCodeResponseFilterTest() throws Throwable { b.addResponseFilter(new ResponseFilter() { - public FilterContext filter(FilterContext ctx) throws FilterException { + public FilterContext filter(FilterContext ctx) throws FilterException { if (ctx.getResponseStatus() != null && ctx.getResponseStatus().getStatusCode() == 200 && replay.getAndSet(false)) { Request request = new RequestBuilder(ctx.getRequest()).addHeader("X-Replay", "true").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; } @@ -201,8 +197,6 @@ public FilterContext filter(FilterContext ctx) throws FilterException { assertNotNull(response); assertEquals(response.getStatusCode(), 200); assertEquals(response.getHeader("X-Replay"), "true"); - } catch (IOException ex) { - fail("Should have timed out"); } finally { c.close(); } @@ -215,12 +209,12 @@ public void replayHeaderResponseFilterTest() throws Throwable { b.addResponseFilter(new ResponseFilter() { - public FilterContext filter(FilterContext ctx) throws FilterException { + public FilterContext filter(FilterContext ctx) throws FilterException { 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; } @@ -234,8 +228,6 @@ public FilterContext filter(FilterContext ctx) throws FilterException { assertNotNull(response); assertEquals(response.getStatusCode(), 200); assertEquals(response.getHeader("Ping"), "Pong"); - } catch (IOException ex) { - fail("Should have timed out"); } finally { c.close(); } 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 f27e9063b3..0f06a51758 100644 --- a/src/test/java/com/ning/http/client/async/HostnameVerifierTest.java +++ b/src/test/java/com/ning/http/client/async/HostnameVerifierTest.java @@ -15,6 +15,7 @@ import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClientConfig.Builder; import com.ning.http.client.Response; + import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.handler.AbstractHandler; @@ -30,6 +31,7 @@ import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; + import java.io.File; import java.io.IOException; import java.io.InputStream; @@ -41,11 +43,11 @@ import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.util.Enumeration; +import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.atomic.AtomicBoolean; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.*; public abstract class HostnameVerifierTest extends AbstractBasicTest { @@ -225,9 +227,9 @@ public void negativeHostnameVerifierTest() throws Throwable { 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()); + client.preparePost(getTargetUrl()).setBody(file).setHeader("Content-Type", "text/html").execute().get(); + } catch (ExecutionException ex) { + assertTrue(ex.getCause() instanceof ConnectException); } } finally { client.close(); @@ -245,9 +247,9 @@ public void remoteIDHostnameVerifierTest() throws Throwable { 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()); + client.preparePost(getTargetUrl()).setBody(file).setHeader("Content-Type", "text/html").execute().get(); + } catch (ExecutionException ex) { + assertTrue(ex.getCause() instanceof ConnectException); } } finally { client.close(); @@ -265,9 +267,9 @@ public void remotePosHostnameVerifierTest() throws Throwable { 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()); + client.preparePost(getTargetUrl()).setBody(file).setHeader("Content-Type", "text/html").execute().get(); + } catch (ExecutionException ex) { + assertTrue(ex.getCause() instanceof ConnectException); } } finally { client.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 ab4e34a1bc..325adbf54d 100644 --- a/src/test/java/com/ning/http/client/async/MaxConnectionsInThreads.java +++ b/src/test/java/com/ning/http/client/async/MaxConnectionsInThreads.java @@ -16,8 +16,8 @@ */ package com.ning.http.client.async; -import com.ning.http.client.AsyncHttpClient; -import com.ning.http.client.AsyncHttpClientConfig; +import static org.testng.Assert.*; + import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.nio.SelectChannelConnector; @@ -26,93 +26,93 @@ import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; +import com.ning.http.client.AsyncCompletionHandlerBase; +import com.ning.http.client.AsyncHttpClient; +import com.ning.http.client.AsyncHttpClientConfig; +import com.ning.http.client.Response; + import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; + import java.io.IOException; import java.io.OutputStream; import java.net.URI; import java.net.URISyntaxException; -import java.util.ArrayList; -import java.util.List; - -import static org.testng.AssertJUnit.assertTrue; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicReference; abstract public class MaxConnectionsInThreads extends AbstractBasicTest { private static URI servletEndpointUri; @Test(groups = { "online", "default_provider" }) - public void testMaxConnectionsWithinThreads() { + public void testMaxConnectionsWithinThreads() throws InterruptedException { String[] urls = new String[] { servletEndpointUri.toString(), servletEndpointUri.toString() }; - final AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setConnectTimeout(1000).setRequestTimeout(5000).setAllowPoolingConnections(true).setMaxConnections(1).setMaxConnectionsPerHost(1).build()); + final AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setConnectTimeout(1000).setRequestTimeout(5000).setAllowPoolingConnections(true)// + .setMaxConnections(1).setMaxConnectionsPerHost(1).build()); + final CountDownLatch inThreadsLatch = new CountDownLatch(2); + final AtomicReference failedRank = new AtomicReference(-1); + 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]; + final int rank = 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("============"); - - } + client.prepareGet(url).execute(new AsyncCompletionHandlerBase() { + @Override + public Response onCompleted(Response response) throws Exception { + Response r = super.onCompleted(response); + inThreadsLatch.countDown(); + return r; + } + + @Override + public void onThrowable(Throwable t) { + super.onThrowable(t); + failedRank.set(rank); + inThreadsLatch.countDown(); + } + }); } }; t.start(); - ts.add(t); } - for (Thread t : ts) { - try { - t.join(); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - - // Let the threads finish - try { - Thread.sleep(4500); - } catch (InterruptedException e1) { - e1.printStackTrace(); - } + inThreadsLatch.await(); - assertTrue("Max Connections should have been reached", caughtError[0]); + assertEquals(failedRank.get().intValue(), 1, "Max Connections should have been reached"); - boolean errorInNotThread = false; + final CountDownLatch notInThreadsLatch = new CountDownLatch(2); + failedRank.set(-1); 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 { - Thread.sleep(2500); - } catch (InterruptedException e1) { - e1.printStackTrace(); + final int rank = i; + client.prepareGet(url).execute(new AsyncCompletionHandlerBase() { + @Override + public Response onCompleted(Response response) throws Exception { + Response r = super.onCompleted(response); + notInThreadsLatch.countDown(); + return r; + } + + @Override + public void onThrowable(Throwable t) { + super.onThrowable(t); + failedRank.set(rank); + notInThreadsLatch.countDown(); + } + }); } - assertTrue("Max Connections should have been reached", errorInNotThread); + + notInThreadsLatch.await(); + + assertEquals(failedRank.get().intValue(), 1, "Max Connections should have been reached"); } finally { client.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 bb1a3d7190..38552c00dc 100644 --- a/src/test/java/com/ning/http/client/async/MaxTotalConnectionTest.java +++ b/src/test/java/com/ning/http/client/async/MaxTotalConnectionTest.java @@ -15,21 +15,23 @@ */ package com.ning.http.client.async; -import com.ning.http.client.AsyncHttpClient; -import com.ning.http.client.AsyncHttpClientConfig; -import com.ning.http.client.ListenableFuture; -import com.ning.http.client.Response; +import static org.testng.Assert.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -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.AsyncHttpClientConfig; +import com.ning.http.client.ListenableFuture; +import com.ning.http.client.Response; + import java.io.IOException; import java.util.ArrayList; import java.util.List; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicReference; public abstract class MaxTotalConnectionTest extends AbstractBasicTest { protected final Logger log = LoggerFactory.getLogger(AbstractBasicTest.class); @@ -60,75 +62,46 @@ public void testMaxTotalConnectionsExceedingException() throws IOException { } } - Assert.assertEquals(1, i); - Assert.assertTrue(caughtError); + assertEquals(i, 1); + assertTrue(caughtError); } finally { client.close(); } } @Test - public void testMaxTotalConnections() throws IOException { + public void testMaxTotalConnections() throws InterruptedException { String[] urls = new String[] { "http://google.com", "http://lenta.ru" }; - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setConnectTimeout(1000) - .setRequestTimeout(5000).setAllowPoolingConnections(false).setMaxConnections(2).setMaxConnectionsPerHost(1) - .build()); - try { - for (String url : urls) { - client.prepareGet(url).execute(); - } - } finally { - client.close(); - } - } + AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setConnectTimeout(1000).setRequestTimeout(5000) + .setAllowPoolingConnections(false).setMaxConnections(2).setMaxConnectionsPerHost(1).build()); - /** - * 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. - * @throws ExecutionException - * @throws InterruptedException - */ - @Test(enabled = false) - public void testMaxTotalConnectionsCorrectExceptionHandling() throws InterruptedException, ExecutionException { - String[] urls = new String[] { "http://google.com", "http://github.com/" }; + final CountDownLatch latch = new CountDownLatch(2); + final AtomicReference failedUrl = new AtomicReference(); - AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setConnectTimeout(1000) - .setRequestTimeout(5000).setAllowPoolingConnections(false).setMaxConnections(1).setMaxConnectionsPerHost(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); + for (String url : urls) { + final String thisUrl = url; + client.prepareGet(url).execute(new AsyncCompletionHandlerBase() { + @Override + public Response onCompleted(Response response) throws Exception { + Response r = super.onCompleted(response); + latch.countDown(); + return r; } - } 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) { - future.get(); + @Override + public void onThrowable(Throwable t) { + super.onThrowable(t); + failedUrl.set(thisUrl); + latch.countDown(); + } + }); } - // 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); + latch.await(); + assertNull(failedUrl.get()); + } finally { client.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 b1af7ba928..3426e5bb4e 100644 --- a/src/test/java/com/ning/http/client/async/SimpleAsyncHttpClientTest.java +++ b/src/test/java/com/ning/http/client/async/SimpleAsyncHttpClientTest.java @@ -13,10 +13,7 @@ package com.ning.http.client.async; import static java.nio.charset.StandardCharsets.*; - import static org.testng.Assert.*; -import static org.testng.AssertJUnit.assertNotNull; -import static org.testng.AssertJUnit.assertNotSame; import org.testng.annotations.Test; @@ -35,6 +32,7 @@ import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; +import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; public abstract class SimpleAsyncHttpClientTest extends AbstractBasicTest { @@ -254,8 +252,11 @@ public void testCloseMasterInvalidDerived() throws Exception { try { derived.get().get(); fail("Expected closed AHC"); - } catch (IOException e) { // expected -- Seems to me that this behavior conflicts with the requirements of Future.get() + + } catch (ExecutionException e) { + assertTrue(e.getCause() instanceof IOException); + } finally { client.close(); derived.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 f423119e60..1a0cdfefd6 100644 --- a/src/test/java/com/ning/http/client/async/TransferListenerTest.java +++ b/src/test/java/com/ning/http/client/async/TransferListenerTest.java @@ -15,7 +15,6 @@ 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 org.eclipse.jetty.server.handler.AbstractHandler; import org.testng.annotations.Test; @@ -120,8 +119,6 @@ public void onThrowable(Throwable t) { assertNotNull(hSent.get()); assertNotNull(bb.get()); assertNull(throwable.get()); - } catch (IOException ex) { - fail("Should have timed out"); } finally { client.close(); } @@ -180,8 +177,6 @@ public void onThrowable(Throwable t) { assertNotNull(hSent.get()); assertEquals(bbReceivedLenght.get(), largeFile.length()); assertEquals(bbSentLenght.get(), largeFile.length()); - } catch (IOException ex) { - fail("Should have timed out"); } finally { client.close(); } @@ -240,8 +235,6 @@ public void onThrowable(Throwable t) { assertNotNull(hSent.get()); assertEquals(bbReceivedLenght.get(), largeFile.length()); assertEquals(bbSentLenght.get(), largeFile.length()); - } catch (IOException ex) { - fail("Should have timed out"); } finally { client.close(); } 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 84d9a40080..4413b33324 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 @@ -43,9 +43,7 @@ import org.glassfish.grizzly.ssl.SSLContextConfigurator; import org.glassfish.grizzly.ssl.SSLEngineConfigurator; import org.glassfish.grizzly.utils.Charsets; -import static org.testng.Assert.assertNull; -import static org.testng.Assert.fail; -import static org.testng.AssertJUnit.assertEquals; +import static org.testng.Assert.*; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; @@ -179,31 +177,26 @@ public void flush() throws IOException { 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; + 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(); - } + @Override + public void onThrowable(Throwable t) { + errors[idx] = t; + t.printStackTrace(); + latch.countDown(); + } + }); } }); } @@ -217,9 +210,9 @@ public void onThrowable(Throwable t) { } for (int i = 0; i < threadCount; i++) { - assertEquals(200, statusCodes[i]); + assertEquals(statusCodes[i], 200); assertNull(errors[i]); - assertEquals(tempFile.length(), totalsReceived[i]); + assertEquals(totalsReceived[i], tempFile.length()); } } finally { client.close(); @@ -309,31 +302,26 @@ public void run() { 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; + 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(); - } + @Override + public void onThrowable(Throwable t) { + errors[idx] = t; + t.printStackTrace(); + latch.countDown(); + } + }); } }); } @@ -347,9 +335,9 @@ public void onThrowable(Throwable t) { } for (int i = 0; i < threadCount; i++) { - assertEquals(200, statusCodes[i]); + assertEquals(statusCodes[i], 200); assertNull(errors[i]); - assertEquals(tempFile.length(), totalsReceived[i]); + assertEquals(totalsReceived[i], tempFile.length()); } } finally { client.close(); From ed6586a4e6713bba37a144feb0f1bf88900ae36b Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 9 Oct 2014 16:49:12 +0200 Subject: [PATCH 653/701] Filter headers propagated on redirect, close #735 --- .../providers/netty/handler/Protocol.java | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/main/java/com/ning/http/client/providers/netty/handler/Protocol.java b/src/main/java/com/ning/http/client/providers/netty/handler/Protocol.java index 821125e37d..4093400269 100644 --- a/src/main/java/com/ning/http/client/providers/netty/handler/Protocol.java +++ b/src/main/java/com/ning/http/client/providers/netty/handler/Protocol.java @@ -20,6 +20,7 @@ import static org.jboss.netty.handler.codec.http.HttpResponseStatus.MOVED_PERMANENTLY; import static org.jboss.netty.handler.codec.http.HttpResponseStatus.SEE_OTHER; import static org.jboss.netty.handler.codec.http.HttpResponseStatus.TEMPORARY_REDIRECT; +import static org.jboss.netty.handler.codec.http.HttpHeaders.Names.*; import org.jboss.netty.channel.Channel; import org.jboss.netty.handler.codec.http.HttpHeaders; @@ -29,6 +30,7 @@ import com.ning.http.client.AsyncHandler; import com.ning.http.client.AsyncHttpClientConfig; +import com.ning.http.client.FluentCaseInsensitiveStringsMap; import com.ning.http.client.HttpResponseHeaders; import com.ning.http.client.HttpResponseStatus; import com.ning.http.client.MaxRedirectException; @@ -50,6 +52,9 @@ import java.io.IOException; import java.util.HashSet; +import java.util.List; +import java.util.Locale; +import java.util.Map; import java.util.Set; public abstract class Protocol { @@ -73,6 +78,16 @@ public abstract class Protocol { REDIRECT_STATUSES.add(TEMPORARY_REDIRECT.getCode()); } + public static final Set PROPAGATED_ON_REDIRECT_HEADERS = new HashSet(); + static { + PROPAGATED_ON_REDIRECT_HEADERS.add(ACCEPT.toLowerCase(Locale.US)); + PROPAGATED_ON_REDIRECT_HEADERS.add(ACCEPT_CHARSET.toLowerCase(Locale.US)); + PROPAGATED_ON_REDIRECT_HEADERS.add(ACCEPT_ENCODING.toLowerCase(Locale.US)); + PROPAGATED_ON_REDIRECT_HEADERS.add(ACCEPT_LANGUAGE.toLowerCase(Locale.US)); + PROPAGATED_ON_REDIRECT_HEADERS.add(REFERER.toLowerCase(Locale.US)); + PROPAGATED_ON_REDIRECT_HEADERS.add(USER_AGENT.toLowerCase(Locale.US)); + } + public Protocol(ChannelManager channelManager, AsyncHttpClientConfig config, NettyAsyncHttpProviderConfig nettyConfig, NettyRequestSender requestSender) { this.channelManager = channelManager; @@ -91,6 +106,17 @@ public Protocol(ChannelManager channelManager, AsyncHttpClientConfig config, Net public abstract void onClose(NettyResponseFuture future); + private FluentCaseInsensitiveStringsMap propagatedHeaders(Request request) { + FluentCaseInsensitiveStringsMap redirectHeaders = new FluentCaseInsensitiveStringsMap(); + for (Map.Entry> headerEntry : request.getHeaders()) { + String headerName = headerEntry.getKey(); + List headerValues = headerEntry.getValue(); + if (PROPAGATED_ON_REDIRECT_HEADERS.contains(headerName.toLowerCase(Locale.US))) + redirectHeaders.add(headerName, headerValues); + } + return redirectHeaders; + } + protected boolean exitAfterHandlingRedirect(// Channel channel,// NettyResponseFuture future,// @@ -139,6 +165,8 @@ protected boolean exitAfterHandlingRedirect(// requestBuilder.addOrReplaceCookie(c); } + requestBuilder.setHeaders(propagatedHeaders(future.getRequest())); + Callback callback = channelManager.newDrainCallback(future, channel, initialConnectionKeepAlive, initialPoolKey); if (HttpHeaders.isTransferEncodingChunked(response)) { From 5a1a2cec0560b039061889ef7f8f6af5e40c7038 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 9 Oct 2014 18:17:30 +0200 Subject: [PATCH 654/701] NTLM WWW-Authenticate header is not always the first one, close #736 --- .../providers/netty/handler/HttpProtocol.java | 17 ++++++++++------- .../netty/request/NettyRequestFactory.java | 9 +++++---- .../client/providers/netty/util/HttpUtils.java | 13 +++++++++---- 3 files changed, 24 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/handler/HttpProtocol.java b/src/main/java/com/ning/http/client/providers/netty/handler/HttpProtocol.java index d90bb769fe..39286edc92 100644 --- a/src/main/java/com/ning/http/client/providers/netty/handler/HttpProtocol.java +++ b/src/main/java/com/ning/http/client/providers/netty/handler/HttpProtocol.java @@ -13,7 +13,7 @@ */ package com.ning.http.client.providers.netty.handler; -import static com.ning.http.client.providers.netty.util.HttpUtils.isNTLM; +import static com.ning.http.client.providers.netty.util.HttpUtils.getNTLM; import static com.ning.http.util.AsyncHttpProviderUtils.getDefaultPort; import static com.ning.http.util.MiscUtils.isNonEmpty; import static org.jboss.netty.handler.codec.http.HttpResponseStatus.CONTINUE; @@ -90,8 +90,9 @@ private Realm kerberosChallenge(Channel channel,// .build(); } catch (Throwable throwable) { - if (isNTLM(proxyAuth)) { - return ntlmChallenge(proxyAuth.get(0), request, proxyServer, headers, realm, future, proxyInd); + String ntlmAuthenticate = getNTLM(proxyAuth); + if (ntlmAuthenticate != null) { + return ntlmChallenge(ntlmAuthenticate, request, proxyServer, headers, realm, future, proxyInd); } requestSender.abort(channel, future, throwable); return null; @@ -218,9 +219,10 @@ private boolean exitAfterHandling401(// Realm newRealm = null; boolean negociate = wwwAuthHeaders.contains("Negotiate"); - if (!wwwAuthHeaders.contains("Kerberos") && (isNTLM(wwwAuthHeaders) || negociate)) { + String ntlmAuthenticate = getNTLM(wwwAuthHeaders); + if (!wwwAuthHeaders.contains("Kerberos") && ntlmAuthenticate != null) { // NTLM - newRealm = ntlmChallenge(wwwAuthHeaders.get(0), request, proxyServer, request.getHeaders(), realm, future, false); + newRealm = ntlmChallenge(ntlmAuthenticate, request, proxyServer, request.getHeaders(), realm, future, false); // don't forget to reuse channel: NTLM authenticates a connection future.setReuseChannel(true); @@ -304,8 +306,9 @@ private boolean exitAfterHandling407(// FluentCaseInsensitiveStringsMap requestHeaders = request.getHeaders(); boolean negociate = proxyAuthHeaders.contains("Negotiate"); - if (!proxyAuthHeaders.contains("Kerberos") && (isNTLM(proxyAuthHeaders) || negociate)) { - newRealm = ntlmProxyChallenge(proxyAuthHeaders.get(0), request, proxyServer, requestHeaders, realm, future, true); + String ntlmAuthenticate = getNTLM(proxyAuthHeaders); + if (!proxyAuthHeaders.contains("Kerberos") && ntlmAuthenticate != null) { + newRealm = ntlmProxyChallenge(ntlmAuthenticate, request, proxyServer, requestHeaders, realm, future, true); // SPNEGO KERBEROS } else if (negociate) { newRealm = kerberosChallenge(channel, proxyAuthHeaders, request, proxyServer, requestHeaders, realm, future, true); diff --git a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestFactory.java b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestFactory.java index 5a89f0c2e9..a0a053e582 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestFactory.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestFactory.java @@ -13,7 +13,7 @@ */ package com.ning.http.client.providers.netty.request; -import static com.ning.http.client.providers.netty.util.HttpUtils.isNTLM; +import static com.ning.http.client.providers.netty.util.HttpUtils.getNTLM; import static com.ning.http.client.providers.netty.util.HttpUtils.isSecure; import static com.ning.http.client.providers.netty.util.HttpUtils.isWebSocket; import static com.ning.http.client.providers.netty.util.HttpUtils.useProxyConnect; @@ -157,13 +157,14 @@ public String firstRequestOnlyProxyAuthorizationHeader(Request request, ProxySer if (method == HttpMethod.CONNECT) { List auth = request.getHeaders().get(HttpHeaders.Names.PROXY_AUTHORIZATION); - if (isNTLM(auth)) { - proxyAuthorization = auth.get(0); + String ntlmHeader = getNTLM(auth); + if (ntlmHeader != null) { + proxyAuthorization = ntlmHeader; } } else if (proxyServer != null && proxyServer.getPrincipal() != null && isNonEmpty(proxyServer.getNtlmDomain())) { List auth = request.getHeaders().get(HttpHeaders.Names.PROXY_AUTHORIZATION); - if (!isNTLM(auth)) { + if (getNTLM(auth) == null) { String msg = NTLMEngine.INSTANCE.generateType1Msg(); proxyAuthorization = "NTLM " + msg; } diff --git a/src/main/java/com/ning/http/client/providers/netty/util/HttpUtils.java b/src/main/java/com/ning/http/client/providers/netty/util/HttpUtils.java index b130873459..1d2168a785 100644 --- a/src/main/java/com/ning/http/client/providers/netty/util/HttpUtils.java +++ b/src/main/java/com/ning/http/client/providers/netty/util/HttpUtils.java @@ -13,8 +13,6 @@ */ package com.ning.http.client.providers.netty.util; -import static com.ning.http.util.MiscUtils.isNonEmpty; - import org.jboss.netty.handler.codec.http.HttpHeaders; import com.ning.http.client.uri.Uri; @@ -33,8 +31,15 @@ public final class HttpUtils { private HttpUtils() { } - public static boolean isNTLM(List auth) { - return isNonEmpty(auth) && auth.get(0).startsWith("NTLM"); + public static String getNTLM(List authenticateHeaders) { + if (authenticateHeaders != null) { + for (String authenticateHeader: authenticateHeaders) { + if (authenticateHeader.startsWith("NTLM")) + return authenticateHeader; + } + } + + return null; } public static List getNettyHeaderValuesByCaseInsensitiveName(HttpHeaders headers, String name) { From 9ed723fd6ad5dec0b726f8a87fe20ccc3123dfc4 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 9 Oct 2014 18:20:00 +0200 Subject: [PATCH 655/701] [maven-release-plugin] prepare release async-http-client-1.9.0-BETA18 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index caffa38820..c902b094db 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.9.0-SNAPSHOT + 1.9.0-BETA18 jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From 0451da8ea5ef56cef9e19f3f63633f4188648b68 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 9 Oct 2014 18:20:07 +0200 Subject: [PATCH 656/701] [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 c902b094db..caffa38820 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.9.0-BETA18 + 1.9.0-SNAPSHOT jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From 8c12d1535ed3fc52e51478ae6caa971d534e8ef4 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 9 Oct 2014 23:20:35 +0200 Subject: [PATCH 657/701] Move PerHostConnectionPoolPartitioning inside ConnectionPoolPartitioning, close #737 --- .../client/ConnectionPoolPartitioning.java | 12 ++++++++ .../PerHostConnectionPoolPartitioning.java | 29 ------------------- .../ning/http/client/RequestBuilderBase.java | 2 +- 3 files changed, 13 insertions(+), 30 deletions(-) delete mode 100644 src/main/java/com/ning/http/client/PerHostConnectionPoolPartitioning.java diff --git a/src/main/java/com/ning/http/client/ConnectionPoolPartitioning.java b/src/main/java/com/ning/http/client/ConnectionPoolPartitioning.java index 6ce6e18457..ff220b14cc 100644 --- a/src/main/java/com/ning/http/client/ConnectionPoolPartitioning.java +++ b/src/main/java/com/ning/http/client/ConnectionPoolPartitioning.java @@ -16,8 +16,20 @@ package com.ning.http.client; import com.ning.http.client.uri.Uri; +import com.ning.http.util.AsyncHttpProviderUtils; public interface ConnectionPoolPartitioning { String getPartitionId(Uri uri, ProxyServer proxyServer); + + public enum PerHostConnectionPoolPartitioning implements ConnectionPoolPartitioning { + + INSTANCE; + + public String getPartitionId(Uri uri, ProxyServer proxyServer) { + String serverPart = AsyncHttpProviderUtils.getBaseUrl(uri); + return proxyServer != null ? proxyServer.getUrl() + serverPart : serverPart; + } + } + } diff --git a/src/main/java/com/ning/http/client/PerHostConnectionPoolPartitioning.java b/src/main/java/com/ning/http/client/PerHostConnectionPoolPartitioning.java deleted file mode 100644 index 911e66a769..0000000000 --- a/src/main/java/com/ning/http/client/PerHostConnectionPoolPartitioning.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * 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 com.ning.http.client.uri.Uri; -import com.ning.http.util.AsyncHttpProviderUtils; - -public enum PerHostConnectionPoolPartitioning implements ConnectionPoolPartitioning { - - INSTANCE; - - public String getPartitionId(Uri uri, ProxyServer proxyServer) { - String serverPart = AsyncHttpProviderUtils.getBaseUrl(uri); - return proxyServer != null ? proxyServer.getUrl() + serverPart : serverPart; - } -} diff --git a/src/main/java/com/ning/http/client/RequestBuilderBase.java b/src/main/java/com/ning/http/client/RequestBuilderBase.java index 0968c00d25..9312df7ebc 100644 --- a/src/main/java/com/ning/http/client/RequestBuilderBase.java +++ b/src/main/java/com/ning/http/client/RequestBuilderBase.java @@ -67,7 +67,7 @@ private static final class RequestImpl implements Request { private int requestTimeout; private long rangeOffset; public String charset; - private ConnectionPoolPartitioning connectionPoolPartitioning = PerHostConnectionPoolPartitioning.INSTANCE; + private ConnectionPoolPartitioning connectionPoolPartitioning = ConnectionPoolPartitioning.PerHostConnectionPoolPartitioning.INSTANCE; private List queryParams; public RequestImpl() { From 4735d235ddd85ebf709447d7a14f6b14519fad18 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 13 Oct 2014 14:39:03 +0200 Subject: [PATCH 658/701] AbstractFilePart.visitDispositionHeader should honor defined charset, close #738 --- .../java/com/ning/http/client/multipart/AbstractFilePart.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/ning/http/client/multipart/AbstractFilePart.java b/src/main/java/com/ning/http/client/multipart/AbstractFilePart.java index d800e006c5..f7e243c14b 100644 --- a/src/main/java/com/ning/http/client/multipart/AbstractFilePart.java +++ b/src/main/java/com/ning/http/client/multipart/AbstractFilePart.java @@ -69,7 +69,7 @@ protected void visitDispositionHeader(PartVisitor visitor) throws IOException { if (fileName != null) { visitor.withBytes(FILE_NAME_BYTES); visitor.withByte(QUOTE_BYTE); - visitor.withBytes(fileName.getBytes(US_ASCII)); + visitor.withBytes(fileName.getBytes(getCharset() != null ? getCharset(): US_ASCII)); visitor.withByte(QUOTE_BYTE); } } From 816f36d2d6500082b189716098340920e3b9b090 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 14 Oct 2014 10:57:05 +0200 Subject: [PATCH 659/701] SignatureCalculator should be resolved before computing the final URI, close #739 --- src/main/java/com/ning/http/client/RequestBuilderBase.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/ning/http/client/RequestBuilderBase.java b/src/main/java/com/ning/http/client/RequestBuilderBase.java index 9312df7ebc..b39f54b3e5 100644 --- a/src/main/java/com/ning/http/client/RequestBuilderBase.java +++ b/src/main/java/com/ning/http/client/RequestBuilderBase.java @@ -584,8 +584,8 @@ private void computeFinalUri() { } public Request build() { - computeFinalUri(); executeSignatureCalculator(); + computeFinalUri(); computeRequestCharset(); computeRequestLength(); return request; From 95007f8966af3447bfe6d81e53e65a6722228c65 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 14 Oct 2014 11:29:02 +0200 Subject: [PATCH 660/701] Fix maven-scm-plugin version and align --- pom.xml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index caffa38820..d751e6426e 100644 --- a/pom.xml +++ b/pom.xml @@ -208,12 +208,12 @@ org.apache.maven.scm maven-scm-provider-gitexe - 1.6 + 1.9.2 org.apache.maven.scm maven-scm-manager-plexus - 1.6 + 1.9.2 org.kathrynhuxtable.maven.wagon @@ -240,6 +240,11 @@ ${surefire.redirectTestOutputToFile} + + org.apache.maven.plugins + maven-scm-plugin + 1.9.2 + org.codehaus.mojo animal-sniffer-maven-plugin From 6db71493eebee9998d297bd6cfca7a9746b6ec51 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 14 Oct 2014 11:33:34 +0200 Subject: [PATCH 661/701] Revert back to maven-scm-plugin 1.9.1 --- pom.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index d751e6426e..29cf7b8bba 100644 --- a/pom.xml +++ b/pom.xml @@ -208,12 +208,12 @@ org.apache.maven.scm maven-scm-provider-gitexe - 1.9.2 + 1.9.1 org.apache.maven.scm maven-scm-manager-plexus - 1.9.2 + 1.9.1 org.kathrynhuxtable.maven.wagon @@ -243,7 +243,7 @@ org.apache.maven.plugins maven-scm-plugin - 1.9.2 + 1.9.1 org.codehaus.mojo From 28511e3c22498a2cd21a6d74f38c02da95d0805d Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 14 Oct 2014 11:36:52 +0200 Subject: [PATCH 662/701] no comment --- pom.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index 29cf7b8bba..c7030d64c7 100644 --- a/pom.xml +++ b/pom.xml @@ -208,12 +208,12 @@ org.apache.maven.scm maven-scm-provider-gitexe - 1.9.1 + 1.6 org.apache.maven.scm maven-scm-manager-plexus - 1.9.1 + 1.6 org.kathrynhuxtable.maven.wagon @@ -243,7 +243,7 @@ org.apache.maven.plugins maven-scm-plugin - 1.9.1 + 1.6 org.codehaus.mojo From b7e8e0dae89a87b6085cc1265826581820b92d80 Mon Sep 17 00:00:00 2001 From: jfarcand Date: Tue, 14 Oct 2014 07:51:14 -0400 Subject: [PATCH 663/701] [maven-release-plugin] prepare release async-http-client-1.9.0-BETA19 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index c7030d64c7..448e308d2c 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.9.0-SNAPSHOT + 1.9.0-BETA19 jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From bc2c983d19f395b005617474edfee6a9ed6ef46b Mon Sep 17 00:00:00 2001 From: jfarcand Date: Tue, 14 Oct 2014 07:51:16 -0400 Subject: [PATCH 664/701] [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 448e308d2c..c7030d64c7 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.9.0-BETA19 + 1.9.0-SNAPSHOT jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From bb0c35d289461f01b70147081c0bd05b47c0dce5 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 16 Oct 2014 14:27:26 +0200 Subject: [PATCH 665/701] Have a way to configure SslEngine enabled Protocols and CipherSuites, close #740 --- .../http/client/AsyncHttpClientConfig.java | 36 +++++++++++++++++++ .../ning/http/client/SSLEngineFactory.java | 34 +++++++++++++++++- .../netty/channel/ChannelManager.java | 19 +++------- .../java/com/ning/http/util/SslUtils.java | 3 +- 4 files changed, 74 insertions(+), 18 deletions(-) diff --git a/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java b/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java index 0784474230..c6bba0b597 100644 --- a/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java @@ -79,6 +79,8 @@ public class AsyncHttpClientConfig { protected boolean disableUrlEncodingForBoundRequests; protected int ioThreadMultiplier; protected TimeConverter timeConverter; + protected String[] enabledProtocols; + protected String[] enabledCipherSuites; protected AsyncHttpProviderConfig providerConfig; protected AsyncHttpClientConfig() { @@ -114,6 +116,8 @@ private AsyncHttpClientConfig(int connectTimeout,// boolean disableUrlEncodingForBoundedRequests, // int ioThreadMultiplier, // TimeConverter timeConverter,// + String[] enabledProtocols,// + String[] enabledCipherSuites,// AsyncHttpProviderConfig providerConfig) { this.connectTimeout = connectTimeout; @@ -146,6 +150,8 @@ private AsyncHttpClientConfig(int connectTimeout,// this.disableUrlEncodingForBoundRequests = disableUrlEncodingForBoundedRequests; this.ioThreadMultiplier = ioThreadMultiplier; this.timeConverter = timeConverter; + this.enabledProtocols = enabledProtocols; + this.enabledCipherSuites = enabledCipherSuites; this.providerConfig = providerConfig; } @@ -449,6 +455,20 @@ public boolean isAcceptAnyCertificate() { return acceptAnyCertificate; } + /** + * since 1.9.0 + */ + public String[] getEnabledProtocols() { + return enabledProtocols; + } + + /** + * since 1.9.0 + */ + public String[] getEnabledCipherSuites() { + return enabledCipherSuites; + } + /** * Builder for an {@link AsyncHttpClient} */ @@ -484,6 +504,8 @@ public static class Builder { private int maxRequestRetry = defaultMaxRequestRetry(); private boolean disableUrlEncodingForBoundedRequests = defaultDisableUrlEncodingForBoundRequests(); private int ioThreadMultiplier = defaultIoThreadMultiplier(); + private String[] enabledProtocols; + private String[] enabledCipherSuites; private TimeConverter timeConverter; private AsyncHttpProviderConfig providerConfig; @@ -903,6 +925,16 @@ public Builder setAcceptAnyCertificate(boolean acceptAnyCertificate) { return this; } + public Builder setEnabledProtocols(String[] enabledProtocols) { + this.enabledProtocols = enabledProtocols; + return this; + } + + public Builder setEnabledCipherSuites(String[] enabledCipherSuites) { + this.enabledCipherSuites = enabledCipherSuites; + return this; + } + /** * Create a config builder with values taken from the given prototype configuration. * @@ -943,6 +975,8 @@ public Builder(AsyncHttpClientConfig prototype) { hostnameVerifier = prototype.getHostnameVerifier(); strict302Handling = prototype.isStrict302Handling(); timeConverter = prototype.timeConverter; + enabledProtocols = prototype.enabledProtocols; + enabledCipherSuites = prototype.enabledCipherSuites; acceptAnyCertificate = prototype.acceptAnyCertificate; } @@ -1006,6 +1040,8 @@ else if (hostnameVerifier == null) disableUrlEncodingForBoundedRequests, // ioThreadMultiplier, // timeConverter,// + enabledProtocols, // + enabledCipherSuites, // providerConfig); } } diff --git a/src/main/java/com/ning/http/client/SSLEngineFactory.java b/src/main/java/com/ning/http/client/SSLEngineFactory.java index ec34af3871..9c51d97f48 100644 --- a/src/main/java/com/ning/http/client/SSLEngineFactory.java +++ b/src/main/java/com/ning/http/client/SSLEngineFactory.java @@ -13,6 +13,9 @@ */ package com.ning.http.client; +import com.ning.http.util.SslUtils; + +import javax.net.ssl.SSLContext; import javax.net.ssl.SSLEngine; import java.security.GeneralSecurityException; @@ -21,11 +24,40 @@ * Factory that creates an {@link SSLEngine} to be used for a single SSL connection. */ public interface SSLEngineFactory { + /** * Creates new {@link SSLEngine}. * * @return new engine * @throws GeneralSecurityException if the SSLEngine cannot be created */ - SSLEngine newSSLEngine() throws GeneralSecurityException; + SSLEngine newSSLEngine(String peerHost, int peerPort) throws GeneralSecurityException; + + public static class DefaultSSLEngineFactory implements SSLEngineFactory { + + private final AsyncHttpClientConfig config; + + public DefaultSSLEngineFactory(AsyncHttpClientConfig config) { + this.config = config; + } + + @Override + public SSLEngine newSSLEngine(String peerHost, int peerPort) throws GeneralSecurityException { + SSLContext sslContext = config.getSSLContext(); + + if (sslContext == null) + sslContext = SslUtils.getInstance().getSSLContext(config.isAcceptAnyCertificate()); + + SSLEngine sslEngine = sslContext.createSSLEngine(peerHost, peerPort); + sslEngine.setUseClientMode(true); + + if (config.getEnabledProtocols() != null) + sslEngine.setEnabledProtocols(config.getEnabledProtocols()); + + if (config.getEnabledCipherSuites() != null) + sslEngine.setEnabledCipherSuites(config.getEnabledCipherSuites()); + + return sslEngine; + } + } } diff --git a/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java b/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java index 5fd4fb7cff..818fc23754 100644 --- a/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java +++ b/src/main/java/com/ning/http/client/providers/netty/channel/ChannelManager.java @@ -41,6 +41,7 @@ import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.ConnectionPoolPartitioning; import com.ning.http.client.ProxyServer; +import com.ning.http.client.SSLEngineFactory; import com.ning.http.client.providers.netty.Callback; import com.ning.http.client.providers.netty.NettyAsyncHttpProviderConfig; import com.ning.http.client.providers.netty.channel.pool.ChannelPool; @@ -54,9 +55,7 @@ import com.ning.http.client.providers.netty.handler.WebSocketProtocol; import com.ning.http.client.providers.netty.request.NettyRequestSender; import com.ning.http.client.uri.Uri; -import com.ning.http.util.SslUtils; -import javax.net.ssl.SSLContext; import javax.net.ssl.SSLEngine; import java.io.IOException; @@ -85,6 +84,7 @@ public class ChannelManager { private final AsyncHttpClientConfig config; private final NettyAsyncHttpProviderConfig nettyConfig; + private final SSLEngineFactory sslEngineFactory; private final ChannelPool channelPool; private final boolean maxTotalConnectionsEnabled; private final Semaphore freeChannels; @@ -109,6 +109,7 @@ public ChannelManager(AsyncHttpClientConfig config, NettyAsyncHttpProviderConfig this.config = config; this.nettyConfig = nettyConfig; this.nettyTimer = nettyTimer; + this.sslEngineFactory = nettyConfig.getSslEngineFactory() != null? nettyConfig.getSslEngineFactory() : new SSLEngineFactory.DefaultSSLEngineFactory(config); ChannelPool channelPool = nettyConfig.getChannelPool(); if (channelPool == null && config.isAllowPoolingConnections()) { @@ -376,19 +377,7 @@ private HttpClientCodec newHttpClientCodec() { } public SslHandler createSslHandler(String peerHost, int peerPort) throws GeneralSecurityException, IOException { - SSLEngine sslEngine = null; - if (nettyConfig.getSslEngineFactory() != null) { - sslEngine = nettyConfig.getSslEngineFactory().newSSLEngine(); - - } else { - SSLContext sslContext = config.getSSLContext(); - if (sslContext == null) - sslContext = SslUtils.getInstance().getSSLContext(config.isAcceptAnyCertificate()); - - sslEngine = sslContext.createSSLEngine(peerHost, peerPort); - sslEngine.setUseClientMode(true); - } - + SSLEngine sslEngine = sslEngineFactory.newSSLEngine(peerHost, peerPort); return handshakeTimeout > 0 ? new SslHandler(sslEngine, getDefaultBufferPool(), false, nettyTimer, handshakeTimeout) : new SslHandler(sslEngine); } diff --git a/src/main/java/com/ning/http/util/SslUtils.java b/src/main/java/com/ning/http/util/SslUtils.java index f298f9dbcd..64a5bc4330 100644 --- a/src/main/java/com/ning/http/util/SslUtils.java +++ b/src/main/java/com/ning/http/util/SslUtils.java @@ -19,7 +19,6 @@ import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; -import java.io.IOException; import java.security.GeneralSecurityException; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; @@ -62,7 +61,7 @@ public static SslUtils getInstance() { return SingletonHolder.instance; } - public SSLContext getSSLContext(boolean acceptAnyCertificate) throws GeneralSecurityException, IOException { + public SSLContext getSSLContext(boolean acceptAnyCertificate) throws GeneralSecurityException { return acceptAnyCertificate ? looseTrustManagerSSLContext : SSLContext.getDefault(); } } From 6a0b689c1de67e0a3b7559e30ff131d6686fa5cd Mon Sep 17 00:00:00 2001 From: Ben Barnard Date: Mon, 27 Oct 2014 14:37:20 +0100 Subject: [PATCH 666/701] Upgrade to animal-sniffer-maven-plugin 1.11 During local builds I experienced something that might have been http://jira.codehaus.org/browse/MANIMALSNIFFER-8, which is fixed in newer builds. Newer animal-sniffer releases also have some performance improvements. The animal-sniffer:check task now takes roughly three quarters of a second less time as before on my machine. --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index c7030d64c7..844f778a65 100644 --- a/pom.xml +++ b/pom.xml @@ -248,7 +248,7 @@ org.codehaus.mojo animal-sniffer-maven-plugin - 1.6 + 1.11 org.codehaus.mojo.signature From e86d1f4b03818a9d6c94e760daebf31eeb5a8b65 Mon Sep 17 00:00:00 2001 From: Ben Barnard Date: Mon, 27 Oct 2014 16:57:56 +0100 Subject: [PATCH 667/701] Add tests for connection events MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is groundwork for adding more events in #732. Sadly I couldn’t put these higher up in the test hierarchy, because the Grizzly provider doesn’t seem to fire most events. --- .../client/async/EventCollectingHandler.java | 89 +++++++++++++++++++ .../netty/NettyAsyncProviderBasicTest.java | 37 ++++++++ .../async/netty/NettyBasicHttpsTest.java | 36 ++++++++ .../async/netty/NettyConnectionPoolTest.java | 32 +++++++ 4 files changed, 194 insertions(+) create mode 100644 src/test/java/com/ning/http/client/async/EventCollectingHandler.java diff --git a/src/test/java/com/ning/http/client/async/EventCollectingHandler.java b/src/test/java/com/ning/http/client/async/EventCollectingHandler.java new file mode 100644 index 0000000000..9e2c44e8a0 --- /dev/null +++ b/src/test/java/com/ning/http/client/async/EventCollectingHandler.java @@ -0,0 +1,89 @@ +package com.ning.http.client.async; + +import org.testng.Assert; + +import com.ning.http.client.AsyncCompletionHandlerBase; +import com.ning.http.client.AsyncHandlerExtensions; +import com.ning.http.client.HttpResponseHeaders; +import com.ning.http.client.HttpResponseStatus; +import com.ning.http.client.Response; + +import java.util.Queue; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +public class EventCollectingHandler extends AsyncCompletionHandlerBase implements AsyncHandlerExtensions { + public Queue firedEvents = new ConcurrentLinkedQueue(); + private CountDownLatch completionLatch = new CountDownLatch(1); + + public void waitForCompletion() throws InterruptedException { + if (!completionLatch.await(AbstractBasicTest.TIMEOUT, TimeUnit.SECONDS)) { + Assert.fail("Timeout out"); + } + } + + @Override + public Response onCompleted(Response response) throws Exception { + firedEvents.add("Completed"); + try { + return super.onCompleted(response); + } finally { + completionLatch.countDown(); + } + } + + @Override + public STATE onStatusReceived(HttpResponseStatus status) throws Exception { + firedEvents.add("StatusReceived"); + return super.onStatusReceived(status); + } + + @Override + public STATE onHeadersReceived(HttpResponseHeaders headers) throws Exception { + firedEvents.add("HeadersReceived"); + return super.onHeadersReceived(headers); + } + + @Override + public STATE onHeaderWriteCompleted() { + firedEvents.add("HeaderWriteCompleted"); + return super.onHeaderWriteCompleted(); + } + + @Override + public STATE onContentWriteCompleted() { + firedEvents.add("ContentWriteCompleted"); + return super.onContentWriteCompleted(); + } + + @Override + public void onOpenConnection() { + firedEvents.add("OpenConnection"); + } + + @Override + public void onConnectionOpen() { + firedEvents.add("ConnectionOpen"); + } + + @Override + public void onPoolConnection() { + firedEvents.add("PoolConnection"); + } + + @Override + public void onConnectionPooled() { + firedEvents.add("ConnectionPooled"); + } + + @Override + public void onSendRequest(Object request) { + firedEvents.add("SendRequest"); + } + + @Override + public void onRetry() { + firedEvents.add("Retry"); + } +} 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 02718102ab..acc5bc6292 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 @@ -12,15 +12,27 @@ */ package com.ning.http.client.async.netty; +import static org.testng.Assert.assertEquals; + import org.testng.annotations.Test; +import com.google.common.base.Joiner; import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.AsyncHttpProviderConfig; +import com.ning.http.client.Request; +import com.ning.http.client.RequestBuilder; import com.ning.http.client.async.AsyncProvidersBasicTest; +import com.ning.http.client.async.EventCollectingHandler; import com.ning.http.client.async.ProviderUtil; import com.ning.http.client.providers.netty.NettyAsyncHttpProviderConfig; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + @Test public class NettyAsyncProviderBasicTest extends AsyncProvidersBasicTest { @@ -38,4 +50,29 @@ public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { protected String generatedAcceptEncodingHeader() { return "gzip,deflate"; } + + @Test(groups = { "standalone", "default_provider", "async" }) + public void testNewConnectionEventsFired() throws InterruptedException, TimeoutException, ExecutionException { + Request request = new RequestBuilder("GET").setUrl("http://127.0.0.1:" + port1 + "/Test").build(); + + try (AsyncHttpClient client = getAsyncHttpClient(null)) { + EventCollectingHandler handler = new EventCollectingHandler(); + client.executeRequest(request, handler).get(3, TimeUnit.SECONDS); + handler.waitForCompletion(); + + List expectedEvents = Arrays.asList( + "PoolConnection", + "OpenConnection", + "ConnectionOpen", + "SendRequest", + "HeaderWriteCompleted", + "StatusReceived", + "HeadersReceived", + "Completed"); + + assertEquals(handler.firedEvents, expectedEvents, + "Got: " + Joiner.on(", ").join(handler.firedEvents)); + } + + } } diff --git a/src/test/java/com/ning/http/client/async/netty/NettyBasicHttpsTest.java b/src/test/java/com/ning/http/client/async/netty/NettyBasicHttpsTest.java index 1b205a900e..c45f7a59ed 100644 --- a/src/test/java/com/ning/http/client/async/netty/NettyBasicHttpsTest.java +++ b/src/test/java/com/ning/http/client/async/netty/NettyBasicHttpsTest.java @@ -12,13 +12,49 @@ */ package com.ning.http.client.async.netty; +import static org.testng.Assert.assertEquals; + +import org.testng.annotations.Test; + +import com.google.common.base.Joiner; import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.async.BasicHttpsTest; +import com.ning.http.client.async.EventCollectingHandler; import com.ning.http.client.async.ProviderUtil; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicBoolean; + public class NettyBasicHttpsTest extends BasicHttpsTest { + @Test + public void testNormalEventsFired() throws InterruptedException, TimeoutException, ExecutionException { + try (AsyncHttpClient client = getAsyncHttpClient(new AsyncHttpClientConfig.Builder().setSSLContext(createSSLContext(new AtomicBoolean(true))).build())) { + EventCollectingHandler handler = new EventCollectingHandler(); + client.preparePost(getTargetUrl()).setBody("whatever").execute(handler).get(3, TimeUnit.SECONDS); + handler.waitForCompletion(); + + List expectedEvents = Arrays.asList( + "PoolConnection", + "OpenConnection", + "ConnectionOpen", + "SendRequest", + "HeaderWriteCompleted", + "StatusReceived", + "HeadersReceived", + "Completed"); + + assertEquals(handler.firedEvents, expectedEvents, + "Got: " + Joiner.on(", ").join(handler.firedEvents)); + } + + } + @Override public AsyncHttpClient getAsyncHttpClient(AsyncHttpClientConfig config) { return ProviderUtil.nettyProvider(config); diff --git a/src/test/java/com/ning/http/client/async/netty/NettyConnectionPoolTest.java b/src/test/java/com/ning/http/client/async/netty/NettyConnectionPoolTest.java index 1039335e4f..9d309f7bfa 100644 --- a/src/test/java/com/ning/http/client/async/netty/NettyConnectionPoolTest.java +++ b/src/test/java/com/ning/http/client/async/netty/NettyConnectionPoolTest.java @@ -21,16 +21,22 @@ import org.jboss.netty.channel.Channel; import org.testng.annotations.Test; +import com.google.common.base.Joiner; import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClientConfig; +import com.ning.http.client.Request; +import com.ning.http.client.RequestBuilder; import com.ning.http.client.Response; import com.ning.http.client.async.ConnectionPoolTest; +import com.ning.http.client.async.EventCollectingHandler; import com.ning.http.client.async.ProviderUtil; import com.ning.http.client.providers.netty.NettyAsyncHttpProviderConfig; import com.ning.http.client.providers.netty.channel.pool.ChannelPool; import com.ning.http.client.providers.netty.channel.pool.NoopChannelPool; import java.net.ConnectException; +import java.util.Arrays; +import java.util.List; import java.util.concurrent.TimeUnit; public class NettyConnectionPoolTest extends ConnectionPoolTest { @@ -131,5 +137,31 @@ public void testHostNotContactable() { } } + @Test + public void testPooledEventsFired() throws Exception { + Request request = new RequestBuilder("GET").setUrl("http://127.0.0.1:" + port1 + "/Test").build(); + + try (AsyncHttpClient client = getAsyncHttpClient(null)) { + EventCollectingHandler firstHandler = new EventCollectingHandler(); + client.executeRequest(request, firstHandler).get(3, TimeUnit.SECONDS); + firstHandler.waitForCompletion(); + + EventCollectingHandler secondHandler = new EventCollectingHandler(); + client.executeRequest(request, secondHandler).get(3, TimeUnit.SECONDS); + secondHandler.waitForCompletion(); + + List expectedEvents = Arrays.asList( + "PoolConnection", + "ConnectionPooled", + "SendRequest", + "HeaderWriteCompleted", + "StatusReceived", + "HeadersReceived", + "Completed"); + + assertEquals(secondHandler.firedEvents, expectedEvents, + "Got: " + Joiner.on(", ").join(secondHandler.firedEvents)); + } + } } From 8e5570989703e472a6cb9acf873e9457b4a25095 Mon Sep 17 00:00:00 2001 From: Ben Barnard Date: Mon, 27 Oct 2014 16:58:02 +0100 Subject: [PATCH 668/701] Add additional handler extension callbacks Implements #732 for 1.9.x. --- .../http/client/AsyncHandlerExtensions.java | 10 ++++++++++ .../netty/request/NettyConnectListener.java | 7 ++++++- .../netty/request/NettyRequestSender.java | 17 ++++++++++------- .../client/async/EventCollectingHandler.java | 10 ++++++++++ .../netty/NettyAsyncProviderBasicTest.java | 1 + .../client/async/netty/NettyBasicHttpsTest.java | 2 ++ 6 files changed, 39 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/ning/http/client/AsyncHandlerExtensions.java b/src/main/java/com/ning/http/client/AsyncHandlerExtensions.java index bcfe4cd171..f60bf6a772 100644 --- a/src/main/java/com/ning/http/client/AsyncHandlerExtensions.java +++ b/src/main/java/com/ning/http/client/AsyncHandlerExtensions.java @@ -59,4 +59,14 @@ public interface AsyncHandlerExtensions { * Notify the callback every time a request is being retried. */ void onRetry(); + + /** + * Notify the callback after DNS resolution has completed. + */ + void onDnsResolved(); + + /** + * Notify the callback when the SSL handshake performed to establish an HTTPS connection has been completed. + */ + void onSslHandshakeCompleted(); } diff --git a/src/main/java/com/ning/http/client/providers/netty/request/NettyConnectListener.java b/src/main/java/com/ning/http/client/providers/netty/request/NettyConnectListener.java index c859c133b1..50547de2c4 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/NettyConnectListener.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/NettyConnectListener.java @@ -22,6 +22,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.ning.http.client.AsyncHandler; import com.ning.http.client.AsyncHandlerExtensions; import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.providers.netty.channel.ChannelManager; @@ -71,7 +72,7 @@ private void abortChannelPreemption(String poolKey) { if (channelPreempted) channelManager.abortChannelPreemption(poolKey); } - + private void writeRequest(Channel channel, String poolKey) { LOGGER.debug("Request using non cached Channel '{}':\n{}\n", channel, future.getNettyRequest().getHttpRequest()); @@ -108,6 +109,10 @@ public void operationComplete(ChannelFuture handshakeFuture) throws Exception { LOGGER.debug("onFutureSuccess: session = {}, id = {}, isValid = {}, host = {}", session.toString(), Base64.encode(session.getId()), session.isValid(), host); if (hostnameVerifier.verify(host, session)) { + final AsyncHandler asyncHandler = future.getAsyncHandler(); + if (asyncHandler instanceof AsyncHandlerExtensions) + AsyncHandlerExtensions.class.cast(asyncHandler).onSslHandshakeCompleted(); + writeRequest(channel, poolKey); } else { abortChannelPreemption(poolKey); diff --git a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java index 5468b6f899..c176f20414 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java @@ -250,7 +250,7 @@ private ListenableFuture sendRequestWithNewChannel(// HttpMethod method = future.getNettyRequest().getHttpRequest().getMethod(); requestFactory.addAuthorizationHeader(headers, requestFactory.firstRequestOnlyAuthorizationHeader(request, uri, proxy, realm)); requestFactory.setProxyAuthorizationHeader(headers, requestFactory.firstRequestOnlyProxyAuthorizationHeader(request, proxy, method)); - + // Do not throw an exception when we need an extra connection for a // redirect // FIXME why? This violate the max connection per host handling, right? @@ -276,7 +276,7 @@ private ListenableFuture sendRequestWithNewChannel(// if (asyncHandler instanceof AsyncHandlerExtensions) AsyncHandlerExtensions.class.cast(asyncHandler).onOpenConnection(); - ChannelFuture channelFuture = connect(request, uri, proxy, useProxy, bootstrap); + ChannelFuture channelFuture = connect(request, uri, proxy, useProxy, bootstrap, asyncHandler); channelFuture.addListener(new NettyConnectListener(config, future, this, channelManager, channelPreempted, poolKey)); } catch (Throwable t) { @@ -308,17 +308,17 @@ private NettyResponseFuture newNettyResponseFuture(Uri uri, Request reque } public void writeRequest(NettyResponseFuture future, Channel channel) { - + NettyRequest nettyRequest = future.getNettyRequest(); HttpRequest httpRequest = nettyRequest.getHttpRequest(); AsyncHandler handler = future.getAsyncHandler(); - + // if the channel is dead because it was pooled and the remote // server decided to close it, // we just let it go and the channelInactive do its work if (!Channels.isChannelValid(channel)) return; - + try { if (handler instanceof TransferCompletionHandler) configureTransferAdapter(handler, httpRequest); @@ -362,9 +362,12 @@ else if (!useProxy || avoidProxy(proxy, uri.getHost())) return new InetSocketAddress(proxy.getHost(), proxy.getPort()); } - private ChannelFuture connect(Request request, Uri uri, ProxyServer proxy, boolean useProxy, ClientBootstrap bootstrap) { + private ChannelFuture connect(Request request, Uri uri, ProxyServer proxy, boolean useProxy, ClientBootstrap bootstrap, AsyncHandler asyncHandler) { InetSocketAddress remoteAddress = remoteAddress(request, uri, proxy, useProxy); + if (asyncHandler instanceof AsyncHandlerExtensions) + AsyncHandlerExtensions.class.cast(asyncHandler).onDnsResolved(); + if (request.getLocalAddress() != null) return bootstrap.connect(remoteAddress, new InetSocketAddress(request.getLocalAddress(), 0)); else @@ -484,7 +487,7 @@ private boolean validateWebSocketRequest(Request request, AsyncHandler asyncH } public Channel pollAndVerifyCachedChannel(Uri uri, ProxyServer proxy, ConnectionPoolPartitioning connectionPoolPartitioning, AsyncHandler asyncHandler) { - + if (asyncHandler instanceof AsyncHandlerExtensions) AsyncHandlerExtensions.class.cast(asyncHandler).onPoolConnection(); diff --git a/src/test/java/com/ning/http/client/async/EventCollectingHandler.java b/src/test/java/com/ning/http/client/async/EventCollectingHandler.java index 9e2c44e8a0..4e30c90f3f 100644 --- a/src/test/java/com/ning/http/client/async/EventCollectingHandler.java +++ b/src/test/java/com/ning/http/client/async/EventCollectingHandler.java @@ -86,4 +86,14 @@ public void onSendRequest(Object request) { public void onRetry() { firedEvents.add("Retry"); } + + @Override + public void onDnsResolved() { + firedEvents.add("DnsResolved"); + } + + @Override + public void onSslHandshakeCompleted() { + firedEvents.add("SslHandshakeCompleted"); + } } 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 acc5bc6292..a45521cfc0 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 @@ -63,6 +63,7 @@ public void testNewConnectionEventsFired() throws InterruptedException, TimeoutE List expectedEvents = Arrays.asList( "PoolConnection", "OpenConnection", + "DnsResolved", "ConnectionOpen", "SendRequest", "HeaderWriteCompleted", diff --git a/src/test/java/com/ning/http/client/async/netty/NettyBasicHttpsTest.java b/src/test/java/com/ning/http/client/async/netty/NettyBasicHttpsTest.java index c45f7a59ed..a2df20c56a 100644 --- a/src/test/java/com/ning/http/client/async/netty/NettyBasicHttpsTest.java +++ b/src/test/java/com/ning/http/client/async/netty/NettyBasicHttpsTest.java @@ -42,6 +42,8 @@ public void testNormalEventsFired() throws InterruptedException, TimeoutExceptio List expectedEvents = Arrays.asList( "PoolConnection", "OpenConnection", + "DnsResolved", + "SslHandshakeCompleted", "ConnectionOpen", "SendRequest", "HeaderWriteCompleted", From ed270d28d00adcb9c7b4d12ec63c74f2b23f263d Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 28 Oct 2014 16:45:18 +0100 Subject: [PATCH 669/701] =?UTF-8?q?Fix=20class=20header=20"pour=20que=20JF?= =?UTF-8?q?A=20arr=C3=AAte=20de=20chialer=20comme=20un=20Qu=C3=A9becois"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../http/client/async/EventCollectingHandler.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/test/java/com/ning/http/client/async/EventCollectingHandler.java b/src/test/java/com/ning/http/client/async/EventCollectingHandler.java index 4e30c90f3f..13402952d9 100644 --- a/src/test/java/com/ning/http/client/async/EventCollectingHandler.java +++ b/src/test/java/com/ning/http/client/async/EventCollectingHandler.java @@ -1,3 +1,16 @@ +/* + * Copyright (c) 2014 AsyncHttpClient Project. 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; import org.testng.Assert; From 01031b6132fc7b671354f46c94cf94b5b777898a Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 30 Oct 2014 15:03:59 +0100 Subject: [PATCH 670/701] Made logger static to improve performance. Fixed logger name, backport #749 --- .../java/com/ning/http/client/AsyncCompletionHandler.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/ning/http/client/AsyncCompletionHandler.java b/src/main/java/com/ning/http/client/AsyncCompletionHandler.java index 402972cbf7..e5f916007c 100644 --- a/src/main/java/com/ning/http/client/AsyncCompletionHandler.java +++ b/src/main/java/com/ning/http/client/AsyncCompletionHandler.java @@ -28,7 +28,7 @@ */ public abstract class AsyncCompletionHandler implements AsyncHandler, ProgressAsyncHandler { - private final Logger log = LoggerFactory.getLogger(AsyncCompletionHandlerBase.class); + private static final Logger LOGGER = LoggerFactory.getLogger(AsyncCompletionHandler.class); private final Response.ResponseBuilder builder = new Response.ResponseBuilder(); @Override @@ -57,7 +57,7 @@ public final T onCompleted() throws Exception { @Override public void onThrowable(Throwable t) { - log.debug(t.getMessage(), t); + LOGGER.debug(t.getMessage(), t); } /** From 607be69f6a8fcf00583425a9471969e30b05cf68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Fredrik=20Wed=C3=A9n?= Date: Thu, 30 Oct 2014 15:35:45 +0100 Subject: [PATCH 671/701] Fix handling of multiple double dots above root in parsing of relative URI --- .../com/ning/http/client/uri/UriParser.java | 2 + .../com/ning/http/client/uri/UriTest.java | 132 +++++++++++++++++- 2 files changed, 133 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/ning/http/client/uri/UriParser.java b/src/main/java/com/ning/http/client/uri/UriParser.java index 979b31a885..311d9c6133 100644 --- a/src/main/java/com/ning/http/client/uri/UriParser.java +++ b/src/main/java/com/ning/http/client/uri/UriParser.java @@ -213,6 +213,8 @@ private void removeEmbedded2Dots() { if (end >= 0 && path.indexOf("/../", end) != 0) { path = path.substring(0, end) + path.substring(i + 3); i = 0; + } else if (end == 0) { + break; } } else i = i + 3; diff --git a/src/test/java/com/ning/http/client/uri/UriTest.java b/src/test/java/com/ning/http/client/uri/UriTest.java index 1c57c60c56..e64bf50a5c 100644 --- a/src/test/java/com/ning/http/client/uri/UriTest.java +++ b/src/test/java/com/ning/http/client/uri/UriTest.java @@ -15,6 +15,7 @@ import org.testng.annotations.Test; import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertNull; public class UriTest { @@ -83,5 +84,134 @@ public void testAbsoluteURIWithContext() { assertEquals(url.getPath(), "/750198471659552/accounts/test-users"); assertEquals(url.getQuery(), "method=get&access_token=750198471659552lleveCvbUu_zqBa9tkT3tcgaPh4"); } -} + @Test + public void testRelativeUriWithDots() { + Uri context = Uri.create("https://hello.com/level1/level2/"); + + Uri url = Uri.create(context, "../other/content/img.png"); + + assertEquals(url.getScheme(), "https"); + assertEquals(url.getHost(), "hello.com"); + assertEquals(url.getPort(), -1); + assertEquals(url.getPath(), "/level1/other/content/img.png"); + assertNull(url.getQuery()); + } + + @Test + public void testRelativeUriWithDotsAboveRoot() { + Uri context = Uri.create("https://hello.com/level1"); + + Uri url = Uri.create(context, "../other/content/img.png"); + + assertEquals(url.getScheme(), "https"); + assertEquals(url.getHost(), "hello.com"); + assertEquals(url.getPort(), -1); + assertEquals(url.getPath(), "/../other/content/img.png"); + assertNull(url.getQuery()); + } + + @Test + public void testRelativeUriWithAbsoluteDots() { + Uri context = Uri.create("https://hello.com/level1/"); + + Uri url = Uri.create(context, "/../other/content/img.png"); + + assertEquals(url.getScheme(), "https"); + assertEquals(url.getHost(), "hello.com"); + assertEquals(url.getPort(), -1); + assertEquals(url.getPath(), "/../other/content/img.png"); + assertNull(url.getQuery()); + } + + @Test + public void testRelativeUriWithConsecutiveDots() { + Uri context = Uri.create("https://hello.com/level1/level2/"); + + Uri url = Uri.create(context, "../../other/content/img.png"); + + assertEquals(url.getScheme(), "https"); + assertEquals(url.getHost(), "hello.com"); + assertEquals(url.getPort(), -1); + assertEquals(url.getPath(), "/other/content/img.png"); + assertNull(url.getQuery()); + } + + @Test + public void testRelativeUriWithConsecutiveDotsAboveRoot() { + Uri context = Uri.create("https://hello.com/level1/level2"); + + Uri url = Uri.create(context, "../../other/content/img.png"); + + assertEquals(url.getScheme(), "https"); + assertEquals(url.getHost(), "hello.com"); + assertEquals(url.getPort(), -1); + assertEquals(url.getPath(), "/../other/content/img.png"); + assertNull(url.getQuery()); + } + + @Test + public void testRelativeUriWithAbsoluteConsecutiveDots() { + Uri context = Uri.create("https://hello.com/level1/level2/"); + + Uri url = Uri.create(context, "/../../other/content/img.png"); + + assertEquals(url.getScheme(), "https"); + assertEquals(url.getHost(), "hello.com"); + assertEquals(url.getPort(), -1); + assertEquals(url.getPath(), "/../../other/content/img.png"); + assertNull(url.getQuery()); + } + + @Test + public void testRelativeUriWithConsecutiveDotsFromRoot() { + Uri context = Uri.create("https://hello.com/"); + + Uri url = Uri.create(context, "../../../other/content/img.png"); + + assertEquals(url.getScheme(), "https"); + assertEquals(url.getHost(), "hello.com"); + assertEquals(url.getPort(), -1); + assertEquals(url.getPath(), "/../../../other/content/img.png"); + assertNull(url.getQuery()); + } + + @Test + public void testRelativeUriWithConsecutiveDotsFromRootResource() { + Uri context = Uri.create("https://hello.com/level1"); + + Uri url = Uri.create(context, "../../../other/content/img.png"); + + assertEquals(url.getScheme(), "https"); + assertEquals(url.getHost(), "hello.com"); + assertEquals(url.getPort(), -1); + assertEquals(url.getPath(), "/../../../other/content/img.png"); + assertNull(url.getQuery()); + } + + @Test + public void testRelativeUriWithConsecutiveDotsFromSubrootResource() { + Uri context = Uri.create("https://hello.com/level1/level2"); + + Uri url = Uri.create(context, "../../../other/content/img.png"); + + assertEquals(url.getScheme(), "https"); + assertEquals(url.getHost(), "hello.com"); + assertEquals(url.getPort(), -1); + assertEquals(url.getPath(), "/../../other/content/img.png"); + assertNull(url.getQuery()); + } + + @Test + public void testRelativeUriWithConsecutiveDotsFromLevel3Resource() { + Uri context = Uri.create("https://hello.com/level1/level2/level3"); + + Uri url = Uri.create(context, "../../../other/content/img.png"); + + assertEquals(url.getScheme(), "https"); + assertEquals(url.getHost(), "hello.com"); + assertEquals(url.getPort(), -1); + assertEquals(url.getPath(), "/../other/content/img.png"); + assertNull(url.getQuery()); + } +} From 2f37ee2b1ac35acfa017cfdaaecfc3d12ab9bbbf Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 31 Oct 2014 12:00:27 +0100 Subject: [PATCH 672/701] Upgrade Netty 3.9.5 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 844f778a65..9655e72208 100644 --- a/pom.xml +++ b/pom.xml @@ -555,7 +555,7 @@ http://oss.sonatype.org/content/repositories/snapshots true - 3.9.4.Final + 3.9.5.Final 2.3.16 1.7 1.7 From ba1c4cfec3edcdc45db925af87328da3c2a7b7ff Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 31 Oct 2014 17:47:53 +0100 Subject: [PATCH 673/701] [maven-release-plugin] prepare release async-http-client-1.9.0-BETA20 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 9655e72208..58a770f916 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.9.0-SNAPSHOT + 1.9.0-BETA20 jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From 01ac2937c878e083b2bb0e74e2a579dbd7c0f433 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 31 Oct 2014 17:47:57 +0100 Subject: [PATCH 674/701] [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 58a770f916..9655e72208 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.9.0-BETA20 + 1.9.0-SNAPSHOT jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From 8dea296de4024b809eb6ebd46ba9edabe7dc26a0 Mon Sep 17 00:00:00 2001 From: Ben Barnard Date: Tue, 28 Oct 2014 14:54:32 +0100 Subject: [PATCH 675/701] Allow users to override connection keep alive logic Implements #733 for 1.9.x. --- .../netty/NettyAsyncHttpProviderConfig.java | 12 ++++++++++++ .../netty/handler/ConnectionStrategy.java | 18 ++++++++++++++++++ .../handler/Http1Point1ConnectionStrategy.java | 18 ++++++++++++++++++ .../providers/netty/handler/HttpProtocol.java | 10 +++++----- 4 files changed, 53 insertions(+), 5 deletions(-) create mode 100644 src/main/java/com/ning/http/client/providers/netty/handler/ConnectionStrategy.java create mode 100644 src/main/java/com/ning/http/client/providers/netty/handler/Http1Point1ConnectionStrategy.java 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 4ae1af6f91..5973eb26c5 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 @@ -21,6 +21,8 @@ import com.ning.http.client.AsyncHttpProviderConfig; import com.ning.http.client.SSLEngineFactory; import com.ning.http.client.providers.netty.channel.pool.ChannelPool; +import com.ning.http.client.providers.netty.handler.ConnectionStrategy; +import com.ning.http.client.providers.netty.handler.Http1Point1ConnectionStrategy; import com.ning.http.client.providers.netty.ws.NettyWebSocket; import java.util.Map; @@ -145,6 +147,8 @@ public Set> propertiesSet() { private boolean keepEncodingHeader = false; + private ConnectionStrategy connectionStrategy = new Http1Point1ConnectionStrategy(); + public boolean isUseDeadLockChecker() { return useDeadLockChecker; } @@ -305,6 +309,14 @@ public void setKeepEncodingHeader(boolean keepEncodingHeader) { this.keepEncodingHeader = keepEncodingHeader; } + public ConnectionStrategy getConnectionStrategy() { + return connectionStrategy; + } + + public void setConnectionStrategy(ConnectionStrategy connectionStrategy) { + this.connectionStrategy = connectionStrategy; + } + public static interface NettyWebSocketFactory { NettyWebSocket newNettyWebSocket(Channel channel, NettyAsyncHttpProviderConfig nettyConfig); } diff --git a/src/main/java/com/ning/http/client/providers/netty/handler/ConnectionStrategy.java b/src/main/java/com/ning/http/client/providers/netty/handler/ConnectionStrategy.java new file mode 100644 index 0000000000..20ce7fcb01 --- /dev/null +++ b/src/main/java/com/ning/http/client/providers/netty/handler/ConnectionStrategy.java @@ -0,0 +1,18 @@ +package com.ning.http.client.providers.netty.handler; + +import org.jboss.netty.handler.codec.http.HttpRequest; +import org.jboss.netty.handler.codec.http.HttpResponse; + +/** + * Provides an interface for decisions about HTTP connections. + */ +public interface ConnectionStrategy { + + /** + * Determines whether the connection should be kept alive after this HTTP message exchange. + * @param request the HTTP request + * @param response the HTTP response + * @return true if the connection should be kept alive, false if it should be closed. + */ + boolean keepAlive(HttpRequest request, HttpResponse response); +} diff --git a/src/main/java/com/ning/http/client/providers/netty/handler/Http1Point1ConnectionStrategy.java b/src/main/java/com/ning/http/client/providers/netty/handler/Http1Point1ConnectionStrategy.java new file mode 100644 index 0000000000..329aa948f1 --- /dev/null +++ b/src/main/java/com/ning/http/client/providers/netty/handler/Http1Point1ConnectionStrategy.java @@ -0,0 +1,18 @@ +package com.ning.http.client.providers.netty.handler; + +import org.jboss.netty.handler.codec.http.HttpHeaders; +import org.jboss.netty.handler.codec.http.HttpMessage; +import org.jboss.netty.handler.codec.http.HttpRequest; +import org.jboss.netty.handler.codec.http.HttpResponse; + +public class Http1Point1ConnectionStrategy implements ConnectionStrategy { + + @Override + public boolean keepAlive(HttpRequest httpRequest, HttpResponse response) { + return isConnectionKeepAlive(httpRequest) && isConnectionKeepAlive(response); + } + + public boolean isConnectionKeepAlive(HttpMessage message) { + return !HttpHeaders.Values.CLOSE.equalsIgnoreCase(message.headers().get(HttpHeaders.Names.CONNECTION)); + } +} diff --git a/src/main/java/com/ning/http/client/providers/netty/handler/HttpProtocol.java b/src/main/java/com/ning/http/client/providers/netty/handler/HttpProtocol.java index 39286edc92..29e5a49070 100644 --- a/src/main/java/com/ning/http/client/providers/netty/handler/HttpProtocol.java +++ b/src/main/java/com/ning/http/client/providers/netty/handler/HttpProtocol.java @@ -56,9 +56,13 @@ public final class HttpProtocol extends Protocol { + private final ConnectionStrategy connectionStrategy; + public HttpProtocol(ChannelManager channelManager, AsyncHttpClientConfig config, NettyAsyncHttpProviderConfig nettyConfig, NettyRequestSender requestSender) { super(channelManager, config, nettyConfig, requestSender); + + connectionStrategy = nettyConfig.getConnectionStrategy(); } private Realm.RealmBuilder newRealmBuilder(Realm realm) { @@ -402,10 +406,6 @@ private boolean exitAfterHandlingBody(Channel channel, NettyResponseFuture fu return false; } - private boolean isConnectionKeepAlive(HttpHeaders headers) { - return !HttpHeaders.Values.CLOSE.equalsIgnoreCase(headers.get(HttpHeaders.Names.CONNECTION)); - } - private boolean handleHttpResponse(final HttpResponse response,// final Channel channel,// final NettyResponseFuture future,// @@ -419,7 +419,7 @@ private boolean handleHttpResponse(final HttpResponse response,// // the handler in case of trailing headers future.setHttpHeaders(response.headers()); - future.setKeepAlive(isConnectionKeepAlive(httpRequest.headers()) && isConnectionKeepAlive(response.headers())); + future.setKeepAlive(connectionStrategy.keepAlive(httpRequest, response)); NettyResponseStatus status = new NettyResponseStatus(future.getUri(), config, response); int statusCode = response.getStatus().getCode(); From ec051548aba0576598369d507205e38a2ffb2a4b Mon Sep 17 00:00:00 2001 From: Ben Barnard Date: Mon, 3 Nov 2014 17:28:23 +0100 Subject: [PATCH 676/701] Add missing headers and comments Mea culpa, I should know better by now. --- .../netty/handler/ConnectionStrategy.java | 13 ++++++++++++ .../Http1Point1ConnectionStrategy.java | 20 +++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/src/main/java/com/ning/http/client/providers/netty/handler/ConnectionStrategy.java b/src/main/java/com/ning/http/client/providers/netty/handler/ConnectionStrategy.java index 20ce7fcb01..65ab2cd7d4 100644 --- a/src/main/java/com/ning/http/client/providers/netty/handler/ConnectionStrategy.java +++ b/src/main/java/com/ning/http/client/providers/netty/handler/ConnectionStrategy.java @@ -1,3 +1,16 @@ +/* + * Copyright (c) 2014 AsyncHttpClient Project. 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.providers.netty.handler; import org.jboss.netty.handler.codec.http.HttpRequest; diff --git a/src/main/java/com/ning/http/client/providers/netty/handler/Http1Point1ConnectionStrategy.java b/src/main/java/com/ning/http/client/providers/netty/handler/Http1Point1ConnectionStrategy.java index 329aa948f1..ac4111e6f6 100644 --- a/src/main/java/com/ning/http/client/providers/netty/handler/Http1Point1ConnectionStrategy.java +++ b/src/main/java/com/ning/http/client/providers/netty/handler/Http1Point1ConnectionStrategy.java @@ -1,3 +1,16 @@ +/* + * Copyright (c) 2014 AsyncHttpClient Project. 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.providers.netty.handler; import org.jboss.netty.handler.codec.http.HttpHeaders; @@ -5,8 +18,15 @@ import org.jboss.netty.handler.codec.http.HttpRequest; import org.jboss.netty.handler.codec.http.HttpResponse; +/** + * Connection strategy implementing standard HTTP 1.1 behaviour. + */ public class Http1Point1ConnectionStrategy implements ConnectionStrategy { + /** + * Implemented in accordance with RFC 7230 section 6.1 + * https://tools.ietf.org/html/rfc7230#section-6.1 + */ @Override public boolean keepAlive(HttpRequest httpRequest, HttpResponse response) { return isConnectionKeepAlive(httpRequest) && isConnectionKeepAlive(response); From e60cd2c292029071ae46eb6bf0ebeba004ecd5fe Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 10 Nov 2014 11:33:56 +0100 Subject: [PATCH 677/701] Adjust javadoc for requestTimeout to clarify its meaning, backport #756 --- .../java/com/ning/http/client/AsyncHttpClientConfig.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java b/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java index c6bba0b597..dc6c37a67d 100644 --- a/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java @@ -211,9 +211,9 @@ public int getPooledConnectionIdleTimeout() { } /** - * Return the maximum time in millisecond an {@link com.ning.http.client.AsyncHttpClient} wait for a response + * Return the maximum time in millisecond an {@link com.ning.http.client.AsyncHttpClient} waits until the response is completed. * - * @return the maximum time in millisecond an {@link com.ning.http.client.AsyncHttpClient} wait for a response + * @return the maximum time in millisecond an {@link com.ning.http.client.AsyncHttpClient} waits until the response is completed. */ public int getRequestTimeout() { return requestTimeout; @@ -584,9 +584,9 @@ public Builder setPooledConnectionIdleTimeout(int pooledConnectionIdleTimeout) { } /** - * Set the maximum time in millisecond an {@link com.ning.http.client.AsyncHttpClient} wait for a response + * Set the maximum time in millisecond an {@link com.ning.http.client.AsyncHttpClient} waits until the response is completed. * - * @param requestTimeout the maximum time in millisecond an {@link com.ning.http.client.AsyncHttpClient} wait for a response + * @param requestTimeout the maximum time in millisecond an {@link com.ning.http.client.AsyncHttpClient} waits until the response is completed. * @return a {@link Builder} */ public Builder setRequestTimeout(int requestTimeout) { From dfb8ac055c4fce468fdb795de787b79a100d6786 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 10 Nov 2014 15:12:29 +0100 Subject: [PATCH 678/701] FluentCaseInsensitiveStringsMap.get should return an empty immutable list instead of null, close #758 --- .../ning/http/client/FluentCaseInsensitiveStringsMap.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/main/java/com/ning/http/client/FluentCaseInsensitiveStringsMap.java b/src/main/java/com/ning/http/client/FluentCaseInsensitiveStringsMap.java index 7f6d241a8e..aa53d8042e 100644 --- a/src/main/java/com/ning/http/client/FluentCaseInsensitiveStringsMap.java +++ b/src/main/java/com/ning/http/client/FluentCaseInsensitiveStringsMap.java @@ -420,11 +420,7 @@ public List get(Object key) { String lcKey = key.toString().toLowerCase(Locale.ENGLISH); String realKey = keyLookup.get(lcKey); - if (realKey == null) { - return null; - } else { - return values.get(realKey); - } + return realKey != null ? values.get(realKey) : Collections. emptyList(); } @Override From 6a960f45056fb094b84ae9cb243e3fcbe5e9f4b5 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 10 Nov 2014 15:15:08 +0100 Subject: [PATCH 679/701] FluentCaseInsensitiveStringsMap.get should return an empty immutable list instead of null, close #758 --- .../ning/http/client/FluentCaseInsensitiveStringsMap.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/ning/http/client/FluentCaseInsensitiveStringsMap.java b/src/main/java/com/ning/http/client/FluentCaseInsensitiveStringsMap.java index aa53d8042e..190cb22339 100644 --- a/src/main/java/com/ning/http/client/FluentCaseInsensitiveStringsMap.java +++ b/src/main/java/com/ning/http/client/FluentCaseInsensitiveStringsMap.java @@ -413,9 +413,8 @@ public String getJoinedValue(String key, String delimiter) { @Override public List get(Object key) { - if (key == null) { - return null; - } + if (key == null) + return Collections.emptyList(); String lcKey = key.toString().toLowerCase(Locale.ENGLISH); String realKey = keyLookup.get(lcKey); From c196d4e619f18d9b524d2ef3b5fc75a04d4443c0 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 10 Nov 2014 15:17:01 +0100 Subject: [PATCH 680/701] [maven-release-plugin] prepare release async-http-client-1.9.0-BETA21 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 9655e72208..6b14804f2c 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.9.0-SNAPSHOT + 1.9.0-BETA21 jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From 6bc05ae1c2426daff5ef76c37f6c3fd0d6518a39 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 10 Nov 2014 15:17:06 +0100 Subject: [PATCH 681/701] [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 6b14804f2c..9655e72208 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.9.0-BETA21 + 1.9.0-SNAPSHOT jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From 7fe2fb6aac3309b7a51f036e88a02fe156022fcb Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Wed, 19 Nov 2014 10:59:35 +0100 Subject: [PATCH 682/701] Drop InputStreamBodyGenerator marking strategy, close #760 --- .../generators/InputStreamBodyGenerator.java | 20 +---- .../ning/http/client/async/ChunkingTest.java | 85 ++++++++----------- 2 files changed, 37 insertions(+), 68 deletions(-) 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 a79a2e6b9e..4060948b19 100644 --- a/src/main/java/com/ning/http/client/generators/InputStreamBodyGenerator.java +++ b/src/main/java/com/ning/http/client/generators/InputStreamBodyGenerator.java @@ -40,12 +40,6 @@ public class InputStreamBodyGenerator implements BodyGenerator { public InputStreamBodyGenerator(InputStream inputStream) { this.inputStream = inputStream; - - if (inputStream.markSupported()) { - inputStream.mark(0); - } else { - logger.info("inputStream.markSupported() not supported. Some features will not work."); - } } public InputStream getInputStream() { @@ -97,12 +91,8 @@ public long read(ByteBuffer buffer) throws IOException { buffer.put(END_PADDING); - return buffer.position(); } else { - if (inputStream.markSupported()) { - inputStream.reset(); - } eof = false; } return -1; @@ -118,14 +108,8 @@ public long read(ByteBuffer buffer) throws IOException { buffer.put(chunk, 0, read); // Was missing the final chunk \r\n. buffer.put(END_PADDING); - } else { - if (read > 0) { - buffer.put(chunk, 0, read); - } else { - if (inputStream.markSupported()) { - inputStream.reset(); - } - } + } else if (read > 0) { + buffer.put(chunk, 0, read); } return read; } 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 956a6f4f6b..b96c49d28d 100644 --- a/src/test/java/com/ning/http/client/async/ChunkingTest.java +++ b/src/test/java/com/ning/http/client/async/ChunkingTest.java @@ -18,13 +18,16 @@ import com.ning.http.client.RequestBuilder; import com.ning.http.client.Response; import com.ning.http.client.generators.InputStreamBodyGenerator; + import org.testng.annotations.Test; import java.io.BufferedInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; +import java.io.IOException; import java.io.InputStream; +import java.net.URISyntaxException; import java.net.URL; import java.util.Random; @@ -67,11 +70,21 @@ abstract public class ChunkingTest extends AbstractBasicTest { * Tests that the custom chunked stream result in success and content returned that is unchunked */ @Test() - public void testCustomChunking() throws Throwable { - doTest(true); + public void testBufferLargerThanFile() throws Throwable { + doTest(new BufferedInputStream(new FileInputStream(getTestFile()), 400000)); } - private void doTest(boolean customChunkedInputStream) throws Exception { + @Test() + public void testBufferSmallThanFile() throws Throwable { + doTest(new BufferedInputStream(new FileInputStream(getTestFile()))); + } + + @Test() + public void testDirectFile() throws Throwable { + doTest(new FileInputStream(getTestFile())); + } + + public void doTest(InputStream is) throws Throwable { AsyncHttpClientConfig.Builder bc = new AsyncHttpClientConfig.Builder()// .setAllowPoolingConnections(true)// .setMaxConnectionsPerHost(1)// @@ -84,44 +97,27 @@ private void doTest(boolean customChunkedInputStream) throws Exception { try { RequestBuilder builder = new RequestBuilder("POST"); builder.setUrl(getTargetUrl()); - if (customChunkedInputStream) { - // made buff in stream big enough to mark. - builder.setBody(new InputStreamBodyGenerator(new BufferedInputStream(new FileInputStream(getTestFile()), 400000))); + // made buff in stream big enough to mark. + builder.setBody(new InputStreamBodyGenerator(is)); + + ListenableFuture response = client.executeRequest(builder.build()); + Response res = response.get(); + assertNotNull(res.getResponseBodyAsStream()); + if (500 == res.getStatusCode()) { + assertEquals(res.getStatusCode(), 500, "Should have 500 status code"); + assertTrue(res.getHeader("X-Exception").contains("invalid.chunk.length"), "Should have failed due to chunking"); + fail("HARD Failing the test due to provided InputStreamBodyGenerator, chunking incorrectly:" + res.getHeader("X-Exception")); } else { - // made buff in stream big enough to mark. - builder.setBody(new InputStreamBodyGenerator(new BufferedInputStream(new FileInputStream(getTestFile()), 400000))); - } - com.ning.http.client.Request r = builder.build(); - Response res = null; - - try { - ListenableFuture response = client.executeRequest(r); - res = response.get(); - assertNotNull(res.getResponseBodyAsStream()); - if (500 == res.getStatusCode()) { - System.out.println("=============="); - System.out.println("500 response from call"); - System.out.println("Headers:" + res.getHeaders()); - System.out.println("=============="); - System.out.flush(); - assertEquals(res.getStatusCode(), 500, "Should have 500 status code"); - assertTrue(res.getHeader("X-Exception").contains("invalid.chunk.length"), "Should have failed due to chunking"); - fail("HARD Failing the test due to provided InputStreamBodyGenerator, chunking incorrectly:" + res.getHeader("X-Exception")); - } else { - assertEquals(readInputStreamToBytes(res.getResponseBodyAsStream()), LARGE_IMAGE_BYTES); - } - } catch (Exception e) { - - fail("Exception Thrown:" + e.getMessage()); + assertEquals(readInputStreamToBytes(res.getResponseBodyAsStream()), LARGE_IMAGE_BYTES); } } finally { if (client != null) client.close(); } } - - private byte[] readInputStreamToBytes(InputStream stream) { - byte[] data = new byte[0]; + + + private byte[] readInputStreamToBytes(InputStream stream) throws IOException { ByteArrayOutputStream buffer = new ByteArrayOutputStream(); try { int nRead; @@ -130,32 +126,21 @@ private byte[] readInputStreamToBytes(InputStream stream) { while ((nRead = stream.read(tmp, 0, tmp.length)) != -1) { buffer.write(tmp, 0, nRead); } + buffer.flush(); - data = buffer.toByteArray(); - } catch (Exception e) { + return buffer.toByteArray(); } finally { try { stream.close(); } catch (Exception e2) { } - return data; } } - private static File getTestFile() { + private static File getTestFile() throws URISyntaxException { String testResource1 = "300k.png"; - - File testResource1File = null; - try { - ClassLoader cl = ChunkingTest.class.getClassLoader(); - URL url = cl.getResource(testResource1); - testResource1File = new File(url.toURI()); - } catch (Throwable e) { - // TODO Auto-generated catch block - fail("unable to find " + testResource1); - } - - return testResource1File; + URL url = ChunkingTest.class.getClassLoader().getResource(testResource1); + return new File(url.toURI()); } } From 3b6d9589a4663435bf72726a3848bcd4c2a0e635 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 20 Nov 2014 14:18:39 +0100 Subject: [PATCH 683/701] Fix tests, disable PostRedirectGetTest that has to be reimplemented --- .../FluentCaseInsensitiveStringsMap.java | 6 ++--- .../providers/netty/util/HttpUtils.java | 3 ++- .../resumable/ResumableAsyncHandler.java | 2 +- .../ning/http/client/async/BasicAuthTest.java | 22 ------------------- .../FluentCaseInsensitiveStringsMapTest.java | 12 +++++----- .../client/async/PostRedirectGetTest.java | 15 ++++++++----- 6 files changed, 21 insertions(+), 39 deletions(-) diff --git a/src/main/java/com/ning/http/client/FluentCaseInsensitiveStringsMap.java b/src/main/java/com/ning/http/client/FluentCaseInsensitiveStringsMap.java index 190cb22339..3732279332 100644 --- a/src/main/java/com/ning/http/client/FluentCaseInsensitiveStringsMap.java +++ b/src/main/java/com/ning/http/client/FluentCaseInsensitiveStringsMap.java @@ -376,10 +376,8 @@ public boolean containsValue(Object value) { public String getFirstValue(String key) { List values = get(key); - if (values == null) { + if (values.isEmpty()) { return null; - } else if (values.isEmpty()) { - return ""; } else { return values.get(0); } @@ -394,7 +392,7 @@ public String getFirstValue(String key) { public String getJoinedValue(String key, String delimiter) { List values = get(key); - if (values == null) { + if (values.isEmpty()) { return null; } else if (values.size() == 1) { return values.get(0); diff --git a/src/main/java/com/ning/http/client/providers/netty/util/HttpUtils.java b/src/main/java/com/ning/http/client/providers/netty/util/HttpUtils.java index 1d2168a785..4edc506c2b 100644 --- a/src/main/java/com/ning/http/client/providers/netty/util/HttpUtils.java +++ b/src/main/java/com/ning/http/client/providers/netty/util/HttpUtils.java @@ -16,6 +16,7 @@ import org.jboss.netty.handler.codec.http.HttpHeaders; import com.ning.http.client.uri.Uri; +import com.ning.http.util.MiscUtils; import java.util.ArrayList; import java.util.List; @@ -32,7 +33,7 @@ private HttpUtils() { } public static String getNTLM(List authenticateHeaders) { - if (authenticateHeaders != null) { + if (MiscUtils.isNonEmpty(authenticateHeaders)) { for (String authenticateHeader: authenticateHeaders) { if (authenticateHeader.startsWith("NTLM")) return authenticateHeader; 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 4c1a1cef3e..b1ad44e88a 100644 --- a/src/main/java/com/ning/http/client/resumable/ResumableAsyncHandler.java +++ b/src/main/java/com/ning/http/client/resumable/ResumableAsyncHandler.java @@ -196,7 +196,7 @@ public Request adjustRequestRange(Request request) { } RequestBuilder builder = new RequestBuilder(request); - if (request.getHeaders().get("Range") == null && byteTransferred.get() != 0) { + if (request.getHeaders().get("Range").isEmpty() && byteTransferred.get() != 0) { builder.setHeader("Range", "bytes=" + byteTransferred.get() + "-"); } return builder.build(); 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 792a1e6c9e..8a2eca788b 100644 --- a/src/test/java/com/ning/http/client/async/BasicAuthTest.java +++ b/src/test/java/com/ning/http/client/async/BasicAuthTest.java @@ -499,28 +499,6 @@ public void basicAuthFileNoKeepAliveTest() throws Throwable { } } - @Test(groups = { "standalone", "default_provider" }) - public void stringBuilderBodyConsumerTest() throws Throwable { - AsyncHttpClient client = getAsyncHttpClient(null); - - try { - 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 = f.get(); - assertEquals(response.getStatusCode(), 200); - assertEquals(response.getResponseBody(), MY_MESSAGE); - assertEquals(response.getStatusCode(), HttpServletResponse.SC_OK); - assertNotNull(response.getHeader("X-Auth")); - } finally { - client.close(); - } - } - @Test(groups = { "standalone", "default_provider" }) public void noneAuthTest() throws IOException, ExecutionException, TimeoutException, InterruptedException { AsyncHttpClient client = getAsyncHttpClient(null); diff --git a/src/test/java/com/ning/http/client/async/FluentCaseInsensitiveStringsMapTest.java b/src/test/java/com/ning/http/client/async/FluentCaseInsensitiveStringsMapTest.java index 290158307b..7f51a46ad7 100644 --- a/src/test/java/com/ning/http/client/async/FluentCaseInsensitiveStringsMapTest.java +++ b/src/test/java/com/ning/http/client/async/FluentCaseInsensitiveStringsMapTest.java @@ -217,7 +217,7 @@ public void deleteTest() { assertEquals(map.get("foo"), Arrays.asList("bar")); assertNull(map.getFirstValue("baz")); assertNull(map.getJoinedValue("baz", ", ")); - assertNull(map.get("baz")); + assertTrue(map.get("baz").isEmpty()); } @Test @@ -295,7 +295,7 @@ public void deleteAllArrayTest() { assertEquals(map.get("foo"), Arrays.asList("bar")); assertNull(map.getFirstValue("baz")); assertNull(map.getJoinedValue("baz", ", ")); - assertNull(map.get("baz")); + assertTrue(map.get("baz").isEmpty()); } @Test @@ -318,10 +318,10 @@ public void deleteAllCollectionTest() { assertEquals(map.keySet(), Collections.emptyList()); assertNull(map.getFirstValue("foo")); assertNull(map.getJoinedValue("foo", ", ")); - assertNull(map.get("foo")); + assertTrue(map.get("foo").isEmpty()); assertNull(map.getFirstValue("baz")); assertNull(map.getJoinedValue("baz", ", ")); - assertNull(map.get("baz")); + assertTrue(map.get("baz").isEmpty()); } @Test @@ -480,7 +480,7 @@ public void replaceValueWithNullTest() { assertEquals(map.get("foo"), Arrays.asList("bar")); assertNull(map.getFirstValue("baz")); assertNull(map.getJoinedValue("baz", ", ")); - assertNull(map.get("baz")); + assertTrue(map.get("baz").isEmpty()); } @Test @@ -547,7 +547,7 @@ public void replaceAllTest2() { assertEquals(map.keySet(), new LinkedHashSet(Arrays.asList("Bar", "baz"))); assertNull(map.getFirstValue("foo")); assertNull(map.getJoinedValue("foo", ", ")); - assertNull(map.get("foo")); + assertTrue(map.get("foo").isEmpty()); assertEquals(map.getFirstValue("bar"), "baz"); assertEquals(map.getJoinedValue("bar", ", "), "baz"); assertEquals(map.get("bar"), Arrays.asList("baz")); 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 35ca5d2562..0a6da44c9a 100644 --- a/src/test/java/com/ning/http/client/async/PostRedirectGetTest.java +++ b/src/test/java/com/ning/http/client/async/PostRedirectGetTest.java @@ -44,27 +44,32 @@ public AbstractHandler configureHandler() throws Exception { // ------------------------------------------------------------ Test Methods - @Test(groups = { "standalone", "post_redirect_get" }) + // FIXME reimplement test since only some headers are propagated on redirect + @Test(groups = { "standalone", "post_redirect_get" }, enabled = false) public void postRedirectGet302Test() throws Exception { doTestPositive(302); } - @Test(groups = { "standalone", "post_redirect_get" }) + // FIXME reimplement test since only some headers are propagated on redirect + @Test(groups = { "standalone", "post_redirect_get" }, enabled = false) public void postRedirectGet302StrictTest() throws Exception { doTestNegative(302, true); } - @Test(groups = { "standalone", "post_redirect_get" }) + // FIXME reimplement test since only some headers are propagated on redirect + @Test(groups = { "standalone", "post_redirect_get" }, enabled = false) public void postRedirectGet303Test() throws Exception { doTestPositive(303); } - @Test(groups = { "standalone", "post_redirect_get" }) + // FIXME reimplement test since only some headers are propagated on redirect + @Test(groups = { "standalone", "post_redirect_get" }, enabled = false) public void postRedirectGet301Test() throws Exception { doTestNegative(301, false); } - @Test(groups = { "standalone", "post_redirect_get" }) + // FIXME reimplement test since only some headers are propagated on redirect + @Test(groups = { "standalone", "post_redirect_get" }, enabled = false) public void postRedirectGet307Test() throws Exception { doTestNegative(307, false); } From 1a89a8ea9009503786a7f74818840aa0b727533e Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 20 Nov 2014 14:18:51 +0100 Subject: [PATCH 684/701] Upgrade Grizzly 2.3.17 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 9655e72208..f0706098c7 100644 --- a/pom.xml +++ b/pom.xml @@ -556,7 +556,7 @@ http://oss.sonatype.org/content/repositories/snapshots true 3.9.5.Final - 2.3.16 + 2.3.17 1.7 1.7 2.12 From 615f2162bbb3a061e742b8518f77882c77d4c89f Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Thu, 20 Nov 2014 14:56:03 +0100 Subject: [PATCH 685/701] NPE when Future.cancel happens before channel is attached, close #762 --- .../providers/netty/future/NettyResponseFuture.java | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/future/NettyResponseFuture.java b/src/main/java/com/ning/http/client/providers/netty/future/NettyResponseFuture.java index 7e299d153f..a84280463b 100755 --- a/src/main/java/com/ning/http/client/providers/netty/future/NettyResponseFuture.java +++ b/src/main/java/com/ning/http/client/providers/netty/future/NettyResponseFuture.java @@ -129,8 +129,11 @@ public boolean cancel(boolean force) { if (isCancelled.getAndSet(true)) return false; - Channels.setDiscard(channel); - Channels.silentlyCloseChannel(channel); + // cancel could happen before channel was attached + if (channel != null) { + Channels.setDiscard(channel); + Channels.silentlyCloseChannel(channel); + } if (!onThrowableCalled.getAndSet(true)) { try { @@ -371,6 +374,12 @@ public void setConnectAllowed(boolean allowConnect) { } public void attachChannel(Channel channel, boolean reuseChannel) { + + // future could have been cancelled first + if (isDone()) { + Channels.silentlyCloseChannel(channel); + } + this.channel = channel; this.reuseChannel = reuseChannel; } From 9c28aaadd5e991f23df1fd33b79c2522b8d8ccfc Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 21 Nov 2014 16:26:15 +0100 Subject: [PATCH 686/701] Remove bodyGenerator on resetNonMultipartData --- src/main/java/com/ning/http/client/RequestBuilderBase.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/ning/http/client/RequestBuilderBase.java b/src/main/java/com/ning/http/client/RequestBuilderBase.java index b39f54b3e5..74c95cb544 100644 --- a/src/main/java/com/ning/http/client/RequestBuilderBase.java +++ b/src/main/java/com/ning/http/client/RequestBuilderBase.java @@ -374,6 +374,7 @@ public void resetNonMultipartData() { request.byteData = null; request.stringData = null; request.streamData = null; + request.bodyGenerator = null; request.length = -1; } From 09d80fdcc2dff55957ade0e35a6ec85c3572f171 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 21 Nov 2014 17:03:41 +0100 Subject: [PATCH 687/701] Let one pass a List request body, close #763 --- .../netty/request/NettyRequestFactory.java | 9 +-- .../request/body/NettyByteArrayBody.java | 18 ++---- .../body/NettyCompositeByteArrayBody.java | 55 +++++++++++++++++++ .../netty/request/body/NettyDirectBody.java | 32 +++++++++++ 4 files changed, 97 insertions(+), 17 deletions(-) create mode 100644 src/main/java/com/ning/http/client/providers/netty/request/body/NettyCompositeByteArrayBody.java create mode 100644 src/main/java/com/ning/http/client/providers/netty/request/body/NettyDirectBody.java diff --git a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestFactory.java b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestFactory.java index a0a053e582..9529d91ab4 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestFactory.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestFactory.java @@ -26,7 +26,7 @@ import static com.ning.http.util.AuthenticatorUtils.computeDigestAuthentication; import static com.ning.http.util.MiscUtils.isNonEmpty; -import org.jboss.netty.buffer.ChannelBuffers; +import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.handler.codec.http.DefaultHttpRequest; import org.jboss.netty.handler.codec.http.HttpHeaders; import org.jboss.netty.handler.codec.http.HttpMethod; @@ -46,6 +46,7 @@ import com.ning.http.client.providers.netty.request.body.NettyBody; import com.ning.http.client.providers.netty.request.body.NettyBodyBody; import com.ning.http.client.providers.netty.request.body.NettyByteArrayBody; +import com.ning.http.client.providers.netty.request.body.NettyDirectBody; import com.ning.http.client.providers.netty.request.body.NettyFileBody; import com.ning.http.client.providers.netty.request.body.NettyInputStreamBody; import com.ning.http.client.providers.netty.request.body.NettyMultipartBody; @@ -263,11 +264,11 @@ public NettyRequest newNettyRequest(Request request, Uri uri, boolean forceConne HttpRequest httpRequest; NettyRequest nettyRequest; - if (body instanceof NettyByteArrayBody) { - byte[] bytes = NettyByteArrayBody.class.cast(body).getBytes(); + if (body instanceof NettyDirectBody) { + ChannelBuffer buffer = NettyDirectBody.class.cast(body).channelBuffer(); httpRequest = new DefaultHttpRequest(httpVersion, method, requestUri); // body is passed as null as it's written directly with the request - httpRequest.setContent(ChannelBuffers.wrappedBuffer(bytes)); + httpRequest.setContent(buffer); nettyRequest = new NettyRequest(httpRequest, null); } else { diff --git a/src/main/java/com/ning/http/client/providers/netty/request/body/NettyByteArrayBody.java b/src/main/java/com/ning/http/client/providers/netty/request/body/NettyByteArrayBody.java index 78127d94f6..eec6dd629f 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/body/NettyByteArrayBody.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/body/NettyByteArrayBody.java @@ -13,14 +13,10 @@ */ package com.ning.http.client.providers.netty.request.body; -import org.jboss.netty.channel.Channel; +import org.jboss.netty.buffer.ChannelBuffer; +import org.jboss.netty.buffer.ChannelBuffers; -import com.ning.http.client.AsyncHttpClientConfig; -import com.ning.http.client.providers.netty.future.NettyResponseFuture; - -import java.io.IOException; - -public class NettyByteArrayBody implements NettyBody { +public class NettyByteArrayBody extends NettyDirectBody { private final byte[] bytes; private final String contentType; @@ -34,10 +30,6 @@ public NettyByteArrayBody(byte[] bytes, String contentType) { this.contentType = contentType; } - public byte[] getBytes() { - return bytes; - } - @Override public long getContentLength() { return bytes.length; @@ -49,7 +41,7 @@ public String getContentType() { } @Override - public void write(Channel channel, NettyResponseFuture future, AsyncHttpClientConfig config) throws IOException { - throw new UnsupportedOperationException("This kind of body is supposed to be writen directly"); + public ChannelBuffer channelBuffer() { + return ChannelBuffers.wrappedBuffer(bytes); } } diff --git a/src/main/java/com/ning/http/client/providers/netty/request/body/NettyCompositeByteArrayBody.java b/src/main/java/com/ning/http/client/providers/netty/request/body/NettyCompositeByteArrayBody.java new file mode 100644 index 0000000000..743940fe06 --- /dev/null +++ b/src/main/java/com/ning/http/client/providers/netty/request/body/NettyCompositeByteArrayBody.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2014 AsyncHttpClient Project. 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.providers.netty.request.body; + +import org.jboss.netty.buffer.ChannelBuffer; +import org.jboss.netty.buffer.ChannelBuffers; + +import java.util.List; + +public class NettyCompositeByteArrayBody extends NettyDirectBody { + + private final byte[][] bytes; + private final String contentType; + private final long contentLength; + + public NettyCompositeByteArrayBody(List bytes) { + this(bytes, null); + } + + public NettyCompositeByteArrayBody(List bytes, String contentType) { + this.bytes = new byte[bytes.size()][]; + bytes.toArray(this.bytes); + this.contentType = contentType; + long l = 0; + for (byte[] b : bytes) + l += b.length; + contentLength = l; + } + + @Override + public long getContentLength() { + return contentLength; + } + + @Override + public String getContentType() { + return contentType; + } + + @Override + public ChannelBuffer channelBuffer() { + return ChannelBuffers.wrappedBuffer(bytes); + } +} diff --git a/src/main/java/com/ning/http/client/providers/netty/request/body/NettyDirectBody.java b/src/main/java/com/ning/http/client/providers/netty/request/body/NettyDirectBody.java new file mode 100644 index 0000000000..373327053a --- /dev/null +++ b/src/main/java/com/ning/http/client/providers/netty/request/body/NettyDirectBody.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2014 AsyncHttpClient Project. 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.providers.netty.request.body; + +import org.jboss.netty.buffer.ChannelBuffer; +import org.jboss.netty.channel.Channel; + +import com.ning.http.client.AsyncHttpClientConfig; +import com.ning.http.client.providers.netty.future.NettyResponseFuture; + +import java.io.IOException; + +public abstract class NettyDirectBody implements NettyBody { + + public abstract ChannelBuffer channelBuffer(); + + @Override + public void write(Channel channel, NettyResponseFuture future, AsyncHttpClientConfig config) throws IOException { + throw new UnsupportedOperationException("This kind of body is supposed to be writen directly"); + } +} From 6cdc0532908c39ce3610e0fd71a9a5cff9162705 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 21 Nov 2014 17:23:31 +0100 Subject: [PATCH 688/701] Response.getHeaders(String name) should return an empty list instead of null, close #764 --- src/main/java/com/ning/http/client/ResponseBase.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/ning/http/client/ResponseBase.java b/src/main/java/com/ning/http/client/ResponseBase.java index 7e96ae9be2..1afc8bdb09 100644 --- a/src/main/java/com/ning/http/client/ResponseBase.java +++ b/src/main/java/com/ning/http/client/ResponseBase.java @@ -75,7 +75,7 @@ public final String getHeader(String name) { @Override public final List getHeaders(String name) { - return headers != null ? getHeaders().get(name) : null; + return headers != null ? getHeaders().get(name) : Collections. emptyList(); } @Override From a6dc5778443d171bbaf6e40090259b284a8edc62 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 21 Nov 2014 17:26:33 +0100 Subject: [PATCH 689/701] [maven-release-plugin] prepare release async-http-client-1.9.0-BETA22 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index f0706098c7..63fdcdda3f 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.9.0-SNAPSHOT + 1.9.0-BETA22 jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From cfd9ee174936cb06163bb187ae8018b3916801d6 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 21 Nov 2014 17:26:39 +0100 Subject: [PATCH 690/701] [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 63fdcdda3f..f0706098c7 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.9.0-BETA22 + 1.9.0-SNAPSHOT jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From 9140c8a062965e27ed61b710f44253873dd0c69d Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 21 Nov 2014 17:59:39 +0100 Subject: [PATCH 691/701] amend #763 --- src/main/java/com/ning/http/client/Request.java | 5 +++++ .../com/ning/http/client/RequestBuilderBase.java | 15 +++++++++++++++ .../netty/request/NettyRequestFactory.java | 4 ++++ 3 files changed, 24 insertions(+) diff --git a/src/main/java/com/ning/http/client/Request.java b/src/main/java/com/ning/http/client/Request.java index 31952de494..7f10796da2 100644 --- a/src/main/java/com/ning/http/client/Request.java +++ b/src/main/java/com/ning/http/client/Request.java @@ -79,6 +79,11 @@ public interface Request { */ byte[] getByteData(); + /** + * @return the current request's body as a composite of byte arrays + */ + List getCompositeByteData(); + /** * Return the current request's body as a string * diff --git a/src/main/java/com/ning/http/client/RequestBuilderBase.java b/src/main/java/com/ning/http/client/RequestBuilderBase.java index 74c95cb544..878b0513b6 100644 --- a/src/main/java/com/ning/http/client/RequestBuilderBase.java +++ b/src/main/java/com/ning/http/client/RequestBuilderBase.java @@ -53,6 +53,7 @@ private static final class RequestImpl implements Request { private FluentCaseInsensitiveStringsMap headers = new FluentCaseInsensitiveStringsMap(); private ArrayList cookies; private byte[] byteData; + private List compositeByteData; private String stringData; private InputStream streamData; private BodyGenerator bodyGenerator; @@ -82,6 +83,7 @@ public RequestImpl(Request prototype) { this.headers = new FluentCaseInsensitiveStringsMap(prototype.getHeaders()); this.cookies = new ArrayList(prototype.getCookies()); this.byteData = prototype.getByteData(); + this.compositeByteData = prototype.getCompositeByteData(); this.stringData = prototype.getStringData(); this.streamData = prototype.getStreamData(); this.bodyGenerator = prototype.getBodyGenerator(); @@ -132,6 +134,10 @@ public byte[] getByteData() { return byteData; } + public List getCompositeByteData() { + return compositeByteData; + } + public String getStringData() { return stringData; } @@ -372,6 +378,7 @@ public void resetFormParams() { public void resetNonMultipartData() { request.byteData = null; + request.compositeByteData = null; request.stringData = null; request.streamData = null; request.bodyGenerator = null; @@ -395,6 +402,14 @@ public T setBody(byte[] data) { return derived.cast(this); } + public T setBody(List data) { + resetFormParams(); + resetNonMultipartData(); + resetMultipartData(); + request.compositeByteData = data; + return derived.cast(this); + } + public T setBody(String data) { resetFormParams(); resetNonMultipartData(); diff --git a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestFactory.java b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestFactory.java index 9529d91ab4..a17f7dc73d 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestFactory.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestFactory.java @@ -46,6 +46,7 @@ import com.ning.http.client.providers.netty.request.body.NettyBody; import com.ning.http.client.providers.netty.request.body.NettyBodyBody; import com.ning.http.client.providers.netty.request.body.NettyByteArrayBody; +import com.ning.http.client.providers.netty.request.body.NettyCompositeByteArrayBody; import com.ning.http.client.providers.netty.request.body.NettyDirectBody; import com.ning.http.client.providers.netty.request.body.NettyFileBody; import com.ning.http.client.providers.netty.request.body.NettyInputStreamBody; @@ -207,6 +208,9 @@ private NettyBody body(Request request, HttpMethod method) throws IOException { if (request.getByteData() != null) nettyBody = new NettyByteArrayBody(request.getByteData()); + else if (request.getCompositeByteData() != null) + nettyBody = new NettyCompositeByteArrayBody(request.getCompositeByteData()); + else if (request.getStringData() != null) nettyBody = new NettyByteArrayBody(request.getStringData().getBytes(bodyCharset)); From 2cd9178ad09f9b89d8d0eb357037b647acdf3412 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 21 Nov 2014 18:01:09 +0100 Subject: [PATCH 692/701] [maven-release-plugin] prepare release async-http-client-1.9.0-BETA23 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index f0706098c7..e0860c432e 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.9.0-SNAPSHOT + 1.9.0-BETA23 jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From 551142a4f784f9b19ee8e7dfcfe31d2d88f7f524 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 21 Nov 2014 18:01:14 +0100 Subject: [PATCH 693/701] [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 e0860c432e..f0706098c7 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.9.0-BETA23 + 1.9.0-SNAPSHOT jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From b4e955860d1502040f26699bc062ec7f94c14c7e Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 25 Nov 2014 14:10:17 +0100 Subject: [PATCH 694/701] Minor clean up --- .../netty/request/NettyRequestSender.java | 18 +++++------------- .../netty/request/ProgressListener.java | 6 +----- 2 files changed, 6 insertions(+), 18 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java index c176f20414..50c74fe125 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java @@ -323,18 +323,9 @@ public void writeRequest(NettyResponseFuture future, Channel channel) { if (handler instanceof TransferCompletionHandler) configureTransferAdapter(handler, httpRequest); - if (!future.isHeadersAlreadyWrittenOnContinue()) { - try { - if (future.getAsyncHandler() instanceof AsyncHandlerExtensions) - AsyncHandlerExtensions.class.cast(future.getAsyncHandler()).onSendRequest(nettyRequest); - channel.write(httpRequest).addListener(new ProgressListener(config, future.getAsyncHandler(), future, true)); - } catch (Throwable cause) { - // FIXME why not notify? - LOGGER.debug(cause.getMessage(), cause); - // FIXME what about the attribute? how could this fail? - Channels.silentlyCloseChannel(channel); - return; - } + if (!future.isHeadersAlreadyWrittenOnContinue() &&future.getAsyncHandler() instanceof AsyncHandlerExtensions) { + AsyncHandlerExtensions.class.cast(future.getAsyncHandler()).onSendRequest(nettyRequest); + channel.write(httpRequest).addListener(new ProgressListener(config, future.getAsyncHandler(), future, true)); } // FIXME what happens to this second write if the first one failed? Should it be done in the ProgressListener? @@ -346,7 +337,8 @@ public void writeRequest(NettyResponseFuture future, Channel channel) { if (Channels.isChannelValid(channel)) scheduleTimeouts(future); - } catch (Throwable ioe) { + } catch (Throwable t) { + LOGGER.error("Can't write request", t); Channels.silentlyCloseChannel(channel); } } diff --git a/src/main/java/com/ning/http/client/providers/netty/request/ProgressListener.java b/src/main/java/com/ning/http/client/providers/netty/request/ProgressListener.java index 6cdec4c060..c6604655ac 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/ProgressListener.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/ProgressListener.java @@ -52,11 +52,7 @@ private boolean abortOnThrowable(Throwable cause, Channel channel) { if (cause != null && future.getState() != NettyResponseFuture.STATE.NEW) { // The write operation failed. If the channel was cached, it means it got asynchronously closed. // Let's retry a second time. - if (cause instanceof IllegalStateException) { - LOGGER.debug(cause.getMessage(), cause); - Channels.silentlyCloseChannel(channel); - - } else if (cause instanceof ClosedChannelException || StackTraceInspector.abortOnReadOrWriteException(cause)) { + if (cause instanceof IllegalStateException || cause instanceof ClosedChannelException || StackTraceInspector.abortOnReadOrWriteException(cause)) { LOGGER.debug(cause == null ? "" : cause.getMessage(), cause); Channels.silentlyCloseChannel(channel); From afd3068b7386046ca77a54938dbad33a935c14f8 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Tue, 25 Nov 2014 14:13:35 +0100 Subject: [PATCH 695/701] Fix previous commit --- .../client/providers/netty/request/NettyRequestSender.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java index 50c74fe125..3a92909990 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java @@ -323,8 +323,9 @@ public void writeRequest(NettyResponseFuture future, Channel channel) { if (handler instanceof TransferCompletionHandler) configureTransferAdapter(handler, httpRequest); - if (!future.isHeadersAlreadyWrittenOnContinue() &&future.getAsyncHandler() instanceof AsyncHandlerExtensions) { - AsyncHandlerExtensions.class.cast(future.getAsyncHandler()).onSendRequest(nettyRequest); + if (!future.isHeadersAlreadyWrittenOnContinue()) { + if (future.getAsyncHandler() instanceof AsyncHandlerExtensions) + AsyncHandlerExtensions.class.cast(future.getAsyncHandler()).onSendRequest(nettyRequest); channel.write(httpRequest).addListener(new ProgressListener(config, future.getAsyncHandler(), future, true)); } From 104865d83dd33d29969588dbbdca757554aeb999 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 28 Nov 2014 13:39:37 +0100 Subject: [PATCH 696/701] Possible event loss when pooled connection is closed before writing, close #768 --- .../providers/netty/handler/Processor.java | 8 +-- .../netty/request/NettyRequestSender.java | 54 ++++++++++++------- 2 files changed, 36 insertions(+), 26 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/handler/Processor.java b/src/main/java/com/ning/http/client/providers/netty/handler/Processor.java index ff02910d6f..78df51a895 100644 --- a/src/main/java/com/ning/http/client/providers/netty/handler/Processor.java +++ b/src/main/java/com/ning/http/client/providers/netty/handler/Processor.java @@ -32,7 +32,6 @@ import com.ning.http.client.providers.netty.future.NettyResponseFuture; import com.ning.http.client.providers.netty.future.StackTraceInspector; import com.ning.http.client.providers.netty.request.NettyRequestSender; -import com.ning.http.util.AsyncHttpProviderUtils; import java.io.IOException; import java.nio.channels.ClosedChannelException; @@ -128,12 +127,7 @@ public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws return; protocol.onClose(future); - - if (future.isDone()) - channelManager.closeChannel(channel); - - else if (!requestSender.retry(future)) - requestSender.abort(channel, future, AsyncHttpProviderUtils.REMOTELY_CLOSED_EXCEPTION); + requestSender.handleUnexpectedClosedChannel(channel, future); } } diff --git a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java index 3a92909990..e6f71415b4 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java @@ -17,6 +17,7 @@ import static com.ning.http.client.providers.netty.util.HttpUtils.useProxyConnect; import static com.ning.http.util.AsyncHttpProviderUtils.getDefaultPort; import static com.ning.http.util.AsyncHttpProviderUtils.requestTimeout; +import static com.ning.http.util.AsyncHttpProviderUtils.REMOTELY_CLOSED_EXCEPTION; import static com.ning.http.util.ProxyUtils.avoidProxy; import static com.ning.http.util.ProxyUtils.getProxyServer; @@ -207,28 +208,35 @@ private ListenableFuture sendRequestWithCachedChannel(Request request, Ur future.attachChannel(channel, false); LOGGER.debug("Using cached Channel {}\n for request \n{}\n", channel, future.getNettyRequest().getHttpRequest()); - Channels.setAttribute(channel, future); - try { - writeRequest(future, channel); - } catch (Exception ex) { - // write request isn't supposed to throw Exceptions - LOGGER.debug("writeRequest failure", ex); - if (ex.getMessage() != null && ex.getMessage().contains("SSLEngine")) { - // FIXME what is this for? https://github.com/AsyncHttpClient/async-http-client/commit/a847c3d4523ccc09827743e15b17e6bab59c553b - // can such an exception happen as we write async? - LOGGER.debug("SSLEngine failure", ex); - future = null; - } else { - try { - asyncHandler.onThrowable(ex); - } catch (Throwable t) { - LOGGER.warn("doConnect.writeRequest()", t); + if (Channels.isChannelValid(channel)) { + Channels.setAttribute(channel, future); + + try { + writeRequest(future, channel); + } catch (Exception ex) { + // write request isn't supposed to throw Exceptions + LOGGER.debug("writeRequest failure", ex); + if (ex.getMessage() != null && ex.getMessage().contains("SSLEngine")) { + // FIXME what is this for? https://github.com/AsyncHttpClient/async-http-client/commit/a847c3d4523ccc09827743e15b17e6bab59c553b + // can such an exception happen as we write async? + LOGGER.debug("SSLEngine failure", ex); + future = null; + } else { + try { + asyncHandler.onThrowable(ex); + } catch (Throwable t) { + LOGGER.warn("doConnect.writeRequest()", t); + } + IOException ioe = new IOException(ex.getMessage()); + ioe.initCause(ex); + throw ioe; } - IOException ioe = new IOException(ex.getMessage()); - ioe.initCause(ex); - throw ioe; } + } else { + // bad luck, the channel was closed in-between + // there's a very good chance onClose was already notified but the future wasn't already registered + handleUnexpectedClosedChannel(channel, future); } return future; } @@ -413,6 +421,14 @@ public void abort(Channel channel, NettyResponseFuture future, Throwable t) { } } + public void handleUnexpectedClosedChannel(Channel channel, NettyResponseFuture future) { + if (future.isDone()) + channelManager.closeChannel(channel); + + else if (!retry(future)) + abort(channel, future, REMOTELY_CLOSED_EXCEPTION); + } + public boolean retry(NettyResponseFuture future) { if (isClosed()) From a8a8faaa7e18716ffb09c92b3d54ccaf37edd1be Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 28 Nov 2014 13:41:05 +0100 Subject: [PATCH 697/701] Notify Handshake failures, close #767 --- .../client/providers/netty/request/NettyConnectListener.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/ning/http/client/providers/netty/request/NettyConnectListener.java b/src/main/java/com/ning/http/client/providers/netty/request/NettyConnectListener.java index 50547de2c4..16d9a13d8a 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/NettyConnectListener.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/NettyConnectListener.java @@ -115,9 +115,10 @@ public void operationComplete(ChannelFuture handshakeFuture) throws Exception { writeRequest(channel, poolKey); } else { - abortChannelPreemption(poolKey); - future.abort(new ConnectException("HostnameVerifier exception")); + onFutureFailure(channel, new ConnectException("HostnameVerifier exception")); } + } else { + onFutureFailure(channel, handshakeFuture.getCause()); } } }); From a06476425e4a5f641a03a744cb7bd9d455fc5e2f Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 28 Nov 2014 13:43:10 +0100 Subject: [PATCH 698/701] [maven-release-plugin] prepare release async-http-client-1.9.0-BETA24 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index f0706098c7..f1ce2a930b 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.9.0-SNAPSHOT + 1.9.0-BETA24 jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From f2f5c8d3803107626d82605c192fad77a127088c Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Fri, 28 Nov 2014 13:43:14 +0100 Subject: [PATCH 699/701] [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 f1ce2a930b..f0706098c7 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.9.0-BETA24 + 1.9.0-SNAPSHOT jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and From a6e2fec796b27af541d2f509fbdca51f0926ec82 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 1 Dec 2014 11:03:42 +0100 Subject: [PATCH 700/701] Change web socket package into ws --- .../http/client/AsyncHttpClientConfig.java | 8 ++-- .../com/ning/http/client/UpgradeHandler.java | 2 +- .../grizzly/GrizzlyAsyncHttpProvider.java | 16 +++---- .../netty/handler/WebSocketProtocol.java | 2 +- .../netty/request/NettyRequestSender.java | 2 +- .../providers/netty/ws/NettyWebSocket.java | 18 ++++---- .../DefaultWebSocketListener.java | 2 +- .../client/{websocket => ws}/WebSocket.java | 2 +- .../WebSocketByteFragmentListener.java | 2 +- .../WebSocketByteListener.java | 2 +- .../WebSocketCloseCodeReasonListener.java | 2 +- .../{websocket => ws}/WebSocketListener.java | 2 +- .../WebSocketPingListener.java | 2 +- .../WebSocketPongListener.java | 2 +- .../WebSocketTextFragmentListener.java | 2 +- .../WebSocketTextListener.java | 2 +- .../WebSocketUpgradeHandler.java | 2 +- .../{websocket => ws}/AbstractBasicTest.java | 2 +- .../{websocket => ws}/ByteMessageTest.java | 5 ++- .../CloseCodeReasonMessageTest.java | 20 ++++++--- .../ProxyTunnellingTest.java | 7 ++- .../{websocket => ws}/RedirectTest.java | 9 ++-- .../{websocket => ws}/TextMessageTest.java | 44 +++++++++++-------- .../grizzly/GrizzlyByteMessageTest.java | 4 +- .../GrizzlyCloseCodeReasonMsgTest.java | 4 +- .../grizzly/GrizzlyProxyTunnellingTest.java | 4 +- .../grizzly/GrizzlyRedirectTest.java | 4 +- .../grizzly/GrizzlyTextMessageTest.java | 4 +- .../netty/NettyByteMessageTest.java | 4 +- .../netty/NettyCloseCodeReasonMsgTest.java | 4 +- .../netty/NettyProxyTunnellingTest.java | 4 +- .../netty/NettyRedirectTest.java | 4 +- .../netty/NettyTextMessageTest.java | 4 +- 33 files changed, 109 insertions(+), 88 deletions(-) rename src/main/java/com/ning/http/client/{websocket => ws}/DefaultWebSocketListener.java (98%) rename src/main/java/com/ning/http/client/{websocket => ws}/WebSocket.java (98%) rename src/main/java/com/ning/http/client/{websocket => ws}/WebSocketByteFragmentListener.java (96%) rename src/main/java/com/ning/http/client/{websocket => ws}/WebSocketByteListener.java (95%) rename src/main/java/com/ning/http/client/{websocket => ws}/WebSocketCloseCodeReasonListener.java (96%) rename src/main/java/com/ning/http/client/{websocket => ws}/WebSocketListener.java (96%) rename src/main/java/com/ning/http/client/{websocket => ws}/WebSocketPingListener.java (95%) rename src/main/java/com/ning/http/client/{websocket => ws}/WebSocketPongListener.java (95%) rename src/main/java/com/ning/http/client/{websocket => ws}/WebSocketTextFragmentListener.java (96%) rename src/main/java/com/ning/http/client/{websocket => ws}/WebSocketTextListener.java (96%) rename src/main/java/com/ning/http/client/{websocket => ws}/WebSocketUpgradeHandler.java (99%) rename src/test/java/com/ning/http/client/{websocket => ws}/AbstractBasicTest.java (98%) rename src/test/java/com/ning/http/client/{websocket => ws}/ByteMessageTest.java (97%) rename src/test/java/com/ning/http/client/{websocket => ws}/CloseCodeReasonMessageTest.java (88%) rename src/test/java/com/ning/http/client/{websocket => ws}/ProxyTunnellingTest.java (95%) rename src/test/java/com/ning/http/client/{websocket => ws}/RedirectTest.java (92%) rename src/test/java/com/ning/http/client/{websocket => ws}/TextMessageTest.java (88%) rename src/test/java/com/ning/http/client/{websocket => ws}/grizzly/GrizzlyByteMessageTest.java (92%) rename src/test/java/com/ning/http/client/{websocket => ws}/grizzly/GrizzlyCloseCodeReasonMsgTest.java (91%) rename src/test/java/com/ning/http/client/{websocket => ws}/grizzly/GrizzlyProxyTunnellingTest.java (91%) rename src/test/java/com/ning/http/client/{websocket => ws}/grizzly/GrizzlyRedirectTest.java (91%) rename src/test/java/com/ning/http/client/{websocket => ws}/grizzly/GrizzlyTextMessageTest.java (92%) rename src/test/java/com/ning/http/client/{websocket => ws}/netty/NettyByteMessageTest.java (91%) rename src/test/java/com/ning/http/client/{websocket => ws}/netty/NettyCloseCodeReasonMsgTest.java (90%) rename src/test/java/com/ning/http/client/{websocket => ws}/netty/NettyProxyTunnellingTest.java (91%) rename src/test/java/com/ning/http/client/{websocket => ws}/netty/NettyRedirectTest.java (91%) rename src/test/java/com/ning/http/client/{websocket => ws}/netty/NettyTextMessageTest.java (91%) diff --git a/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java b/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java index dc6c37a67d..72cf8e2ffa 100644 --- a/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java +++ b/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java @@ -183,8 +183,8 @@ public int getConnectTimeout() { } /** - * Return the maximum time, in milliseconds, a {@link com.ning.http.client.websocket.WebSocket} may be idle before being timed out. - * @return the maximum time, in milliseconds, a {@link com.ning.http.client.websocket.WebSocket} may be idle before being timed out. + * Return the maximum time, in milliseconds, a {@link com.ning.http.client.ws.WebSocket} may be idle before being timed out. + * @return the maximum time, in milliseconds, a {@link com.ning.http.client.ws.WebSocket} may be idle before being timed out. */ public int getWebSocketTimeout() { return webSocketTimeout; @@ -546,10 +546,10 @@ public Builder setConnectTimeout(int connectTimeOut) { } /** - * Set the maximum time in millisecond an {@link com.ning.http.client.websocket.WebSocket} can stay idle. + * Set the maximum time in millisecond an {@link com.ning.http.client.ws.WebSocket} can stay idle. * * @param webSocketTimeout - * the maximum time in millisecond an {@link com.ning.http.client.websocket.WebSocket} can stay idle. + * the maximum time in millisecond an {@link com.ning.http.client.ws.WebSocket} can stay idle. * @return a {@link Builder} */ public Builder setWebSocketTimeout(int webSocketTimeout) { diff --git a/src/main/java/com/ning/http/client/UpgradeHandler.java b/src/main/java/com/ning/http/client/UpgradeHandler.java index 3eee98659c..7b53f5b33c 100644 --- a/src/main/java/com/ning/http/client/UpgradeHandler.java +++ b/src/main/java/com/ning/http/client/UpgradeHandler.java @@ -13,7 +13,7 @@ package com.ning.http.client; /** - * Invoked when an {@link AsyncHandler.STATE#UPGRADE} is returned. Currently the library only support {@link com.ning.http.client.websocket.WebSocket} + * Invoked when an {@link AsyncHandler.STATE#UPGRADE} is returned. Currently the library only support {@link com.ning.http.client.ws.WebSocket} * as type. * * @param 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 28666fad1d..7f60f7923d 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 @@ -107,14 +107,14 @@ import com.ning.http.client.multipart.Part; import com.ning.http.client.ntlm.NTLMEngine; import com.ning.http.client.uri.Uri; -import com.ning.http.client.websocket.WebSocket; -import com.ning.http.client.websocket.WebSocketByteListener; -import com.ning.http.client.websocket.WebSocketCloseCodeReasonListener; -import com.ning.http.client.websocket.WebSocketListener; -import com.ning.http.client.websocket.WebSocketPingListener; -import com.ning.http.client.websocket.WebSocketPongListener; -import com.ning.http.client.websocket.WebSocketTextListener; -import com.ning.http.client.websocket.WebSocketUpgradeHandler; +import com.ning.http.client.ws.WebSocket; +import com.ning.http.client.ws.WebSocketByteListener; +import com.ning.http.client.ws.WebSocketCloseCodeReasonListener; +import com.ning.http.client.ws.WebSocketListener; +import com.ning.http.client.ws.WebSocketPingListener; +import com.ning.http.client.ws.WebSocketPongListener; +import com.ning.http.client.ws.WebSocketTextListener; +import com.ning.http.client.ws.WebSocketUpgradeHandler; import com.ning.http.util.AsyncHttpProviderUtils; import com.ning.http.util.AuthenticatorUtils; import com.ning.http.util.ProxyUtils; diff --git a/src/main/java/com/ning/http/client/providers/netty/handler/WebSocketProtocol.java b/src/main/java/com/ning/http/client/providers/netty/handler/WebSocketProtocol.java index 6aba8a24c5..4b999767e3 100644 --- a/src/main/java/com/ning/http/client/providers/netty/handler/WebSocketProtocol.java +++ b/src/main/java/com/ning/http/client/providers/netty/handler/WebSocketProtocol.java @@ -42,7 +42,7 @@ import com.ning.http.client.providers.netty.response.NettyResponseHeaders; import com.ning.http.client.providers.netty.response.NettyResponseStatus; import com.ning.http.client.providers.netty.ws.NettyWebSocket; -import com.ning.http.client.websocket.WebSocketUpgradeHandler; +import com.ning.http.client.ws.WebSocketUpgradeHandler; import java.io.IOException; import java.util.Locale; diff --git a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java index e6f71415b4..183e76a3e4 100644 --- a/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java +++ b/src/main/java/com/ning/http/client/providers/netty/request/NettyRequestSender.java @@ -54,7 +54,7 @@ import com.ning.http.client.providers.netty.request.timeout.RequestTimeoutTimerTask; import com.ning.http.client.providers.netty.request.timeout.TimeoutsHolder; import com.ning.http.client.uri.Uri; -import com.ning.http.client.websocket.WebSocketUpgradeHandler; +import com.ning.http.client.ws.WebSocketUpgradeHandler; import java.io.IOException; import java.net.InetSocketAddress; diff --git a/src/main/java/com/ning/http/client/providers/netty/ws/NettyWebSocket.java b/src/main/java/com/ning/http/client/providers/netty/ws/NettyWebSocket.java index e5f27bcf7d..f6953ba85c 100644 --- a/src/main/java/com/ning/http/client/providers/netty/ws/NettyWebSocket.java +++ b/src/main/java/com/ning/http/client/providers/netty/ws/NettyWebSocket.java @@ -31,15 +31,15 @@ import com.ning.http.client.HttpResponseBodyPart; import com.ning.http.client.providers.netty.NettyAsyncHttpProviderConfig; import com.ning.http.client.providers.netty.response.NettyResponseBodyPart; -import com.ning.http.client.websocket.WebSocket; -import com.ning.http.client.websocket.WebSocketByteFragmentListener; -import com.ning.http.client.websocket.WebSocketByteListener; -import com.ning.http.client.websocket.WebSocketCloseCodeReasonListener; -import com.ning.http.client.websocket.WebSocketListener; -import com.ning.http.client.websocket.WebSocketPingListener; -import com.ning.http.client.websocket.WebSocketPongListener; -import com.ning.http.client.websocket.WebSocketTextFragmentListener; -import com.ning.http.client.websocket.WebSocketTextListener; +import com.ning.http.client.ws.WebSocket; +import com.ning.http.client.ws.WebSocketByteFragmentListener; +import com.ning.http.client.ws.WebSocketByteListener; +import com.ning.http.client.ws.WebSocketCloseCodeReasonListener; +import com.ning.http.client.ws.WebSocketListener; +import com.ning.http.client.ws.WebSocketPingListener; +import com.ning.http.client.ws.WebSocketPongListener; +import com.ning.http.client.ws.WebSocketTextFragmentListener; +import com.ning.http.client.ws.WebSocketTextListener; import java.util.ArrayList; import java.util.Collection; diff --git a/src/main/java/com/ning/http/client/websocket/DefaultWebSocketListener.java b/src/main/java/com/ning/http/client/ws/DefaultWebSocketListener.java similarity index 98% rename from src/main/java/com/ning/http/client/websocket/DefaultWebSocketListener.java rename to src/main/java/com/ning/http/client/ws/DefaultWebSocketListener.java index 6ed9a3d2f1..c2ab5b762c 100644 --- a/src/main/java/com/ning/http/client/websocket/DefaultWebSocketListener.java +++ b/src/main/java/com/ning/http/client/ws/DefaultWebSocketListener.java @@ -11,7 +11,7 @@ * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under. */ -package com.ning.http.client.websocket; +package com.ning.http.client.ws; /** * Default WebSocketListener implementation. Most methods are no-ops. This diff --git a/src/main/java/com/ning/http/client/websocket/WebSocket.java b/src/main/java/com/ning/http/client/ws/WebSocket.java similarity index 98% rename from src/main/java/com/ning/http/client/websocket/WebSocket.java rename to src/main/java/com/ning/http/client/ws/WebSocket.java index c9c8390fab..7c35fe0267 100644 --- a/src/main/java/com/ning/http/client/websocket/WebSocket.java +++ b/src/main/java/com/ning/http/client/ws/WebSocket.java @@ -10,7 +10,7 @@ * "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; +package com.ning.http.client.ws; import java.io.Closeable; diff --git a/src/main/java/com/ning/http/client/websocket/WebSocketByteFragmentListener.java b/src/main/java/com/ning/http/client/ws/WebSocketByteFragmentListener.java similarity index 96% rename from src/main/java/com/ning/http/client/websocket/WebSocketByteFragmentListener.java rename to src/main/java/com/ning/http/client/ws/WebSocketByteFragmentListener.java index 463094f77a..f7127ae8f6 100644 --- a/src/main/java/com/ning/http/client/websocket/WebSocketByteFragmentListener.java +++ b/src/main/java/com/ning/http/client/ws/WebSocketByteFragmentListener.java @@ -11,7 +11,7 @@ * "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; +package com.ning.http.client.ws; import com.ning.http.client.HttpResponseBodyPart; diff --git a/src/main/java/com/ning/http/client/websocket/WebSocketByteListener.java b/src/main/java/com/ning/http/client/ws/WebSocketByteListener.java similarity index 95% rename from src/main/java/com/ning/http/client/websocket/WebSocketByteListener.java rename to src/main/java/com/ning/http/client/ws/WebSocketByteListener.java index a0cf74a368..1958be6756 100644 --- a/src/main/java/com/ning/http/client/websocket/WebSocketByteListener.java +++ b/src/main/java/com/ning/http/client/ws/WebSocketByteListener.java @@ -10,7 +10,7 @@ * "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; +package com.ning.http.client.ws; /** * A {@link WebSocketListener} for bytes diff --git a/src/main/java/com/ning/http/client/websocket/WebSocketCloseCodeReasonListener.java b/src/main/java/com/ning/http/client/ws/WebSocketCloseCodeReasonListener.java similarity index 96% rename from src/main/java/com/ning/http/client/websocket/WebSocketCloseCodeReasonListener.java rename to src/main/java/com/ning/http/client/ws/WebSocketCloseCodeReasonListener.java index af524527b7..73589ea5f4 100644 --- a/src/main/java/com/ning/http/client/websocket/WebSocketCloseCodeReasonListener.java +++ b/src/main/java/com/ning/http/client/ws/WebSocketCloseCodeReasonListener.java @@ -10,7 +10,7 @@ * "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; +package com.ning.http.client.ws; /** * Extend the normal close listener with one that support the WebSocket's code and reason. diff --git a/src/main/java/com/ning/http/client/websocket/WebSocketListener.java b/src/main/java/com/ning/http/client/ws/WebSocketListener.java similarity index 96% rename from src/main/java/com/ning/http/client/websocket/WebSocketListener.java rename to src/main/java/com/ning/http/client/ws/WebSocketListener.java index 83da93ebbd..9d70c607bb 100644 --- a/src/main/java/com/ning/http/client/websocket/WebSocketListener.java +++ b/src/main/java/com/ning/http/client/ws/WebSocketListener.java @@ -10,7 +10,7 @@ * "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; +package com.ning.http.client.ws; /** * A generic {@link WebSocketListener} for WebSocket events. Use the appropriate listener for receiving message bytes. diff --git a/src/main/java/com/ning/http/client/websocket/WebSocketPingListener.java b/src/main/java/com/ning/http/client/ws/WebSocketPingListener.java similarity index 95% rename from src/main/java/com/ning/http/client/websocket/WebSocketPingListener.java rename to src/main/java/com/ning/http/client/ws/WebSocketPingListener.java index f2a7d69ee6..7a820ca0b1 100644 --- a/src/main/java/com/ning/http/client/websocket/WebSocketPingListener.java +++ b/src/main/java/com/ning/http/client/ws/WebSocketPingListener.java @@ -10,7 +10,7 @@ * "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; +package com.ning.http.client.ws; /** * A WebSocket's Ping Listener diff --git a/src/main/java/com/ning/http/client/websocket/WebSocketPongListener.java b/src/main/java/com/ning/http/client/ws/WebSocketPongListener.java similarity index 95% rename from src/main/java/com/ning/http/client/websocket/WebSocketPongListener.java rename to src/main/java/com/ning/http/client/ws/WebSocketPongListener.java index 44e4548888..00d0bfbbb9 100644 --- a/src/main/java/com/ning/http/client/websocket/WebSocketPongListener.java +++ b/src/main/java/com/ning/http/client/ws/WebSocketPongListener.java @@ -10,7 +10,7 @@ * "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; +package com.ning.http.client.ws; /** * A WebSocket's Pong Listener diff --git a/src/main/java/com/ning/http/client/websocket/WebSocketTextFragmentListener.java b/src/main/java/com/ning/http/client/ws/WebSocketTextFragmentListener.java similarity index 96% rename from src/main/java/com/ning/http/client/websocket/WebSocketTextFragmentListener.java rename to src/main/java/com/ning/http/client/ws/WebSocketTextFragmentListener.java index bcc26b74ef..421512c8da 100644 --- a/src/main/java/com/ning/http/client/websocket/WebSocketTextFragmentListener.java +++ b/src/main/java/com/ning/http/client/ws/WebSocketTextFragmentListener.java @@ -11,7 +11,7 @@ * "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; +package com.ning.http.client.ws; import com.ning.http.client.HttpResponseBodyPart; diff --git a/src/main/java/com/ning/http/client/websocket/WebSocketTextListener.java b/src/main/java/com/ning/http/client/ws/WebSocketTextListener.java similarity index 96% rename from src/main/java/com/ning/http/client/websocket/WebSocketTextListener.java rename to src/main/java/com/ning/http/client/ws/WebSocketTextListener.java index b3c46678a4..db5861c022 100644 --- a/src/main/java/com/ning/http/client/websocket/WebSocketTextListener.java +++ b/src/main/java/com/ning/http/client/ws/WebSocketTextListener.java @@ -10,7 +10,7 @@ * "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; +package com.ning.http.client.ws; /** * A {@link WebSocketListener} for text message diff --git a/src/main/java/com/ning/http/client/websocket/WebSocketUpgradeHandler.java b/src/main/java/com/ning/http/client/ws/WebSocketUpgradeHandler.java similarity index 99% rename from src/main/java/com/ning/http/client/websocket/WebSocketUpgradeHandler.java rename to src/main/java/com/ning/http/client/ws/WebSocketUpgradeHandler.java index 2954dc9f76..d956a80c32 100644 --- a/src/main/java/com/ning/http/client/websocket/WebSocketUpgradeHandler.java +++ b/src/main/java/com/ning/http/client/ws/WebSocketUpgradeHandler.java @@ -10,7 +10,7 @@ * "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; +package com.ning.http.client.ws; import com.ning.http.client.AsyncHandler; import com.ning.http.client.HttpResponseBodyPart; diff --git a/src/test/java/com/ning/http/client/websocket/AbstractBasicTest.java b/src/test/java/com/ning/http/client/ws/AbstractBasicTest.java similarity index 98% rename from src/test/java/com/ning/http/client/websocket/AbstractBasicTest.java rename to src/test/java/com/ning/http/client/ws/AbstractBasicTest.java index a3bf5a6382..00b97dcc68 100644 --- a/src/test/java/com/ning/http/client/websocket/AbstractBasicTest.java +++ b/src/test/java/com/ning/http/client/ws/AbstractBasicTest.java @@ -10,7 +10,7 @@ * "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; +package com.ning.http.client.ws; import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClientConfig; diff --git a/src/test/java/com/ning/http/client/websocket/ByteMessageTest.java b/src/test/java/com/ning/http/client/ws/ByteMessageTest.java similarity index 97% rename from src/test/java/com/ning/http/client/websocket/ByteMessageTest.java rename to src/test/java/com/ning/http/client/ws/ByteMessageTest.java index 71b590b02b..e7f7d3927b 100644 --- a/src/test/java/com/ning/http/client/websocket/ByteMessageTest.java +++ b/src/test/java/com/ning/http/client/ws/ByteMessageTest.java @@ -10,13 +10,16 @@ * "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; +package com.ning.http.client.ws; import static org.testng.Assert.assertEquals; import org.testng.annotations.Test; import com.ning.http.client.AsyncHttpClient; +import com.ning.http.client.ws.WebSocket; +import com.ning.http.client.ws.WebSocketByteListener; +import com.ning.http.client.ws.WebSocketUpgradeHandler; import javax.servlet.http.HttpServletRequest; diff --git a/src/test/java/com/ning/http/client/websocket/CloseCodeReasonMessageTest.java b/src/test/java/com/ning/http/client/ws/CloseCodeReasonMessageTest.java similarity index 88% rename from src/test/java/com/ning/http/client/websocket/CloseCodeReasonMessageTest.java rename to src/test/java/com/ning/http/client/ws/CloseCodeReasonMessageTest.java index a2c9b0f634..5ca529788a 100644 --- a/src/test/java/com/ning/http/client/websocket/CloseCodeReasonMessageTest.java +++ b/src/test/java/com/ning/http/client/ws/CloseCodeReasonMessageTest.java @@ -10,9 +10,15 @@ * "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; +package com.ning.http.client.ws; import com.ning.http.client.AsyncHttpClient; +import com.ning.http.client.ws.WebSocket; +import com.ning.http.client.ws.WebSocketCloseCodeReasonListener; +import com.ning.http.client.ws.WebSocketListener; +import com.ning.http.client.ws.WebSocketTextListener; +import com.ning.http.client.ws.WebSocketUpgradeHandler; + import org.testng.annotations.Test; import java.util.concurrent.CountDownLatch; @@ -75,11 +81,11 @@ public Listener(CountDownLatch latch, AtomicReference text) { } @Override - public void onOpen(com.ning.http.client.websocket.WebSocket websocket) { + public void onOpen(com.ning.http.client.ws.WebSocket websocket) { } @Override - public void onClose(com.ning.http.client.websocket.WebSocket websocket) { + public void onClose(com.ning.http.client.ws.WebSocket websocket) { } public void onClose(WebSocket websocket, int code, String reason) { @@ -108,11 +114,11 @@ public void onMessage(String message) { } @Override - public void onOpen(com.ning.http.client.websocket.WebSocket websocket) { + public void onOpen(com.ning.http.client.ws.WebSocket websocket) { } @Override - public void onClose(com.ning.http.client.websocket.WebSocket websocket) { + public void onClose(com.ning.http.client.ws.WebSocket websocket) { } @Override @@ -144,11 +150,11 @@ public void onMessage(String message) { } @Override - public void onOpen(com.ning.http.client.websocket.WebSocket websocket) { + public void onOpen(com.ning.http.client.ws.WebSocket websocket) { } @Override - public void onClose(com.ning.http.client.websocket.WebSocket websocket) { + public void onClose(com.ning.http.client.ws.WebSocket websocket) { } @Override diff --git a/src/test/java/com/ning/http/client/websocket/ProxyTunnellingTest.java b/src/test/java/com/ning/http/client/ws/ProxyTunnellingTest.java similarity index 95% rename from src/test/java/com/ning/http/client/websocket/ProxyTunnellingTest.java rename to src/test/java/com/ning/http/client/ws/ProxyTunnellingTest.java index 6b69fe1acd..4f81fe9395 100644 --- a/src/test/java/com/ning/http/client/websocket/ProxyTunnellingTest.java +++ b/src/test/java/com/ning/http/client/ws/ProxyTunnellingTest.java @@ -10,7 +10,7 @@ * "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; +package com.ning.http.client.ws; import static org.testng.Assert.assertEquals; @@ -25,7 +25,10 @@ import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClientConfig; import com.ning.http.client.ProxyServer; -import com.ning.http.client.websocket.TextMessageTest.EchoTextWebSocket; +import com.ning.http.client.ws.WebSocket; +import com.ning.http.client.ws.WebSocketTextListener; +import com.ning.http.client.ws.WebSocketUpgradeHandler; +import com.ning.http.client.ws.TextMessageTest.EchoTextWebSocket; import javax.servlet.http.HttpServletRequest; diff --git a/src/test/java/com/ning/http/client/websocket/RedirectTest.java b/src/test/java/com/ning/http/client/ws/RedirectTest.java similarity index 92% rename from src/test/java/com/ning/http/client/websocket/RedirectTest.java rename to src/test/java/com/ning/http/client/ws/RedirectTest.java index 2117624cbf..abf986adf6 100644 --- a/src/test/java/com/ning/http/client/websocket/RedirectTest.java +++ b/src/test/java/com/ning/http/client/ws/RedirectTest.java @@ -11,7 +11,7 @@ * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under. */ -package com.ning.http.client.websocket; +package com.ning.http.client.ws; import static org.testng.Assert.assertEquals; @@ -32,6 +32,9 @@ import com.ning.http.client.AsyncHttpClient; import com.ning.http.client.AsyncHttpClientConfig; +import com.ning.http.client.ws.WebSocket; +import com.ning.http.client.ws.WebSocketListener; +import com.ning.http.client.ws.WebSocketUpgradeHandler; public abstract class RedirectTest extends AbstractBasicTest { @@ -92,13 +95,13 @@ public void testRedirectToWSResource() throws Exception { WebSocket websocket = client.prepareGet(getRedirectURL()).execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(new WebSocketListener() { @Override - public void onOpen(com.ning.http.client.websocket.WebSocket websocket) { + public void onOpen(com.ning.http.client.ws.WebSocket websocket) { text.set("OnOpen"); latch.countDown(); } @Override - public void onClose(com.ning.http.client.websocket.WebSocket websocket) { + public void onClose(com.ning.http.client.ws.WebSocket websocket) { } @Override diff --git a/src/test/java/com/ning/http/client/websocket/TextMessageTest.java b/src/test/java/com/ning/http/client/ws/TextMessageTest.java similarity index 88% rename from src/test/java/com/ning/http/client/websocket/TextMessageTest.java rename to src/test/java/com/ning/http/client/ws/TextMessageTest.java index c69731f246..ff89afe222 100644 --- a/src/test/java/com/ning/http/client/websocket/TextMessageTest.java +++ b/src/test/java/com/ning/http/client/ws/TextMessageTest.java @@ -10,12 +10,18 @@ * "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; +package com.ning.http.client.ws; import com.ning.http.client.AsyncHttpClient; +import com.ning.http.client.ws.WebSocket; +import com.ning.http.client.ws.WebSocketListener; +import com.ning.http.client.ws.WebSocketTextListener; +import com.ning.http.client.ws.WebSocketUpgradeHandler; + import org.testng.annotations.Test; import javax.servlet.http.HttpServletRequest; + import java.io.IOException; import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicReference; @@ -78,13 +84,13 @@ public void onOpen() throws Throwable { client.prepareGet(getTargetUrl()).execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(new WebSocketListener() { @Override - public void onOpen(com.ning.http.client.websocket.WebSocket websocket) { + public void onOpen(com.ning.http.client.ws.WebSocket websocket) { text.set("OnOpen"); latch.countDown(); } @Override - public void onClose(com.ning.http.client.websocket.WebSocket websocket) { + public void onClose(com.ning.http.client.ws.WebSocket websocket) { } @Override @@ -143,11 +149,11 @@ public void onTimeoutCloseTest() throws Throwable { client.prepareGet(getTargetUrl()).execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(new WebSocketListener() { @Override - public void onOpen(com.ning.http.client.websocket.WebSocket websocket) { + public void onOpen(com.ning.http.client.ws.WebSocket websocket) { } @Override - public void onClose(com.ning.http.client.websocket.WebSocket websocket) { + public void onClose(com.ning.http.client.ws.WebSocket websocket) { text.set("OnClose"); latch.countDown(); } @@ -176,11 +182,11 @@ public void onClose() throws Throwable { WebSocket websocket = client.prepareGet(getTargetUrl()).execute(new WebSocketUpgradeHandler.Builder().addWebSocketListener(new WebSocketListener() { @Override - public void onOpen(com.ning.http.client.websocket.WebSocket websocket) { + public void onOpen(com.ning.http.client.ws.WebSocket websocket) { } @Override - public void onClose(com.ning.http.client.websocket.WebSocket websocket) { + public void onClose(com.ning.http.client.ws.WebSocket websocket) { text.set("OnClose"); latch.countDown(); } @@ -217,11 +223,11 @@ public void onMessage(String message) { } @Override - public void onOpen(com.ning.http.client.websocket.WebSocket websocket) { + public void onOpen(com.ning.http.client.ws.WebSocket websocket) { } @Override - public void onClose(com.ning.http.client.websocket.WebSocket websocket) { + public void onClose(com.ning.http.client.ws.WebSocket websocket) { latch.countDown(); } @@ -257,11 +263,11 @@ public void onMessage(String message) { } @Override - public void onOpen(com.ning.http.client.websocket.WebSocket websocket) { + public void onOpen(com.ning.http.client.ws.WebSocket websocket) { } @Override - public void onClose(com.ning.http.client.websocket.WebSocket websocket) { + public void onClose(com.ning.http.client.ws.WebSocket websocket) { latch.countDown(); } @@ -279,11 +285,11 @@ public void onMessage(String message) { } @Override - public void onOpen(com.ning.http.client.websocket.WebSocket websocket) { + public void onOpen(com.ning.http.client.ws.WebSocket websocket) { } @Override - public void onClose(com.ning.http.client.websocket.WebSocket websocket) { + public void onClose(com.ning.http.client.ws.WebSocket websocket) { latch.countDown(); } @@ -319,12 +325,12 @@ public void onMessage(String message) { } @Override - public void onOpen(com.ning.http.client.websocket.WebSocket websocket) { + public void onOpen(com.ning.http.client.ws.WebSocket websocket) { websocket.sendMessage("ECHO").sendMessage("ECHO"); } @Override - public void onClose(com.ning.http.client.websocket.WebSocket websocket) { + public void onClose(com.ning.http.client.ws.WebSocket websocket) { latch.countDown(); } @@ -357,11 +363,11 @@ public void onMessage(String message) { } @Override - public void onOpen(com.ning.http.client.websocket.WebSocket websocket) { + public void onOpen(com.ning.http.client.ws.WebSocket websocket) { } @Override - public void onClose(com.ning.http.client.websocket.WebSocket websocket) { + public void onClose(com.ning.http.client.ws.WebSocket websocket) { latch.countDown(); } @@ -399,11 +405,11 @@ public void onMessage(String message) { } @Override - public void onOpen(com.ning.http.client.websocket.WebSocket websocket) { + public void onOpen(com.ning.http.client.ws.WebSocket websocket) { } @Override - public void onClose(com.ning.http.client.websocket.WebSocket websocket) { + public void onClose(com.ning.http.client.ws.WebSocket websocket) { closeLatch.countDown(); } diff --git a/src/test/java/com/ning/http/client/websocket/grizzly/GrizzlyByteMessageTest.java b/src/test/java/com/ning/http/client/ws/grizzly/GrizzlyByteMessageTest.java similarity index 92% rename from src/test/java/com/ning/http/client/websocket/grizzly/GrizzlyByteMessageTest.java rename to src/test/java/com/ning/http/client/ws/grizzly/GrizzlyByteMessageTest.java index 37b1429e3e..b5aa356307 100644 --- a/src/test/java/com/ning/http/client/websocket/grizzly/GrizzlyByteMessageTest.java +++ b/src/test/java/com/ning/http/client/ws/grizzly/GrizzlyByteMessageTest.java @@ -10,14 +10,14 @@ * "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.grizzly; +package com.ning.http.client.ws.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.websocket.ByteMessageTest; +import com.ning.http.client.ws.ByteMessageTest; public class GrizzlyByteMessageTest extends ByteMessageTest { @Override diff --git a/src/test/java/com/ning/http/client/websocket/grizzly/GrizzlyCloseCodeReasonMsgTest.java b/src/test/java/com/ning/http/client/ws/grizzly/GrizzlyCloseCodeReasonMsgTest.java similarity index 91% rename from src/test/java/com/ning/http/client/websocket/grizzly/GrizzlyCloseCodeReasonMsgTest.java rename to src/test/java/com/ning/http/client/ws/grizzly/GrizzlyCloseCodeReasonMsgTest.java index 941de2bfbc..101dcae0a5 100644 --- a/src/test/java/com/ning/http/client/websocket/grizzly/GrizzlyCloseCodeReasonMsgTest.java +++ b/src/test/java/com/ning/http/client/ws/grizzly/GrizzlyCloseCodeReasonMsgTest.java @@ -11,14 +11,14 @@ * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under. */ -package com.ning.http.client.websocket.grizzly; +package com.ning.http.client.ws.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.websocket.CloseCodeReasonMessageTest; +import com.ning.http.client.ws.CloseCodeReasonMessageTest; public class GrizzlyCloseCodeReasonMsgTest extends CloseCodeReasonMessageTest { diff --git a/src/test/java/com/ning/http/client/websocket/grizzly/GrizzlyProxyTunnellingTest.java b/src/test/java/com/ning/http/client/ws/grizzly/GrizzlyProxyTunnellingTest.java similarity index 91% rename from src/test/java/com/ning/http/client/websocket/grizzly/GrizzlyProxyTunnellingTest.java rename to src/test/java/com/ning/http/client/ws/grizzly/GrizzlyProxyTunnellingTest.java index d76c131944..626db32600 100644 --- a/src/test/java/com/ning/http/client/websocket/grizzly/GrizzlyProxyTunnellingTest.java +++ b/src/test/java/com/ning/http/client/ws/grizzly/GrizzlyProxyTunnellingTest.java @@ -10,14 +10,14 @@ * "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.grizzly; +package com.ning.http.client.ws.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.websocket.ProxyTunnellingTest; +import com.ning.http.client.ws.ProxyTunnellingTest; @Test public class GrizzlyProxyTunnellingTest extends ProxyTunnellingTest { diff --git a/src/test/java/com/ning/http/client/websocket/grizzly/GrizzlyRedirectTest.java b/src/test/java/com/ning/http/client/ws/grizzly/GrizzlyRedirectTest.java similarity index 91% rename from src/test/java/com/ning/http/client/websocket/grizzly/GrizzlyRedirectTest.java rename to src/test/java/com/ning/http/client/ws/grizzly/GrizzlyRedirectTest.java index 15cd220c8b..d030a71573 100644 --- a/src/test/java/com/ning/http/client/websocket/grizzly/GrizzlyRedirectTest.java +++ b/src/test/java/com/ning/http/client/ws/grizzly/GrizzlyRedirectTest.java @@ -11,12 +11,12 @@ * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under. */ -package com.ning.http.client.websocket.grizzly; +package com.ning.http.client.ws.grizzly; 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.RedirectTest; +import com.ning.http.client.ws.RedirectTest; public class GrizzlyRedirectTest extends RedirectTest { diff --git a/src/test/java/com/ning/http/client/websocket/grizzly/GrizzlyTextMessageTest.java b/src/test/java/com/ning/http/client/ws/grizzly/GrizzlyTextMessageTest.java similarity index 92% rename from src/test/java/com/ning/http/client/websocket/grizzly/GrizzlyTextMessageTest.java rename to src/test/java/com/ning/http/client/ws/grizzly/GrizzlyTextMessageTest.java index 7499f39c31..8970175f7b 100644 --- a/src/test/java/com/ning/http/client/websocket/grizzly/GrizzlyTextMessageTest.java +++ b/src/test/java/com/ning/http/client/ws/grizzly/GrizzlyTextMessageTest.java @@ -10,14 +10,14 @@ * "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.grizzly; +package com.ning.http.client.ws.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.websocket.ByteMessageTest; +import com.ning.http.client.ws.ByteMessageTest; public class GrizzlyTextMessageTest extends ByteMessageTest { @Override diff --git a/src/test/java/com/ning/http/client/websocket/netty/NettyByteMessageTest.java b/src/test/java/com/ning/http/client/ws/netty/NettyByteMessageTest.java similarity index 91% rename from src/test/java/com/ning/http/client/websocket/netty/NettyByteMessageTest.java rename to src/test/java/com/ning/http/client/ws/netty/NettyByteMessageTest.java index 23e01d43c3..f635e213db 100644 --- a/src/test/java/com/ning/http/client/websocket/netty/NettyByteMessageTest.java +++ b/src/test/java/com/ning/http/client/ws/netty/NettyByteMessageTest.java @@ -10,12 +10,12 @@ * "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.netty; +package com.ning.http.client.ws.netty; 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.ByteMessageTest; +import com.ning.http.client.ws.ByteMessageTest; public class NettyByteMessageTest extends ByteMessageTest { @Override diff --git a/src/test/java/com/ning/http/client/websocket/netty/NettyCloseCodeReasonMsgTest.java b/src/test/java/com/ning/http/client/ws/netty/NettyCloseCodeReasonMsgTest.java similarity index 90% rename from src/test/java/com/ning/http/client/websocket/netty/NettyCloseCodeReasonMsgTest.java rename to src/test/java/com/ning/http/client/ws/netty/NettyCloseCodeReasonMsgTest.java index 1f18760722..e6033c2fa2 100644 --- a/src/test/java/com/ning/http/client/websocket/netty/NettyCloseCodeReasonMsgTest.java +++ b/src/test/java/com/ning/http/client/ws/netty/NettyCloseCodeReasonMsgTest.java @@ -11,12 +11,12 @@ * See the Apache License Version 2.0 for the specific language governing permissions and limitations there under. */ -package com.ning.http.client.websocket.netty; +package com.ning.http.client.ws.netty; 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.CloseCodeReasonMessageTest; +import com.ning.http.client.ws.CloseCodeReasonMessageTest; public class NettyCloseCodeReasonMsgTest extends CloseCodeReasonMessageTest { diff --git a/src/test/java/com/ning/http/client/websocket/netty/NettyProxyTunnellingTest.java b/src/test/java/com/ning/http/client/ws/netty/NettyProxyTunnellingTest.java similarity index 91% rename from src/test/java/com/ning/http/client/websocket/netty/NettyProxyTunnellingTest.java rename to src/test/java/com/ning/http/client/ws/netty/NettyProxyTunnellingTest.java index 538a516895..850907e06e 100644 --- a/src/test/java/com/ning/http/client/websocket/netty/NettyProxyTunnellingTest.java +++ b/src/test/java/com/ning/http/client/ws/netty/NettyProxyTunnellingTest.java @@ -10,14 +10,14 @@ * "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.netty; +package com.ning.http.client.ws.netty; 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.websocket.ProxyTunnellingTest; +import com.ning.http.client.ws.ProxyTunnellingTest; @Test public class NettyProxyTunnellingTest extends ProxyTunnellingTest { diff --git a/src/test/java/com/ning/http/client/websocket/netty/NettyRedirectTest.java b/src/test/java/com/ning/http/client/ws/netty/NettyRedirectTest.java similarity index 91% rename from src/test/java/com/ning/http/client/websocket/netty/NettyRedirectTest.java rename to src/test/java/com/ning/http/client/ws/netty/NettyRedirectTest.java index 38963eb20c..69cab6b18c 100644 --- a/src/test/java/com/ning/http/client/websocket/netty/NettyRedirectTest.java +++ b/src/test/java/com/ning/http/client/ws/netty/NettyRedirectTest.java @@ -10,12 +10,12 @@ * "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.netty; +package com.ning.http.client.ws.netty; 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.RedirectTest; +import com.ning.http.client.ws.RedirectTest; public class NettyRedirectTest extends RedirectTest { diff --git a/src/test/java/com/ning/http/client/websocket/netty/NettyTextMessageTest.java b/src/test/java/com/ning/http/client/ws/netty/NettyTextMessageTest.java similarity index 91% rename from src/test/java/com/ning/http/client/websocket/netty/NettyTextMessageTest.java rename to src/test/java/com/ning/http/client/ws/netty/NettyTextMessageTest.java index 2a34358dfb..d3d10fd257 100644 --- a/src/test/java/com/ning/http/client/websocket/netty/NettyTextMessageTest.java +++ b/src/test/java/com/ning/http/client/ws/netty/NettyTextMessageTest.java @@ -10,12 +10,12 @@ * "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.netty; +package com.ning.http.client.ws.netty; 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.ws.TextMessageTest; public class NettyTextMessageTest extends TextMessageTest { @Override From 63a708fa7a2f78c5246685f1071aaf9ef2c35cd0 Mon Sep 17 00:00:00 2001 From: Stephane Landelle Date: Mon, 1 Dec 2014 19:57:43 +0100 Subject: [PATCH 701/701] [maven-release-plugin] prepare release async-http-client-1.9.0 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index f0706098c7..1689df0556 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.ning async-http-client Asynchronous Http Client - 1.9.0-SNAPSHOT + 1.9.0 jar Async Http Client library purpose is to allow Java applications to easily execute HTTP requests and